diff --git a/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc b/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc index 20479501d3..c046ffcbd5 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc @@ -1,6 +1,6 @@ [[transactions]] == Transactions and concurrency control -:sourcedir: extras +:sourcedir: ../../../../../test/java/org/hibernate/userguide/transactions It is important to understand that the term transaction has many different yet related meanings in regards to persistence and Object/Relational Mapping. In most use-cases these definitions align, but that is not always the case. @@ -96,27 +96,30 @@ This method checks with the underling transaction system if needed, so care shou Let's take a look at using the Transaction API in the various environments. +[[transactions-api-jdbc-example]] .Using Transaction API in JDBC ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/jdbc.java[] +include::{sourcedir}/TransactionsTest.java[tags=transactions-api-jdbc-example] ---- ==== +[[transactions-api-cmt-example]] .Using Transaction API in JTA (CMT) ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/cmt.java[] +include::{sourcedir}/TransactionsTest.java[tags=transactions-api-cmt-example] ---- ==== +[[transactions-api-bmt-example]] .Using Transaction API in JTA (BMT) ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/bmt.java[] +include::{sourcedir}/TransactionsTest.java[tags=transactions-api-bmt-example] ---- ==== diff --git a/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/bmt.java b/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/bmt.java deleted file mode 100644 index bf76d7df07..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/bmt.java +++ /dev/null @@ -1,42 +0,0 @@ -public void doSomeWork() { - - StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() - .applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ) - ...; - - // Note: depending on the JtaPlatform used and some optional settings, - // the underlying transactions here will be controlled through either - // the JTA TransactionManager or UserTransaction - - SessionFactory = ...; - - Session session = sessionFactory.openSession(); - try { - // Assuming a JTA transaction is not already active, - // this call the TM/UT begin method. If a JTA - // transaction is already active, we remember that - // the Transaction associated with the Session did - // not "initiate" the JTA transaction and will later - // nop-op the commit and rollback calls... - session.getTransaction().begin(); - - doTheWork(); - - // calls TM/UT commit method, assuming we are initiator. - session.getTransaction().commit(); - } - catch ( Exception e ) { - // we may need to rollback depending on - // where the exception happened - if ( session.getTransaction().getStatus() == ACTIVE - || session.getTransaction().getStatus() == MARKED_ROLLBACK ) { - // calls TM/UT commit method, assuming we are initiator; - // otherwise marks the JTA transaction for rollback only - session.getTransaction().rollback(); - } - // handle the underlying error - } - finally { - session.close(); - } -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/cmt.java b/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/cmt.java deleted file mode 100644 index 940003b71d..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/cmt.java +++ /dev/null @@ -1,38 +0,0 @@ -public void doSomeWork() { - StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() - .applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ) - ...; - - // Note: depending on the JtaPlatform used and some optional settings, - // the underlying transactions here will be controlled through either - // the JTA TransactionManager or UserTransaction - - SessionFactory = ...; - - Session session = sessionFactory.openSession(); - try { - // Since we are in CMT, a JTA transaction would - // already have been started. This call essentially - // no-ops - session.getTransaction().begin(); - - doTheWork(); - - // Since we did not start the transaction ( CMT ), - // we also will not end it. This call essentially - // no-ops in terms of transaction handling. - session.getTransaction().commit(); - } - catch ( Exception e ) { - // again, the rollback call here would no-op (aside from - // marking the underlying CMT transaction for rollback only). - if ( session.getTransaction().getStatus() == ACTIVE - || session.getTransaction().getStatus() == MARKED_ROLLBACK ) { - session.getTransaction().rollback(); - } - // handle the underlying error - } - finally { - session.close(); - } -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/jdbc.java b/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/jdbc.java deleted file mode 100644 index a1fd540927..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/transactions/extras/jdbc.java +++ /dev/null @@ -1,33 +0,0 @@ -public void doSomeWork() { - StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() - // "jdbc" is the default, but for explicitness - .applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jdbc" ) - ...; - - SessionFactory = ...; - - Session session = sessionFactory.openSession(); - try { - // calls Connection#setAutoCommit( false ) to - // signal start of transaction - session.getTransaction().begin(); - - doTheWork(); - - // calls Connection#commit(), if an error - // happens we attempt a rollback - session.getTransaction().commit(); - } - catch ( Exception e ) { - // we may need to rollback depending on - // where the exception happened - if ( session.getTransaction().getStatus() == ACTIVE - || session.getTransaction().getStatus() == MARKED_ROLLBACK ) { - session.getTransaction().rollback(); - } - // handle the underlying error - } - finally { - session.close(); - } -} \ No newline at end of file diff --git a/documentation/src/test/java/org/hibernate/userguide/transactions/TransactionsTest.java b/documentation/src/test/java/org/hibernate/userguide/transactions/TransactionsTest.java new file mode 100644 index 0000000000..8b749527c5 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/transactions/TransactionsTest.java @@ -0,0 +1,201 @@ +package org.hibernate.userguide.transactions; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.resource.transaction.spi.TransactionStatus; + +import org.junit.Test; + +/** + * @author Vlad Mihalcea + */ +public class TransactionsTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Customer.class + }; + } + + @Test + public void jdbc() { + //tag::transactions-api-jdbc-example[] + StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + // "jdbc" is the default, but for explicitness + .applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jdbc" ) + .build(); + + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( Customer.class ) + .getMetadataBuilder() + .build(); + + SessionFactory sessionFactory = metadata.getSessionFactoryBuilder() + .build(); + + Session session = sessionFactory.openSession(); + try { + // calls Connection#setAutoCommit( false ) to + // signal start of transaction + session.getTransaction().begin(); + + session.createQuery( "UPDATE customer set NAME = 'Sir. '||NAME" ) + .executeUpdate(); + + // calls Connection#commit(), if an error + // happens we attempt a rollback + session.getTransaction().commit(); + } + catch ( Exception e ) { + // we may need to rollback depending on + // where the exception happened + if ( session.getTransaction().getStatus() == TransactionStatus.ACTIVE + || session.getTransaction().getStatus() == TransactionStatus.MARKED_ROLLBACK ) { + session.getTransaction().rollback(); + } + // handle the underlying error + } + finally { + session.close(); + } + //end::transactions-api-jdbc-example[] + } + + @Test + public void cmt() { + //tag::transactions-api-cmt-example[] + StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + // "jdbc" is the default, but for explicitness + .applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ) + .build(); + + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( Customer.class ) + .getMetadataBuilder() + .build(); + + SessionFactory sessionFactory = metadata.getSessionFactoryBuilder() + .build(); + + // Note: depending on the JtaPlatform used and some optional settings, + // the underlying transactions here will be controlled through either + // the JTA TransactionManager or UserTransaction + + Session session = sessionFactory.openSession(); + try { + // Since we are in CMT, a JTA transaction would + // already have been started. This call essentially + // no-ops + session.getTransaction().begin(); + + Number customerCount = (Number) session.createQuery( "select count(c) from Customer c" ).uniqueResult(); + + // Since we did not start the transaction ( CMT ), + // we also will not end it. This call essentially + // no-ops in terms of transaction handling. + session.getTransaction().commit(); + } + catch ( Exception e ) { + // again, the rollback call here would no-op (aside from + // marking the underlying CMT transaction for rollback only). + if ( session.getTransaction().getStatus() == TransactionStatus.ACTIVE + || session.getTransaction().getStatus() == TransactionStatus.MARKED_ROLLBACK ) { + session.getTransaction().rollback(); + } + // handle the underlying error + } + finally { + session.close(); + } + //end::transactions-api-cmt-example[] + } + + @Test + public void bmt() { + //tag::transactions-api-bmt-example[] + StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + // "jdbc" is the default, but for explicitness + .applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ) + .build(); + + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( Customer.class ) + .getMetadataBuilder() + .build(); + + SessionFactory sessionFactory = metadata.getSessionFactoryBuilder() + .build(); + + // Note: depending on the JtaPlatform used and some optional settings, + // the underlying transactions here will be controlled through either + // the JTA TransactionManager or UserTransaction + + Session session = sessionFactory.openSession(); + try { + // Assuming a JTA transaction is not already active, + // this call the TM/UT begin method. If a JTA + // transaction is already active, we remember that + // the Transaction associated with the Session did + // not "initiate" the JTA transaction and will later + // nop-op the commit and rollback calls... + session.getTransaction().begin(); + + session.persist( new Customer( ) ); + Customer customer = (Customer) session.createQuery( "select c from Customer c" ).uniqueResult(); + + // calls TM/UT commit method, assuming we are initiator. + session.getTransaction().commit(); + } + catch ( Exception e ) { + // we may need to rollback depending on + // where the exception happened + if ( session.getTransaction().getStatus() == TransactionStatus.ACTIVE + || session.getTransaction().getStatus() == TransactionStatus.MARKED_ROLLBACK ) { + // calls TM/UT commit method, assuming we are initiator; + // otherwise marks the JTA transaction for rollback only + session.getTransaction().rollback(); + } + // handle the underlying error + } + finally { + session.close(); + } + //end::transactions-api-bmt-example[] + } + + @Entity(name = "Customer") + public static class Customer { + + @Id + @GeneratedValue + private Long id; + + private String name; + + public Customer() { + } + + public Customer(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + } +}