Skip to content

Transaction

Yong Zhu edited this page May 7, 2020 · 4 revisions

jSqlBox uses the jTransactions module as its transaction tool. jTransactions is an independent transaction tool that has nothing to do with jSqlBox. There is a separate release on Maven. In addition, jSqlBox also comes with a distributed transaction module that supports sub-database and sub-table. For details of distributed transactions, see the "Distributed Transactions" section. In this section, only several conventional transaction management methods are introduced.

First way: Manually control the opening and closing of Connection transactions

Examples are as follows:

 DbContext ctx = new DbContext ();
 Connection conn = null;
 try {
conn = dataSource.getConnection ();
conn.setAutoCommit (false);
ctx.update (conn, 'update users set age =?', 5);
        ...
conn.commit ();
 } catch (SQLException e) {
conn.rollback ();
 } finally {
ctx.close (conn);
 }

The above method is more limited, because a Connection parameter must be passed in the method, and SQLException must be manually caught, which is cumbersome to use and rarely used in actual projects.

The second way: automatic submission mode

This is the default transaction mode of jSqlBox, as long as no transaction-related configuration is performed, all insert, update and other operations are run in automatic commit mode. E.g:

DbContext ctx = new DbContext (someDataSource);
ctx.iUpdate ('update users set age =?', 5);
ctx.iExecute ('delete from users');

The execution of the above two SQLs is independent, not under the same transaction.

The third way: Use the ManualTxConnectionManager module to manually control the opening and closing of transactions for each DbContext instance

 DbContextctx = new DbContext (dataSource);
 ctx.setConnectionManager (new ManualTxConnectionManager ());
 ctx.startTrans ();
 try {
    new User (). putField ("firstName", "Foo"). insert (ctx);
    Assert.assertEquals (101, ctx.eCountAll (Tail.class, tail ("users"))));
    ctx.commitTrans ();
 } catch (Exception e) {
    ctx.rollbackTrans ();
 }

Note that ManualTx is not thread safe and can only be used in one thread, so you must create a new DbContext instance in each thread and create a new ManualTxConnectionManager instance. The advantage of this transaction management method is that you can independently control the transaction of each DbContext, but the disadvantage is that you must create multiple DbContext instances. The complete source code for the above example can be found in ManualTxTest.java under Unit Testing.

The fourth way: TinyTxConnectionManager module

 DbContextctx = new DbContext (dataSource);
 ctx.setConnectionManager (TinyTxConnectionManager.instance ());
 ctx.startTrans ();
 try {
    new User (). putField ("firstName", "Foo"). insert (ctx);
    Assert.assertEquals (101, ctx.eCountAll (Tail.class, tail ("users"))));
    ctx.commitTrans ();
 } catch (Exception e) {
    ctx.rollbackTrans ();
 }

After using the TinyTxConnectionManager transaction connection management class, all DbContexts can share the same TinyTxConnectionManager singleton, and there is no longer a need to create a transaction management class for each DbContext instance. Its limitation is that in the same thread, a transaction allows only one DbContext to obtain a Connection connection and perform database operations. It uses the ThreadLocal class to implement this function at the bottom. The complete source code of the above example can be found in TinyTxTest.java under Unit Testing and TinyTxTester.java, which is a demonstration of declarative transactions.

The fifth way: GroupTxConnectionManager module

 DbContextctx1 = new DbContext (dataSource1);
 DbContextctx2 = new DbContext (dataSource2);
 ctx1.setConnectionManager (GroupTxConnectionManager.instance ());
 ctx2.setConnectionManager (GroupTxConnectionManager.instance ());
 ctx1.startTrans ();
 try {
    new User (). putField ("firstName", "Foo"). insert (ctx1);
    new User (). putField ("firstName", "Foo"). insert (ctx2);
    Assert.assertEquals (101, ctx1.eCountAll (Tail.class, tail ("users"))));
    ctx1.commitTrans ();
 } catch (Exception e) {
    ctx1.rollbackTrans ();
 }

After using the GroupTxConnectionManager transaction connection management class, all DbContexts can share the same GroupTxConnectionManager singleton, and there is no need to create a transaction management class for each DbContext instance. It allows multiple DbContexts in a thread to obtain Connection connections and perform database operations at the same time, but please note that it cannot guarantee the consistency of each Connection submission, that is, it is not a distributed transaction. This transaction module can only be used in some unimportant occasions. If strict distributed transactions are required, please refer to the next section "Distributed Transactions". The complete source code of the above example can be found in GroupTxTest.java under Unit Testing and AnnotationGroupTxTest.java, which is a demonstration of declarative transactions.

Declarative transactions

jTransactions also includes two modules, SpringConnectionManager and JFinalConnectionManager, which are used in Spring and JFinal occasions respectively. They call Spring or JFinal transaction functions at the bottom.

The above is the introduction of basic manual opening and submitting transactions. In actual projects, TinyTxAOP, GroupTxAOP, GtxAOP, etc. can also be used to configure event-type transactions.

public class AnnotationTxDemoTest {
    public static class DataSourceCfg extends BeanBox {
        {
            setProperty ("jdbcUrl", "jdbc: h2: mem: DBName; MODE = MYSQL; DB_CLOSE_DELAY = -1; TRACE_LEVEL_SYSTEM_OUT = 0");
            setProperty ("driverClassName", "org.h2.Driver");
            setProperty ("username", "sa");
            setProperty ("password", "");
        }

        public HikariDataSource create () {
            HikariDataSource ds = new HikariDataSource ();
            this.setPreDestroy ("close"); // jBeanBox will close pool
            return ds;
        }
    }

    @Retention (RetentionPolicy.RUNTIME)
    @Target ({ElementType.METHOD})
    @AOP
    public static @interface TX {// This is a customized AOP annotation
        public Class <?> value () default TinyTxAOP.class;
    }

    DbContext ctx;
    {
        ctx = new DbContext ((DataSource) BeanBox.getBean (DataSourceBox.class));
        ctx.setConnectionManager (TinyTxConnectionManager.instance ());
    }

    @TX
    public void txInsert () {
        ctx.nExecute ("insert into user_tb (id) values ​​('123')");
        System.out.println (1/0); // DIV 0!
    }

    @Test
    public void doTest () {
       AnnotationTxDemoTest tester = JBEANBOX.getBean (AnnotationTxDemoTest.class);
       tester.txInsert (); // Transaction error, automatic rollback
       ...
    }

}

Declarative transactions in Spring

In the above example, the IOC / AOP tool jBeanBox was used, which has been included since jSqlBox version 4.0.0. jBeanBox uses the Aop alliance standard interface, so the above example can also be easily switched to use Spring as an IOC / AOP tool. If you use the integrated Spring-boot environment, the configuration can be simplified as follows:

@SpringBootApplication
public class JsqlboxInSpringbootApplication {
     @Autowired
     DataSource ds;

     public static void main (String [] args) {
         SpringApplication.run (JsqlboxInSpringbootApplication.class, args);
     }
 
     @Bean
     public DbContext createDefaultDbContext () {
         DbContext ctx = new DbContext (ds);
         ctx.setConnectionManager (SpringTxConnectionManager.instance ());
         DbContext.setGlobalDbBoxContext (ctx); // Set static global context
         return ctx;
     }
}

For details, please see the jsqlbox-springboot demo project in the demo directory.

Clone this wiki locally