Spring 5 declarative transaction control
1. Programming transaction control related objects
1.1 PlatformTransactionManager
The PlatformTransactionManager interface is the transaction manager of spring, which provides our common methods of operating transactions.
method | explain |
---|---|
TransactionStatus getTransaction(TransactionDefination defination) | Gets the status information of the transaction |
void commit(TransactionStatus status) | Commit transaction |
void rollback(TransactionStatus status) | Rollback transaction |
be careful:
PlatformTransactionManager is an interface type. Different Dao layer technologies have different implementation classes, such as:
When Dao layer technology is JDBC or mybatis: org.springframework.jdbc.datasource.DataSourceTransactionManager
When Dao layer technology is Hibernate: org.springframework.orm.hibernate5.hibernatetransaction Manager
1.2 TransactionDefinition
TransactionDefinition is the transaction definition attribute information object, which contains the following methods:
method | explain |
---|---|
int getIsolationLevel() | Gets the isolation level of the transaction |
int getPropogationBehavior() | Get propagation behavior of transaction |
int getTimeout() | Get timeout |
boolean isReadOnly() | Read only |
-
Transaction isolation level
Setting the isolation level can solve the problems caused by transaction concurrency, such as dirty reading, non repeatable reading and virtual reading (phantom reading).
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITTED
ISOLATION_READ_COMMITTED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE -
Transaction propagation behavior
REQUIRED: if there is no transaction currently, create a new transaction. If there is already a transaction, join it. General selection (default)
SUPPORTS: SUPPORTS the current transaction. If there is no transaction, it will be executed in a non transactional manner (no transaction)
MANDATORY: use the current transaction. If there is no transaction, an exception will be thrown
REQUERS_NEW: create a new transaction. If it is currently in a transaction, suspend the current transaction.
NOT_SUPPORTED: perform operations in a non transactional manner. If there is a transaction, suspend the current transaction
NEVER: runs in a non transactional manner. If there is a transaction, an exception will be thrown
NESTED: if a transaction currently exists, it is executed within a NESTED transaction. If there is no current transaction, perform an operation similar to REQUIRED
Timeout: the default value is - 1. There is no timeout limit. If yes, set in seconds
Read only: it is recommended to set it as read-only when querying
1.3 TransactionStatus
The TransactionStatus interface provides the specific running status of transactions. The methods are described below.
method | explain |
---|---|
boolean hasSavepoint() | Store rollback points |
boolean isCompleted() | Is the transaction complete |
boolean isNewTransaction() | Is this a new transaction |
boolean isRollbackOnly() | Whether the transaction is rolled back |
1.4 key points of knowledge
Three objects of programming transaction control
PlatformTransactionManager
TransactionDefinition
TransactionStatus
2. Declarative transaction control based on XML
2.1 what is declarative transaction control
Spring's declarative transaction, as its name implies, is to handle transactions in a declarative manner. The declaration here refers to the declaration in the configuration file, and the declarative transaction in the spring configuration file is used to replace the code transaction.
The role of declarative transactions
- Transaction management does not invade developed components. Specifically, the business logic object will not realize that it is in the process of transaction management. In fact, it should be so, because transaction management is a system level service, not a part of business logic. If you want to change the transaction management plan, you only need to reconfigure it in the definition file. When transaction management is not needed, As long as you modify the setting file, you can remove the transaction management service without changing the code and recompiling, which is very convenient for maintenance
Note: the underlying layer of Spring declarative transaction control is AOP.
- Business logic pointcut
- Transaction control notification
2.2 implementation of declarative transaction control (quick start)
applicationContext.xml
Configuration points:
Platform transaction manager configuration
Configuration of transaction notifications
Configuration of transaction aop weaving
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd "> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="accountDao" class="com.raphuscucullatus.dao.impl.AccountDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <!-- Target objects and business methods are pointcuts --> <bean id="accountService" class="com.raphuscucullatus.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> </bean> <!-- Configure the platform transaction manager to provide notifications --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- notice --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- Configuration weaving --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.raphuscucullatus.service.impl.*.*(..))"/> </aop:config> </beans>
jdbc.priperties
jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=088.5741
pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.raphuscucullatus</groupId> <artifactId>spring_tx</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> </project>
dao
package com.raphuscucullatus.dao.impl; import com.raphuscucullatus.dao.AccountDao; import org.springframework.jdbc.core.JdbcTemplate; /** * @author raphus cucullatus * @version 2021/9/25 23:28 * @since JDK8 */ public class AccountDaoImpl implements AccountDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate){ this.jdbcTemplate = jdbcTemplate; } @Override public void out(String outMan, double money) { jdbcTemplate.update("update account set money=money-? where name = ?",money,outMan); } @Override public void in(String inMan, double money) { jdbcTemplate.update("update account set money=money+? where name = ?",money,inMan); } }
service
package com.raphuscucullatus.service.impl; import com.raphuscucullatus.dao.AccountDao; import com.raphuscucullatus.service.AccountService; /** * @author raphus cucullatus * @version 2021/9/25 23:26 * @since JDK8 */ public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void transfer(String outMan, String inMan, double money) { accountDao.out(outMan,money); System.out.println(1/0); accountDao.in(inMan,money); } }
test case
package com.raphuscucullatus.controller; import com.raphuscucullatus.service.AccountService; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author raphus cucullatus * @version 2021/9/25 23:30 * @since JDK8 */ public class AccountController { private AccountService accountService; public void setAccountService(AccountService accountService){ this.accountService=accountService; } public static void main(String[] args) { ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService accountService = classPathXmlApplicationContext.getBean(AccountService.class); accountService.transfer("tom","jerry",1000); } }
2.3 XML explanation
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd "> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="accountDao" class="com.raphuscucullatus.dao.impl.AccountDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <!-- Target objects and business methods are pointcuts --> <bean id="accountService" class="com.raphuscucullatus.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> </bean> <!-- Configure platform transaction manager(The specific implementation class is provided by DAO Layer technology implementation decision) Used to provide notifications --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- advice notice attributes Set transaction properties name Tangent point method name isolation Isolation level propagation Communication behavior timeout Timeout read-only read-only o-rollback-for rollback-for --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/> <tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/> <tx:method name="findAll" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/> <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- Configuration weaving advice-ref Transaction reference pointcut breakthrough point --> <aop:config> <!-- Extract tangent point --> <!-- <aop:pointcut id="transfer" expression="execution(* com.raphuscucullatus.service.impl.*.*(..))"/>--> <!-- <aop:advisor advice-ref="txAdvice" pointcut-ref="transfer"/>--> <!-- Do not extract tangent points --> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.raphuscucullatus.service.impl.*.*(..))"/> </aop:config> </beans>
3. Annotation based declarative transaction control
3.1 configuring declarative transaction control using annotations
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd "> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <!-- Component scan(Annotation configuration) --> <context:component-scan base-package="com.raphuscucullatus"/> <!-- Configure platform transaction manager(The specific implementation class is provided by DAO Layer technology implementation decision) Used to provide notifications --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- Annotation driven(Annotation configuration) --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
dao
package com.raphuscucullatus.dao.impl; import com.raphuscucullatus.dao.AccountDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; /** * @author raphus cucullatus * @version 2021/9/25 23:28 * @since JDK8 */ @Repository("accountDao") public class AccountDaoImpl implements AccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void out(String outMan, double money) { jdbcTemplate.update("update account set money=money-? where name = ?",money,outMan); } @Override public void in(String inMan, double money) { jdbcTemplate.update("update account set money=money+? where name = ?",money,inMan); } }
service
package com.raphuscucullatus.service.impl; import com.raphuscucullatus.dao.AccountDao; import com.raphuscucullatus.service.AccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.test.annotation.Rollback; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** * @author raphus cucullatus * @version 2021/9/25 23:26 * @since JDK8 */ @Service("accountService") public class AccountServiceImpl implements AccountService { /** * */ @Autowired private AccountDao accountDao; /** * Business method * * The annotation Transactional() indicates transaction control for this class, and the transaction attribute is set in parentheses * When the annotation is on a class: set the transaction properties of all methods in the class * When the annotation is on a method: set the transaction properties of all methods of the method * @param outMan transfer accounts * @param inMan Collection * @param money amount of money */ @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED) @Override public void transfer(String outMan, String inMan, double money) { accountDao.out(outMan,money); accountDao.in(inMan,money); } }
test case
package com.raphuscucullatus.controller; import com.raphuscucullatus.service.AccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Controller; /** * @author raphus cucullatus * @version 2021/9/25 23:30 * @since JDK8 */ public class AccountController { public static void main(String[] args) { ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService accountService = classPathXmlApplicationContext.getBean(AccountService.class); accountService.transfer("tom","jerry",1000); } }
3.2 annotation configuration declarative transaction control resolution
① Use @ Transactional to modify classes or methods that need transaction control. The attributes available for annotation are the same as xml configuration methods, such as isolation level, propagation behavior, etc.
② If annotations are used on a class, all methods under the class are configured with the same set of annotation parameters.
③ In terms of methods, different methods can adopt different transaction parameter configurations.
④ Annotation driven to enable transaction in Xml configuration file < TX: annotation driven / >
Key points of knowledge
Configuration points of annotated declarative transaction control
Platform transaction manager configuration (xml mode)
Configuration of transaction notification (@ Transactional annotation configuration)
Transaction annotation driven configuration TX: annotation driven/