Spring transaction management (1) - three configuration methods

When the data of the project needs to be persistently stored, it is inevitable to interact with the database. In the interactive process, the support for transactions is particularly important. The JDBC specification supports the operation of transactions. The concepts related to JDBC transactions are briefly introduced in the chapter Introduction to JDBC (1) - Connection and Transactions . JDBC standardizes the interaction of different databases, including transaction operations, so that developers can use interface programming to shield the differences between different databases. However, the opening and closing of transactions, as well as the control and configuration of transactions still require manual coding control, which is cumbersome and error-prone. Based on this, Spring has opened up a set of transaction management mechanisms to free developers from tedious transaction control and can easily execute transaction control. However, as a developer, the principle behind convenience also needs to be understood in order to better control the program. Next, I will gradually introduce its operation mechanism from the configuration to the principle of Spring transaction management. This article first introduces three configuration methods from primitive to simplified.

Based on mybatis+mysql, the basic xml configuration is as follows

<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="jdbc:mysql://192.168.1.160:3306/lichao"></property>
	<property name="username" value="root"></property>
	<property name="password" value="root"></property>
	<property name="connectionProperties" value="useUnicode=true;autoReconnect=true;failOverReadOnly=false;characterEncoding=utf8;zeroDateTimeBehavior=convertToNull;allowMultiQueries=true"></property>
</bean>

<!-- mybatis的Session工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="configLocation" value="mybatis-config.xml"></property>
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- UserMapper代理 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<property name="mapperInterface" value="com.lcifn.spring.transaction.mapper.UserMapper"/>
	<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>

<!-- userManager实例 -->
<bean id="userManager" class="com.lcifn.spring.transaction.manager.UserManager">
	<property name="userMapper" ref="userMapper"></property>
</bean>

The configuration of mybatis is not introduced too much here. The transaction is defined in the UserManager layer, and a batch operation method is defined in the UserManager to verify the transaction.

@Slf4j
public class UserManager {
	
	@Getter
	@Setter
	private UserMapper userMapper;

	public void batchOperator(){
		User user = new User("lily", 25);
		// 插入一条user记录
		int insertRows = userMapper.insert(user);
		if(insertRows > 0){
			user = userMapper.getUser(user.getId());
			log.info(user.toString());
			user.setName("jack");
			user.setAge(28);
			// 更新user记录
			userMapper.update(user);
		}
	}
}

1.TransactionProxyFactoryBean proxy

Proxy UserManager directly using TransactionProxyFactoryBean

<!-- userManager事务代理类 -->
<bean id="userManagerTransactionProxy" 
	class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
	<!-- 原始对象 -->
	<property name="target" ref="userManager"/>
	<!-- 事务属性 -->
	<property name="transactionAttributes">
		<props>
			<prop key="batchOperator">PROPAGATION_REQUIRED</prop>
		</props>
	</property>
	<!-- 事务管理器 -->
	<property name="transactionManager">
		<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="dataSource"/>
		</bean>
	</property>
</bean>

TransactionProxyFactoryBean uses ProxyFactory to generate proxy classes to complete transaction processing. transactionAttributes receives a properties object, the key is the method name, and the value is the transaction configuration corresponding to the method. The parsing class of the configuration rule is TransactionAttributeEditor, and the configuration rules are as follows

Configuration name prefix configuration options default allocation
propagation properties PROPAGATION_ REQUIRED|MANDATORY|REQUIRES_NEW|NESTED等 REQUIRED
isolation level ISOLATION_ READ_UNCOMMITTED|READ_COMMITTED|REPEATABLE_READ|SERIALIZABLE DEFAULT
overtime time timeout_ Unit: second -1
read only readOnly Not configured means readable and writable, configured to read read and write
Do not rollback exception rules (noRollbackFor) + exception class package path without
Rollback exception rules (rollbackFor - exception class package path Runtime exceptions and Errors

The transaction manager is a subclass of PlatformTransactionManager, which implements three methods of acquiring transactions, submitting transactions and rolling back transactions. Here, the transaction manager DataSourceTransactionManager of jdbc is used.

write a test class

public class TransactionProxyFactoryBeanTest {

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("TransactionProxyFactoryBean.xml");
		UserManager userManager = context.getBean("userManagerTransactionProxy", UserManager.class);
		userManager.batchOperator();
	}
}

Obtain the proxy object of the userManager through the context, and execute the operation method, you can see the operation of the transaction in the log.

2. XML placement

The above configuration method can only be used as a proxy for one class. It is very good to study the mechanism of Spring transaction management, but in the project, transaction management needs to be configured in batches. It can be done by using Advice and Pointcut in Spring AOP, and Spring defines the tx:advice tag to support configuration.

<!-- 事务管理器 -->
<bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 事务Advice增强配置 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="get*" read-only="true" />
		<tx:method name="*" propagation="REQUIRED"/>
	</tx:attributes>
</tx:advice>

<!-- 配置事务aop -->
<aop:config>
	<aop:pointcut id="userPointcut"
		expression="execution(* com.lcifn.spring.transaction.manager.UserManager.*(..))" />
	<aop:advisor advice-ref="txAdvice" pointcut-ref="userPointcut" />
</aop:config>

In tx:advice, you need to configure the transaction manager, and configure the relationship between methods and transaction configuration in tx:attributes in its subtag. The method configuration supports wildcards to match multiple methods, and the transaction configuration is basically the same as the above, except that Spring provides attribute tags to facilitate configuration. Configure the aop:pointcut pointcut to determine which classes and which methods need to be proxied.

Write a test class, where the userManager is directly obtained. Because of the automatic proxy of aop:config, the returned proxy object is already.

public class TransactionTxAdvice {
	
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("transaction-tx-advice.xml");
		UserManager userManager = context.getBean("userManager", UserManager.class);
		userManager.batchOperator();
	}
}

3. Declarative transaction configuration @Transactional

The way of XML configuration can greatly save configuration operations, but if you want to configure fine-grained configuration for each method, xml will also become very cumbersome. How to do? That's when we thought of annotations. Spring provides a super convenient way to complete transaction control and configuration on classes or methods through annotations.

<!-- 事务注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>

The xml is the simple configuration above, and the @Transactional annotation is used on the class or method. For example, the batchOperator method above can be configured as follows

// 事务传播属性为必须,超时时间为2秒
@Transactional(propagation = Propagation.REQUIRED, timeout = 2)

Whether each method starts a transaction, and what properties the transaction configures can be fine-tuned in this way.

4. Transaction isolation level and propagation method

Spring's transaction isolation level supports four levels defined by the SQL standard: Read Uncommitted (unauthorized read), Read Committed (authorized read), Repeatable Read (repeatable read), Serializable (serialization). You can learn more in JDBC (1) - Introduction to Connection and Transactions .

Spring defines the transaction propagation mode, which refers to the rules for the execution of transaction methods at multiple levels (not the same class), that is, the propagation mode of transactions in the method. Spring defines seven propagation behaviors (including transaction creation and rollback behavior ):

  1. REQUIRED: The default propagation method. If there is a current transaction, support the current transaction; if there is no transaction, create a transaction. All are rolled back when rolled back.
  2. REQUIRES_NEW: If there is a current transaction, suspend the current transaction and create a new transaction; if there is no transaction, also create a new transaction. When rolling back, only the current transaction is rolled back, and other transactions are not affected.
  3. NESTED: Nested transactions. If there is currently a transaction, set the savepoint savepoint; if there is no transaction, create a transaction. Only rollback to savepoint when rolling back.
  4. SUPPORTS: If there is a current transaction, the current transaction is supported; if there is no transaction, it is executed in a non-transactional manner. All are rolled back when rolled back.
  5. MANDATORY: Mandatory transaction. If there is a current transaction, the current transaction is supported; if there is no transaction, an exception is thrown. All are rolled back when rolled back.
  6. NOT_SUPPORTED: If there is a current transaction, suspend the current transaction and execute it in a non-transactional manner. If there is no transaction, execute in a non-transactional manner. There is no rollback.
  7. NEVER: Executes in a non-transactional manner, throws an exception if there is currently a transaction. There is no rollback.

With regard to the creation of transactions, one point needs to be emphasized. The default connection submission mode of JDBC is automatic. If a transaction is enabled, the automatic submission will be changed to manual. Therefore, to open a new transaction, that is, to obtain a new connection , the specific implementation will also be prompted in the subsequent source code analysis. In the next chapter, we will analyze the implementation principle of TransactionProxyFactoryBean.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324409921&siteId=291194637