fix tests which were asserting stuff about JPA compliance for a non-JPA method

The JPA spec does not have anything to say about our beginTransaction() method
This commit is contained in:
Gavin King 2024-11-20 23:26:00 +01:00
parent 945ec124fc
commit 597f74f23e
5 changed files with 45 additions and 12 deletions

View File

@ -68,17 +68,29 @@ public interface SharedSessionContract extends QueryProducer, AutoCloseable, Ser
* Begin a unit of work and return the associated {@link Transaction} object. * Begin a unit of work and return the associated {@link Transaction} object.
* If a new underlying transaction is required, begin the transaction. Otherwise, * If a new underlying transaction is required, begin the transaction. Otherwise,
* continue the new work in the context of the existing underlying transaction. * continue the new work in the context of the existing underlying transaction.
* <p> *
* The JPA-standard way to begin a new transaction is by calling * @apiNote
* {@link #getTransaction getTransaction().begin()}. When * The JPA-standard way to begin a new resource-local transaction is by calling
* {@link #getTransaction getTransaction().begin()}. But it's not always safe to
* execute this idiom.
* <ul>
* <li>JPA doesn't allow an {@link jakarta.persistence.EntityTransaction
* EntityTransaction} to represent a JTA transaction context. Therefore, when
* {@linkplain org.hibernate.jpa.spi.JpaCompliance#isJpaTransactionComplianceEnabled * {@linkplain org.hibernate.jpa.spi.JpaCompliance#isJpaTransactionComplianceEnabled
* strict JPA transaction compliance} is enabled via, for example, setting * strict JPA transaction compliance} is enabled via, for example, setting
* {@value org.hibernate.cfg.JpaComplianceSettings#JPA_TRANSACTION_COMPLIANCE}, * {@value org.hibernate.cfg.JpaComplianceSettings#JPA_TRANSACTION_COMPLIANCE},
* or when resource-local transactions are used, the call to {@code begin()} * the call to {@code getTransaction()} fails if transactions are managed by JTA.
* fails if the transaction is already {@linkplain Transaction#isActive active}. * <p>
* On the other hand, this method does not fail when a transaction is already * On the other hand, this method does not fail when JTA transaction management
* active, and simply returns the {@link Transaction} object representing the * is used, not even if strict JPA transaction compliance is enabled.
* active transaction. * <li>Even when resource-local transactions are in use, and even when strict JPA
* transaction compliance is <em>disabled</em>, the call to {@code begin()}
* fails if a transaction is already {@linkplain Transaction#isActive active}.
* <p>
* This method never fails when a transaction is already active. Instead,
* {@code beginTransaction()} simply returns the {@link Transaction} object
* representing the active transaction.
* </ul>
* *
* @return an instance of {@link Transaction} representing the new transaction * @return an instance of {@link Transaction} representing the new transaction
* *
@ -90,6 +102,20 @@ public interface SharedSessionContract extends QueryProducer, AutoCloseable, Ser
/** /**
* Get the {@link Transaction} instance associated with this session. * Get the {@link Transaction} instance associated with this session.
* *
* @apiNote
* This method is the JPA-standard way to obtain an instance of
* {@link jakarta.persistence.EntityTransaction EntityTransaction}
* representing a resource-local transaction. But JPA doesn't allow an
* {@code EntityTransaction} to represent a JTA transaction. Therefore, when
* {@linkplain org.hibernate.jpa.spi.JpaCompliance#isJpaTransactionComplianceEnabled
* strict JPA transaction compliance} is enabled via, for example, setting
* {@value org.hibernate.cfg.JpaComplianceSettings#JPA_TRANSACTION_COMPLIANCE},
* this method fails if transactions are managed by JTA.
* <p>
* On the other hand, when JTA transaction management is used, and when
* strict JPA transaction compliance is <em>disabled</em>, this method happily
* returns a {@link Transaction} representing the current JTA transaction context.
*
* @return an instance of {@link Transaction} representing the transaction * @return an instance of {@link Transaction} representing the transaction
* associated with this session * associated with this session
* *

View File

@ -17,7 +17,7 @@ import org.hibernate.resource.transaction.spi.TransactionStatus;
* depending on how Hibernate is configured. * depending on how Hibernate is configured.
* <p> * <p>
* Every resource-local transaction is associated with a {@link Session} and begins with * Every resource-local transaction is associated with a {@link Session} and begins with
* an explicit call to {@link Session#beginTransaction()}, or, equivalently, with * an explicit call to {@link Session#beginTransaction()}, or, almost equivalently, with
* {@code session.getTransaction().begin()}, and ends with a call to {@link #commit()} * {@code session.getTransaction().begin()}, and ends with a call to {@link #commit()}
* or {@link #rollback()}. * or {@link #rollback()}.
* <p> * <p>
@ -31,6 +31,11 @@ import org.hibernate.resource.transaction.spi.TransactionStatus;
* <p> * <p>
* A {@code Transaction} object is not threadsafe. * A {@code Transaction} object is not threadsafe.
* *
* @apiNote JPA doesn't allow an {@link EntityTransaction} to represent a JTA transaction.
* But when {@linkplain org.hibernate.jpa.spi.JpaCompliance#isJpaTransactionComplianceEnabled
* strict JPA transaction compliance} is disabled, as it is by default, Hibernate allows an
* instance of this interface to represent the current JTA transaction context.
*
* @author Anton van Straaten * @author Anton van Straaten
* @author Steve Ebersole * @author Steve Ebersole
* *

View File

@ -610,7 +610,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override @Override
public Transaction beginTransaction() { public Transaction beginTransaction() {
checkOpen(); checkOpen();
final Transaction transaction = getTransaction(); final Transaction transaction = accessTransaction();
// only need to begin a transaction if it was not // only need to begin a transaction if it was not
// already active (this is the documented semantics) // already active (this is the documented semantics)
if ( !transaction.isActive() ) { if ( !transaction.isActive() ) {

View File

@ -45,7 +45,8 @@ public class JpaComplianceAlreadyStartedTransactionTest extends BaseNonConfigCor
Transaction tx = null; Transaction tx = null;
try { try {
// A call to begin() with an active Tx should cause an IllegalStateException // A call to begin() with an active Tx should cause an IllegalStateException
tx = s.beginTransaction(); tx = s.getTransaction();
tx.begin();
} }
catch (Exception e) { catch (Exception e) {
if ( tx != null && tx.isActive() ) { if ( tx != null && tx.isActive() ) {

View File

@ -50,7 +50,8 @@ public class NonJpaComplianceAlreadyStartedTransactionTest extends BaseNonConfig
public void noIllegalStateExceptionShouldBeThrownWhenBeginTxIsCalledWithAnAlreadyActiveTx() throws Exception { public void noIllegalStateExceptionShouldBeThrownWhenBeginTxIsCalledWithAnAlreadyActiveTx() throws Exception {
tm.begin(); tm.begin();
try (Session s = openSession()) { try (Session s = openSession()) {
Transaction tx = s.beginTransaction(); Transaction tx = s.getTransaction();
tx.begin();
try { try {
s.persist( new TestEntity( "ABC" ) ); s.persist( new TestEntity( "ABC" ) );
tx.commit(); tx.commit();