Spring basic course 11: Spring transaction management

Keywords: Database Session JDBC Spring

Database transactions

  1. A series of database operations with ACID characteristics realized by database, a refers to atomicity, C refers to consistency, I refers to isolation, and D refers to persistence;

  2. Atomicity refers to that the operation within a transaction is a whole and cannot be subdivided; consistency refers to that the consistency of the data before and after the transaction is running has not been broken; isolation refers to the visibility and mutual influence between transactions; persistence refers to that once a transaction is committed, it must be persisted;

  3. There are different levels of isolation: read uncommitted, read committed, repeatable read and serialization, which respectively represent: you can read uncommitted operations of other transactions; you can only read submitted operations of other transactions, but it may be inconsistent to read a content repeatedly; you can read a content repeatedly and it is consistent, but there will be inconsistent statistical information; all operations are serialized;

  4. The persistent operation depends on the database log;

  5. The default level in Oracle is read submitted, and the default level in Mysql is repeatable read;

  6. The operation of database transaction by Jdbc relies on setAutoCommit(boolean), commit(), rollback() of Connection. The commonly used parameters for creating transaction are auto commit and transaction isolation level;

Mybatis transaction

  1. Mybatis provides the org.apache.ibatis.transaction interface to encapsulate transaction operations, and provides the implementation of JdbcTransaction, ManagedTransaction and SpringManagedTransaction;

  2. JdbcTransaction is to obtain Connection from DataSource, control transaction through commit and rollback of Connection, while ManagedTransaction is to control transaction by external container, its commit and rollback operation are empty methods, SpringManagedTransaction is to obtain and release Connection through DataSourceUtils of Spring, and its commit and rollback are also realized through Connection of Jdbc .

  3. Transaction is created through its factory class. In the application, you don't need to care about its creation process. You only need to configure transactionManager type = "JDBC" / in the configuration file, and then use SqlSession's commit and rollback in the code to operate the transaction. Transaction creation is created in the process of openSession. The source code is as follows. openSession method can be passed Enter the isolation level, auto submit and other attributes. The default is not auto submit;

	private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean 		autoCommit) {   
	   Environment environment = this.configuration.getEnvironment();
	   TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
	   Transaction tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
	   ...
   }
  1. Note that by default, the mybatis transaction is not automatically submitted, that is, sqlSession.commit is not called, and the operation is not updated to the database. However, if no commit or rollback is performed, the database will deadlock;

  2. For more information: https://blog.csdn.net/qq924862077/article/details/52599785

Hibernate transaction

  1. Similar to mybatis, Transaction interface is defined and inherited from EntityTransaction interface. There are begin, commit, rollback and other methods. Similarly, the underlying layer relies on Connection to operate database transactions;

  2. Usage: first, define the isolation level in the property name = "hibernate.connection.isolation" 4 / property in the session factory property of the configuration file, and then define the session management mode in the property name = "hibernate. Current" session "context" class / property property property property, including thread, jta, managed. Finally, you can use the session in the application Conduct transaction operations

	Session session = sf.openSession();
    Student stu = new Student("Zhang three 5");
	session.getTransaction().begin();
	session.save(stu);
	session.getTransaction().commit();
  1. For more information: https://www.cnblogs.com/eaglesour/p/9484845.html

JPA transaction

  1. Jpa is a standard specification based on ORM. It only defines standard rules and does not provide implementation, but its main implementation is Hibernate;

  2. Therefore, setting Jpa transaction is similar to setting Hibernate transaction. First, in the configuration file, bean id = "entityManagerFactory" Under property name = "jpaProperties", set hibernate.connection.isolation, Hibernate.current'session'context'class, and then conduct transaction operations through EntityManager in the code:

 	EntityTransaction t = entityManager.getTransaction();
    t.begin();
    StudentOrm s = new StudentOrm("liud",25);
    entityManager.persist(s);
    t.commit();

Spring transaction

  1. The underlying layer of spring transaction still uses Connection, which also extends the transaction propagation mode. The default is "promotion" required, that is, create a transaction if there is no transaction at present, join the transaction if there is one, and "promotion" supports, that is, add the transaction if there is one, and do not use the transaction if there is no transaction at present If there is a transaction, join the transaction. If there is no transaction at present, throw an exception. Promotion ﹣ requests ﹣ new. If there is a transaction at present, suspend the current transaction and create a new one. If there is no transaction, create a new one directly. Promotion ﹣ not ﹣ supported. That is to say, suspend the current transaction if there is a transaction. If there is no transaction, run it in a non transactional way Action ﹣ never, run in non transactional mode. If there is a transaction, throw an exception, promotion ﹣ nested. If there is currently a transaction, execute it in nested transaction mode (equivalent to savePoint). If there is no transaction, create a transaction;

  2. Spring provides transaction definition, PlatformTransactionManager and TransactionStatus API s for transaction support, in which definition is the declaration of transaction rules, status is the description of transaction status, and manager is the specific transaction operation interface;

  3. TransactionDefinition encapsulates database transaction rules such as isolation level and timeout, and extends transaction propagation mode, timeout setting, read-only transaction and other rules. The commonly used implementation class is DefaultTransactionDefinition;

  4. TransactionStatus encapsulates the interface to access the current transaction information, including isNewTransaction(), flush(), isCompleted(), etc;

  5. PlatformTransactionManager encapsulates the specific operations of a transaction, and internally declares a member variable of ThreadLocal < transaction). Therefore, each thread is a transaction object unique to the operation. The implementation classes include: DataSourceTransactionManager (JDBC), HibernateTransactionManager, jpartransactionmanager, JtaTransactionManager (multi database transaction manager, also known as sub Layout transaction manager, XA two-phase commit), API as follows:

   public interface PlatformTransactionManager {
        TransactionStatus getTransaction(TransactionDefinition definition);
        void commit(TransactionStatus status) throws TransactionException;
        void rollback(TransactionStatus status) throws TransactionException;
    }
  1. Use, declare a TransactionManager bean in the application context, pass the construction parameter to the database to connect to DataSource, and the program uses
	@Autowired
    private TransactionManager txManager;
    public boolean update(String sql) {
	    TransactionDefinition txDefinition = new TransactionDefinition();
	    //Create a transaction and bind to the current thread
        TransactionStatus txStatus = txManager.getTransaction(txDefinition);
        boolean result = false;
        try {
            result = jdbcTemplate.update(sql);
            txManager.commit(txStatus);
        } catch (Exception e) {
            result = false;
            txManager.rollback(txStatus);
        }
        return result;
    }

The more elegant way is to use TransactionTemplate, which internally encapsulates the code process of opening transaction, submitting transaction and rolling back transaction. In the application context, the bean s of TransactionManager and TransactionTemplate are declared respectively. manager is the construction parameter of template, and the usage of template:

 	@Autowired
    private TransactionTemplate transactionTemplate;
    public boolean update(String sql) {
       return transactionTemplate.execute(new TransactionCallback<T>() {
           @Override
           public T doInTransaction(TransactionStatus status) {
               return jdbcTemplate.update(sql);
           }
       });
   }
  1. Another way is to weave transaction facets through spring AOP, which can be used only by declaring transaction manager in reference context and turning on transaction annotation scanning, that is, adding annotation @ Transactional to business code;
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<tx:annotation-driven transaction-manager="transactionManager"/>
	@Transactional(propagation = Propagation.REQUIRED)
  1. Note how to open a transaction. Note that only public decorated methods can open a new transaction independently. private decorated methods can only add a transaction. public static decorated methods do not run in a transaction if the caller is not in the transaction;

  2. For the source code analysis of DataSourceTransactionManager, note that the Connection in DataSourceTransactionManager.DataSourceTransactionObject is obtained from the data source for the first time, but is bound to the threadLocal member variable resource of TransactionSynchronizationManager, and then obtained from the member variable resource of TransactionSynchronizationManager;

	// Open a transaction
	-->TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
		Object transaction = doGetTransaction();
		if (definition == null) {
			definition = new DefaultTransactionDefinition();
		}
		if (isExistingTransaction(transaction)) {
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}
		// Construct a transactionStatus
		DefaultTransactionStatus status = newTransactionStatus(
			definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		doBegin(transaction, definition);
		prepareSynchronization(status, definition);
		return status;
	-->doGetTransaction()
		DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
		// Set whether nesting is allowed
        txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
        // Get the ConHolder from the threadLocal member variable of the TransactionSynchronizationManager. The first get should be null
        ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
 	-->isExistingTransaction(transaction)
 		// Determine whether the connHolder in the transaction exists. The first time it does not exist. If it does, add a transaction or throw an exception according to the propagation method
        return txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive();
   -->doBegin(transaction, definition)
   		// Get a connection from the data source
 		Connection newCon = this.obtainDataSource().getConnection();
 		// Set the connection to transaction, and set some flag bits, isolation level
        txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
		txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        con = txObject.getConnectionHolder().getConnection();
       	Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);
		con.setAutoCommit(false);
		// If the connection is obtained for the first time, set the key value pairs of datasource and connection to the threadLocal member variable of TransactionSynchronizationManager
		// This ensures that the resource s obtained by the same thread from transaction synchronization manager are the same, and different threads do not interfere with each other
        if (txObject.isNewConnectionHolder()) {
        	TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
         }
-->prepareSynchronization(status, definition);
	// If it is a new transaction, set some flag bits for the transaction synchronization manager, which are also decorated by threadLocal
-->handleExistingTransaction(definition, transaction, debugEnabled)
	// Currently, there are transactions, which are processed according to the configured transaction propagation mode

// Submission of affairs
-->commit(TransactionStatus status)
	prepareForCommit(status);
	triggerBeforeCommit(status);
	doCommit(status);
	triggerAfterCommit(status);
-->doCommit(status)
	// Get the Connection encapsulated in DataSourceTransactionManager.DataSourceTransactionObject and call its commit to commit the transaction
	Connection con = txObject.getConnectionHolder().getConnection();
	con.commit();
-->rollback and commit Logical analogous	

Comparison of various transaction modes

  1. Basically, the underlying layer uses jdbc to control transactions. spring transactions are recommended, which is more convenient and general;

  2. Try to avoid the mixed operation of jdbc and orm framework;

  3. It is recommended to use spring to provide TransactionTemplate template class and annotation to use transactions. If you need to obtain database connection, you need to use DataSourceUtils tool class;

Tips:

  1. Transaction failure: when the annotation method uses transactions, the internal method calls, and the transaction annotation of the called method does not take effect, because the generated dynamic proxy class does not follow the method of the proxy class when the internal method calls, but simply copies the code into the calling method, and only the direct use of the proxy class will take effect. One solution is the internal method call pass It is replaced by AopContext.currentProxy(). The better is to change the internal method call to the upper level and directly use the proxy class to call;

  2. Nested transaction: a new transaction created in the inner layer is actually a new savePoint created in the outer layer and submitted in the inner layer, which is equivalent to releasing the savePoint. An exception in the inner layer triggers a rollback and rolls back to the savePoint.
    The outer exception, in fact, triggers conn.rollback. At this time, there is no savePoint, and the entire rollback.

Published 24 original articles, won praise 2, visited 846
Private letter follow

Posted by Procode on Mon, 03 Feb 2020 23:27:31 -0800