Spring transaction isolation level and propagation mechanism, spring+mybatis+atomikos for distributed transaction management

This article is reproduced in [ http://blog.csdn.net/liaohaojian/article/details/68488150]

1. The definition of a transaction: A transaction is a collection of multiple units of operation that are either not successful or successful.It must follow four principles (ACID).

  1. Atomicity: A transaction is the smallest unit of work that cannot be separated. Operations within a transaction are either done entirely or not done at all.
  2. Consistency: Before a transaction is executed, the data of the database is in the correct state, but after the transaction is executed, the data of the database should still be in the correct state, that is, the data integrity constraints are not violated; for example, bank transfers, A transfers to B, A must be guaranteed that A's money must be transferred to B and A will not appear.Money was transferred but B was not received, otherwise the data in the database would be in an inconsistent (incorrect) state.
  3. Isolation: Concurrent transaction executions do not affect each other, and operations within one transaction do not affect other transactions, which requires a transaction isolation level to specify isolation;
  4. Durability: Once a transaction is successfully executed, changes to the data in the database must be permanent and will not cause inconsistencies or loss of data due to system failures or power outages, for example.

2. Type of transaction

  1. Database is divided into local and global transactions
    • Local transaction: A common transaction, a separate database, that guarantees the ACID of operations on that database.
    • Distributed transactions: Transactions involving two or more database sources, that is, transactions spanning multiple homogeneous or heterogeneous databases (consisting of local transactions for each database). Distributed transactions are designed to guarantee the ACID of all operations of these local transactions so that transactions can span multiple databases.
  2. Java transaction types are divided into JDBC and JTA transactions
    • JDBC transaction: The local transaction in the database transaction mentioned above, which is controlled by the connection object.
    • JTA Transaction: JTA refers to the Java Transaction API, which is the Java EE database transaction specification. JTA only provides transaction management interfaces and is implemented by application server vendors such as WebSphere Application Server. JTA transactions are more powerful than JDBC and support distributed transactions.
  3. Declarative and programmatic transactions by whether or not they are programmed, reference http://blog.csdn.net/liaohaojian/article/details/70139151
    • Declarative transactions: Implemented through XML configuration or annotations.
    • Programmatic Transactions: Programmed code is implemented by itself when needed in business logic, with a smaller granularity.

3.Spring Transaction Isolation Level: spring has five isolation levels defined in the TransactionDefinition interface.Looking at the source code, its silent isolation_default (the default level for the underlying database) and the other four isolation levels correspond to the database isolation level.

  1. ISOLATION_DEFAULT: With the default isolation level of the underlying database, what the database administrator sets is what
  2. ISOLATION_READ_UNCOMMITTED (Uncommitted Read): At the lowest isolation level, transactions can be read by other transactions before they are committed (magic, dirty, non-repeatable reads can occur)
  3. ISOLATION_READ_COMMITTED (Commit Read): The default sql server level, which prevents other transactions from reading data from uncommitted transactions after a transaction has been committed
  4. ISOLATION_REPEATABLE_READ (Repeatable Read): Repeatable read, guarantees consistency of multiple reads, and prohibits reading uncommitted data from other transactions (this isolation basically prevents dirty reads, non-repeatable reads (mainly modifications), but magic reads (mainly additions and deletions) (MySql default level, changes can be made)Through set transaction isolation level)
  5. ISOLATION_SERIALIZABLE: The most expensive and reliable isolation level (which prevents dirty, non-repeatable, magic reads)
    1. Lost updates: Two transactions update one row of data at the same time, and the last transaction overwrites the first transaction's updates, resulting in the loss of data for the first transaction's updates due to the absence of locks;
    2. Magic Read: In the same transaction, when read more than once, another uncommitted transaction commits something that is inconsistent with the first read (typically more or less rows).
    3. Dirty reading: A transaction reads something that is not mentioned in another transaction, which is dirty reading.
    4. Non-repeatable reading: In the same transaction, the contents of multiple reads are inconsistent (the general number of rows does not change, but the contents change).

The difference between magic reading and non-repeatable reading: Magic reading focuses on insertion and deletion, that is, the second query will find less or more data than the first query, so as to give a kind of illusion, while non-repeatable reading focuses on modification, that is, the second query will find that the query results are inconsistent with the first query resultsThat is, the first result can no longer be reproduced.

The higher the isolation level of the database, the higher the cost of execution, and the poorer the concurrent execution capability. Therefore, in order to consider concurrency performance, the commit-read isolation level is generally used, which can avoid losing updates and dirty reads, although non-repeatable and hallucinatory reads cannot be avoided, it can occur at any timeUse pessimistic or optimistic locks to solve these problems on occasions.

The pessimistic lock and the optimistic lock can be consulted: http://blog.csdn.net/liaohaojian/article/details/62416972

4. Propagation Behavior: There are seven major propagation behaviors that are also defined in the TransactionDefinition interface.

  1. PROPAGATION_REQUIRED: Supports the current transaction, or creates a new one if there is no current transaction.
  2. PROPAGATION_SUPPORTS: Supports the current transaction, if there is no transaction at present, then it is no longer transactional (there is a note in the source code that you can't understand clearly and leave it to be studied later).
  3. PROPAGATION_MANDATORY: Supports the current transaction and throws an exception if there is no transaction at present (enforcing must be executed in an existing transaction, business methods cannot initiate their own transaction on their own).
  4. PROPAGATION_REQUIRES_NEW: Always create a new transaction and suspend it if it already exists.
  5. PROPAGATION_NOT_SUPPORTED: Current transaction is not supported and is always executed non-transactionally, suspending if the current transaction exists.
  6. PROPAGATION_NEVER: Current transaction is not supported; if the current transaction exists, an exception is thrown.
  7. PROPAGATION_NESTED: If the current transaction exists, it executes in a nested transaction, and if there is no current transaction, it performs operations similar to PROPAGATION_REQUIRED (Note: When applied to JDBC, only JDBC drivers above 3.0 apply).

5.Spring Transaction Support

1.spring provides many built-in transaction managers to support different data sources.There are three general categories
  • Under the DataSourceTransactionManager:org.springframework.jdbc.datasource package, the Data Source Transaction Management class provides transaction management for a single javax.sql.DataSource data source, provided it is used for JDBC, Mybatis framework transaction management.
  • HibernateTransactionManager:org.springframework.orm.hibernate3 Package, Data Source Transaction Management Class, provides support for individual org.hibernate.SessionFactory transactions for transaction management when integrating the Hibernate framework; Note: This Transaction Manager only supports Hibernate 3+ and Spring 3.0+ only supports HibernateVersion 3.2+;
  • JtaTransactionManager: Located in the package org.springframework.transaction.jta, provides support for distributed transaction management and delegates transaction management to Java EE application servers or customizes a local JTA transaction manager to be nested in applications.

Built-in transaction managers inherit the abstract class AbstractPlatformTransactionManager, while AbstractPlatformTransactionManager inherits the interface PlatformTransactionManager

The core of the Spring Framework supporting transaction management is transaction manager abstraction. Different data access frameworks can support transaction management of the Minute Data Access Framework by implementing the policy interface PlatformTransactionManager.

The PlatformTransactionManager interface is defined as follows

public interface PlatformTransactionManager {
         TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;//Returns an activated transaction or creates a new transaction (specifically determined by the transaction properties defined by the TransactionDefinition parameter), returning a TransactionStatus object that represents the state of the current transaction, where a TransactionException (unchecked exception) is thrown to indicate that the transaction failed for some reason.
         void commit(TransactionStatus status) throws TransactionException;//Used to commit the transaction represented by the TransactionStatus parameter.
         void rollback(TransactionStatus status) throws TransactionException;//Used to roll back the transaction represented by the TransactionStatus parameter.
}

The TransactionDefinition interface is defined as follows:

public interface TransactionDefinition {  
       int getPropagationBehavior();  //Return Defined Transaction Propagation Behavior
       int getIsolationLevel(); //Return transaction isolation level
       int getTimeout();  //Returns the defined transaction timeout
       boolean isReadOnly();  //Returns whether the defined transaction is read-only
       String getName();  //Return transaction name
} 
The TransactionStatus interface is defined as follows:
public interface TransactionStatus extends SavepointManager {  
       boolean isNewTransaction();  //Returns whether the current transaction is new
       boolean hasSavepoint();  //Returns whether the current transaction has a savepoint
       void setRollbackOnly();  //Set Transaction Rollback
       boolean isRollbackOnly();  //Set whether the current transaction should be rolled back
       void flush();  //Used to refresh modified databases in underlying sessions, typically used to refresh sessions such as Hibernate/JPA, and may have no impact on transactions such as JDBC types;
       boolean isCompleted();  //Return whether the transaction is completed
}  

2.Spring Distributed Transaction Configuration

  • Reference to JNDI data sources from application servers such as Tomcat to indirectly implement JTA transaction management, relying on the application server
  • Direct integration of JOTM (Official Web: http://jotm.objectweb.org/ ), Atomikos (Official: https://www.atomikos.com/ Provides JTA transaction management (no application server support, often used in unit tests)
  • Use the application server-specific transaction manager and use the advanced features of JTA transactions (Weblogic, Websphere)

1. Implement JTA transaction management indirectly by referencing JNDI data sources from application servers such as Tomcat, configured as follows

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/jee
       http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
 <!-- JNDI data source -->
  <jee:jndi-lookup id="dataSource" jndi-name="jdbc/test"/>
    <!-- JTA Transaction Manager  -->
  	<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
  		<!--transactionManagerName Appoint JTA Transaction Manager's JNDI Name, which delegates transaction management to the transaction manager  -->
    	<property name="transactionManagerName" value="java:comp/TransactionManager"/>
  	</bean>
</beans>

2) Distributed transaction management using Atomikos is configured as follows:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"	
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
    xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-3.0.xsd
	http://www.springframework.org/schema/tx
	http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	http://www.springframework.org/schema/task
	http://www.springframework.org/schema/task/spring-task-3.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
	>
     
	<context:component-scan base-package="com.suicai.*.service.impl" />
	<context:component-scan base-package="com.suicai.util" />
    <!-- This method loads configuration files only in xml Use,Tool classes, however, are annotated -->
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:conn.properties" />
	</bean>
	<!-- Only supporting annotations is not supported in xml Use in Configuration properties Files can be used in classes SPEL Expression to load the corresponding value -->
	<bean id="temp" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
		<property name="locations">
			<array>
				<value>classpath:public.properties</value>
			</array>
		</property>
	</bean>
	<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"  destroy-method="close" abstract="true"> 
        <property name="borrowConnectionTimeout" value="60"/>  <!--Failed to get a connection Re-get the maximum time to wait, within which time if a connection is available it will be returned-->
        <property name="reapTimeout" value="20"/> <!--Maximum data acquisition time, if not set, Atomikos With the default of 5 minutes, when processing a large number of data reads, once more than 5 minutes, a similar throw is thrown Resultset is close Error.-->        
        <property name="maintenanceInterval" value="60" />  <!--Connection Recycle Time-->    
        <property name="loginTimeout" value="60" />     <!--java Database connection pool, maximum available for acquisition datasouce Time-->
        <property name="logWriter" value="60"/>
        <property name=""></property>
        <property name="minPoolSize" value="1" />  <!-- Minimum number of connections remaining in connection pool   -->
        <property name="maxPoolSize" value="3" />  <!-- Maximum number of connections remaining in connection pool    -->
        <property name="maxIdleTime" value="60" /> <!-- Maximum idle time,60 If not used in seconds, the connection is discarded.If 0, never discard. Default: 0 -->
    </bean> 
     <!-- Configure 2 data sources mysql -->
     <bean id="ds_suicai" parent="abstractXADataSource">  
     	<!-- uniqueResourceName Represents a unique resource name, such as multiple data sources that cannot be repeated; -->
     	<property name="uniqueResourceName" value="suicaifortest" />
     	<!--  xaDataSourceClassName Is the implementation of a specific distributed data source manufacturer; -->
     	<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
     	<!-- xaProperties Property specifies vendor-specific database properties -->
     	<property name="xaProperties">
            <props>
                <prop key="URL">${db.jdbcUrlOne}</prop>
                <prop key="user">${user}</prop>
                <prop key="password">${password}</prop>
            </props>
        </property>
    </bean>  
	<bean id="ds_kaizhi"  parent="abstractXADataSource">  
		<!-- uniqueResourceName Represents a unique resource name, such as multiple data sources that cannot be repeated; -->
		<property name="uniqueResourceName" value="puildingpurchasefortest" />
		<!-- xaDataSourceClassName Is the implementation of a specific distributed data source manufacturer; -->
		<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
		<!-- xaProperties Property specifies vendor-specific database properties -->
		<property name="xaProperties">
            <props>
                <prop key="URL">${db.jdbcUrlTwo}</prop>
                <prop key="user">${user}</prop>
                <prop key="password">${password}</prop>
            </props>
        </property>
    </bean>  
    <!-- Dynamic Configuration of Data Sources --> 
    <bean id="dataSource2" class="com.suicai.common.datasource.DynamicDataSource">  
        <property name="targetDataSources">  
            <map key-type ="java.lang.String">  
                <entry value-ref ="ds_suicai" key="ds_suicai"></entry >  
                <entry value-ref ="ds_kaizhi" key="ds_kaizhi"></entry >  
            </map > 
        </property>  
        <property name ="defaultTargetDataSource" ref="ds_suicai"></property>  
    </bean>
    
   
    <bean id ="sqlSessionFactoryBeanA" class="org.mybatis.spring.SqlSessionFactoryBean" >  
       <!-- specify data source -->  
       <property name ="dataSource" ref="ds_suicai" />  
       <!-- Appoint mybatis Profile -->  
       <property name ="configLocation" value="classpath:mybatis.cfg.xml" />  
	</bean>
	
	<bean id ="sqlSessionFactoryBeanB" class="org.mybatis.spring.SqlSessionFactoryBean" >  
       <!-- specify data source -->  
       <property name ="dataSource" ref="ds_kaizhi" />  
       <!-- Appoint mybatis Profile -->  
       <property name ="configLocation" value="classpath:mybatis.cfg.xml" />  
	</bean>
	<!--CustomSqlSessionTemplate inherit SqlSessionTemplate Rewrite getSqlSessionFactory Method, please download and view--> 
	<bean id="sqlSessionTemplate" class="com.suicai.util.CustomSqlSessionTemplate" scope="prototype">
        <constructor-arg ref="sqlSessionFactoryBeanA" />
        <property name="targetSqlSessionFactorys">
            <map>     
                <entry value-ref ="sqlSessionFactoryBeanA" key="ds_suicai1"></entry >  
                <entry value-ref ="sqlSessionFactoryBeanB" key="ds_kaizhi1"></entry >  
            </map> 
        </property>
    </bean>  
    
	<!-- To configure atomikos Transaction Manager -->
	<bean id="atomikosTransactionManager" class = "com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method = "close">    
	      <property name="forceShutdown" value="true"/>    
	</bean>    
	<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"></bean>
	<!-- To configure spring Transaction Manager -->
	<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">    
	    <property name="transactionManager">    
	        <ref bean="atomikosTransactionManager"/>    
	    </property>    
	    <property name="userTransaction">    
	        <ref bean="atomikosUserTransaction"/>    
	    </property> 
	    <!-- Must be set, otherwise the program will have an exception JtaTransactionManager does not support custom isolation levels by default -->
	    <property name="allowCustomIsolationLevels" value="true"/>    
	</bean>
	
	<tx:advice id="advice" transaction-manager="transactionManager">
		<tx:attributes>
		    <!-- REQUIRED: Transactions are required, If not, create one in the context -->
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="creat*" propagation="REQUIRED"/>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="delete*" propagation="REQUIRED"/>
			<!-- Support,If there is one,No, no -->
			<tx:method name="*" propagation="SUPPORTS"/>
		</tx:attributes>
	</tx:advice>
	
	<aop:config>
	    <aop:pointcut expression="execution(* com.suicai.*.service.impl.*.*(..))" id="pointcut"/>
	    <!-- bar tx and aop Configuration Associations,Is the complete declarative transaction configuration -->
	    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
	</aop:config>
	<!-- Using package scanning mechanism,Automatically takes all of the contents of the specified package dao register -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- Attention Injection sqlSessionTemplate -->
        <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
		<property name="basePackage" value="com.suicai.*.dao" />
	</bean>
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass">
			<value>org.springframework.web.servlet.view.InternalResourceView</value>
		</property>
		<!--jsp Stored directory-->
		<property name="prefix">
			<value>/</value>
		</property>
		<!--jsp File suffix-->
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>
	<!-- Verification Code -->
	<bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">  
        <property name="config">  
            <bean class="com.google.code.kaptcha.util.Config">  
                <constructor-arg>  
                    <props>  
                        <prop key="kaptcha.border">no</prop>  
                        <prop key="kaptcha.border.color">105,179,90</prop>  
                        <prop key="kaptcha.textproducer.font.color">red</prop>  
                        <prop key="kaptcha.image.width">200</prop>  
                        <prop key="kaptcha.textproducer.font.size">60</prop>  
                        <prop key="kaptcha.image.height">80</prop>  
                        <prop key="kaptcha.session.key">code</prop>  
                        <prop key="kaptcha.textproducer.char.length">4</prop>  
                        <prop key="kaptcha.textproducer.font.names">Song Style,Kai Typography,Microsoft YaHei</prop>  
                    </props>  
                </constructor-arg>  
            </bean>  
        </property>  
    </bean>
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
        <property name="basename" value="classpath:messages"/>  
        <property name="fileEncodings" value="utf-8"/>  
        <property name="cacheSeconds" value="120"/>  
	</bean>
</beans> 

The required packages and associated configuration file download paths for atomikos: http://download.csdn.net/detail/liaohaojian/9810401 Where the file jta.properties is placed in the classpath root directory.

Keywords: Java Database Spring JDBC Mybatis

Added by chrbar on Wed, 10 Jul 2019 19:29:01 +0300