What is a thing
Things can be regarded as a unit composed of several operations on the database at a time.
When we are developing projects at the enterprise level, we are faced with an operation of business personnel, but actually a collection of multi-step operations to read and write to the database. Because data operations are executed sequentially, exceptions may occur in any step of operation. Exceptions will cause the following steps to complete. But at this time, the business logic is not completed correctly (go through the whole process). The previous operation data results may not be reliable at all, so in this case, you should go back.
The function of transaction is to ensure that every operation of the user is reliable, and every operation in the transaction must be successfully executed. As long as an exception occurs, it will fall back to the state of no operation at the beginning of the transaction. These operations are either completed successfully or cancelled, so as to ensure that the data meets the requirements of consistency.
Classification of transactions
Transaction management in Spring can be divided into two forms:
- Programming transaction
- Declarative transaction
Programming transaction
It is rarely used in projects. This method needs to inject a transaction management object TransactionTemplate, and then we need to write our own code to implement when we need to commit or roll back transactions in our code.
It is in our code that we need to manually (shown) commit the rollback transaction like Mybatis.
Declarative transaction
This is based on AOP. In essence, it is an interception before and after methods, so declarative transactions are method level.
There are two ways of Spring declarative transaction management:
- xml based configuration
- Annotation based implementation
Code demonstration:
This is the general control of Spring
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--Note the addition of constraints--> <!--open Spring The annotation scan parses it--> <!--write package Be sure to pay attention to your own package name. Everything under the advanced part can be scanned--> <context:component-scan base-package="com.demo.spring"></context:component-scan> <import resource="db.xml"></import> <!--Import db.xml Configuration file for--> </beans>
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--Note the addition of constraints--> <!--Configure configuration related to database connection--> <!--Spring Read in properties file--> <context:property-placeholder location="config.properties"></context:property-placeholder> <!--to configure Druid Database connection object for--> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"></property> <property name="url" value="${url}"></property> <property name="username" value="${ume}"></property> <property name="password" value="${pwd}"></property> <property name="initialSize" value="${initialSize}"></property> <!--initialSize Initialize several--> <property name="maxActive" value="${maxActive}"></property> <!--maxActive How many connection pools can you create--> </bean> <!--Spring Provided JdbcTemplate Encapsulation class--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="druidDataSource"></property> <!--Will Druids Druid Inject into Spring Provided JdbcTemplate Middle go--> </bean> </beans>
If no transaction is added, in this case:
package com.demo.spring.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository(value = "userDao") public class UserDao { @Autowired JdbcTemplate jdbcTemplate; public void save() { jdbcTemplate.update("insert into admin(account,password,sex) values (?,?,?)","jim","111","male"); int a = 10/0; jdbcTemplate.update("insert into admin(account,password,sex) values (?,?,?)","tom","111","female"); } }
Run test code:
package com.demo.spring.test; import com.demo.spring.dao.UserDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test2 { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); UserDao userDao = applicationContext.getBean("userDao", UserDao.class); userDao.save(); } }
The database will still run the first request sent to the database, and its smallest unit is JDBC template
Now we want the save method in the UserDao class as a whole (in the unit of the whole) to execute or not to execute, which leads to transactions.
Configuration declarative transaction based on xml
Configure using xml
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--Note the addition of constraints--> <!--Configure configuration related to database connection--> <!--Spring Read in properties file--> <context:property-placeholder location="config.properties"></context:property-placeholder> <!--to configure Druid Database connection object for--> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"></property> <property name="url" value="${url}"></property> <property name="username" value="${ume}"></property> <property name="password" value="${pwd}"></property> <property name="initialSize" value="${initialSize}"></property> <!--initialSize Initialize several--> <property name="maxActive" value="${maxActive}"></property> <!--maxActive How many connection pools can you create--> </bean> <!--Spring Provided JdbcTemplate Encapsulation class--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="druidDataSource"></property> <!--Will Druids Druid Inject into Spring Provided JdbcTemplate Middle go--> </bean> <!--Declarative transaction: Spring Configure transaction management--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--Connection to database--> <property name="dataSource" ref="druidDataSource"></property> </bean> <!--to configure Spring Communication behavior, this is Spring A unique function of the framework--> <tx:advice id="txadvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--Adopted here Spring of AOP To add transaction management to the method--> <aop:config> <aop:pointcut id="save" expression="execution(* com.demo.spring.dao.UserDao.save(..))"/> <aop:advisor advice-ref="txadvice" pointcut-ref="save"></aop:advisor> </aop:config> </beans>
Under the management of xml, if you run the code again, you will not let the database execute all the code in case of exceptions.
No more entries in the database
Delete manually written exceptions
Execute again and the results are as follows:
Implemented by annotation
Enable annotation transaction mode:
<!--Enable annotation mode management transaction management--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
Write in the configuration file
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--Note the addition of constraints--> <!--Configure configuration related to database connection--> <!--Spring Read in properties file--> <context:property-placeholder location="config.properties"></context:property-placeholder> <!--to configure Druid Database connection object for--> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"></property> <property name="url" value="${url}"></property> <property name="username" value="${ume}"></property> <property name="password" value="${pwd}"></property> <property name="initialSize" value="${initialSize}"></property> <!--initialSize Initialize several--> <property name="maxActive" value="${maxActive}"></property> <!--maxActive How many connection pools can you create--> </bean> <!--Spring Provided JdbcTemplate Encapsulation class--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="druidDataSource"></property> <!--Will Druids Druid Inject into Spring Provided JdbcTemplate Middle go--> </bean> <!--Declarative transaction: Spring Configure transaction management--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--Connection to database--> <property name="dataSource" ref="druidDataSource"></property> </bean> <!--Enable annotation mode management transaction management--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> </beans>
@The Transactional annotation tag is added to the class, indicating that all methods in the class are added with transaction management. If it is added to the method, the table will the currently added method.
package com.demo.spring.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @Repository(value = "userDao") public class UserDao { @Autowired JdbcTemplate jdbcTemplate; // Transaction: it is regarded as a sequence composed of several operations on the database at a time. It is a whole process, either successful or failed // By default, the jdbc template uses the transaction submission method of jdbc, and is automatically submitted after execution // When we save once, it includes two or more operations on the database // Then we consider these operations as a unit (whole) // This is the atomicity (indivisibility) of transactions. Multiple operations either succeed or fail @Transactional public void save() { jdbcTemplate.update("insert into admin(account,password,sex) values (?,?,?)","jim","111","male"); // int a = 10/0; jdbcTemplate.update("insert into admin(account,password,sex) values (?,?,?)","tom","111","female"); } }
Execute in the form of annotation label, and the result is:
Transaction propagation behavior in Spring
In our actual development, although the user has one operation, there are actually multiple methods at the bottom to implement the operation on the database, so we need to manage the transaction of multiple methods.
An operation of the user
package com.demo.spring.service; import com.demo.spring.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service(value = "userService") public class UserService { @Autowired private UserDao userDao; //Here, userdao is assigned to the userdao attribute in UserService through injection in Spring // Then it is used directly in UserService public void saveUser() { System.out.println("This is UserService Medium saveUser Methods in"); userDao.save1(); int a = 10 / 0; userDao.save2(); } }
The bottom layer needs to operate two methods to implement
package com.demo.spring.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @Repository(value = "userDao") public class UserDao { @Autowired JdbcTemplate jdbcTemplate; // Transaction: it is regarded as a sequence composed of several operations on the database at a time. It is a whole process, either successful or failed // By default, the jdbc template uses the transaction submission method of jdbc, and is automatically submitted after execution // When we save once, it includes two or more operations on the database // Then we consider these operations as a unit (whole) // This is the atomicity (indivisibility) of transactions. Multiple operations either succeed or fail @Transactional public void save1() { jdbcTemplate.update("insert into admin(account,password,sex) values (?,?,?)","jim","111","male"); } @Transactional public void save2(){ jdbcTemplate.update("insert into admin(account,password,sex) values (?,?,?)","tom","111","female"); } }
Test code run:
package com.demo.spring.test; import com.demo.spring.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test2 { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); UserService userService = applicationContext.getBean("userService", UserService.class); userService.saveUser(); } }
result:
If there is an error in UserService, the transaction management here will fail. Based on this problem, as long as we add the @ Transactional tag to UserService, he can't enter. Adding to a class means that all classes are in transaction management. On a person's method, it means that this method is carried out in transaction management.
package com.demo.spring.service; import com.demo.spring.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service(value = "userService") public class UserService { @Autowired private UserDao userDao; //Here, userdao is assigned to the userdao attribute in UserService through injection in Spring // Then it is used directly in UserService @Transactional public void saveUser() { System.out.println("This is UserService Medium saveUser Methods in"); userDao.save1(); int a = 10/0; userDao.save2(); } }
Then the test will be OK.
However, we still need to consider the transaction relationship between the two underlying methods.
What is the propagation behavior of transactions?
Since it is called communication, there must be at least two things before communication can occur. Monomer does not exist to spread this behavior. Transaction propagation behavior refers to how a transaction should proceed when its method is called by another transaction's method. Transaction propagation behavior is a unique transaction enhancement feature of the Spring framework. It does not enter the database behavior of the method actually provided by the transaction.
For example, when the methodA transaction method calls the methodB transaction method, does methodB continue to call the transaction of this methodA or start a transaction management, which is determined by the transaction propagation behavior of methodB.
Profile:
config.properties property file:
driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/demo?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai ume=root pwd=wasd initialSize=5 maxActive=15
Configure database connection and transaction management:
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--Note the addition of constraints--> <!--Configure configuration related to database connection--> <!--Spring Read in properties file--> <context:property-placeholder location="config.properties"></context:property-placeholder> <!--to configure Druid Database connection object for--> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"></property> <property name="url" value="${url}"></property> <property name="username" value="${ume}"></property> <property name="password" value="${pwd}"></property> <property name="initialSize" value="${initialSize}"></property> <!--initialSize Initialize several--> <property name="maxActive" value="${maxActive}"></property> <!--maxActive How many connection pools can you create--> </bean> <!--Spring Provided JdbcTemplate Encapsulation class--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="druidDataSource"></property> <!--Will Druids Druid Inject into Spring Provided JdbcTemplate Middle go--> </bean> <!--Turn on transaction management--> <!--Declarative transaction: Spring Configure transaction management--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--Connection to database--> <property name="dataSource" ref="druidDataSource"></property> </bean> <!--Enable annotation mode management transaction management--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> </beans>
General Spring configuration file:
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--Note the addition of constraints--> <!--open Spring The annotation scan parses it--> <!--write package Be sure to pay attention to your own package name. Everything under the advanced part can be scanned--> <context:component-scan base-package="com.demo.spring"></context:component-scan> <import resource="db.xml"></import> <!--Import db.xml Configuration file for--> </beans>
Code demonstration:
dao layer:
package com.demo.spring.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class DeptDao { @Autowired JdbcTemplate jdbcTemplate; public void save(){ jdbcTemplate.update("insert into dept (name,adminId) values (?,?)","R & D department",1); } }
package com.demo.spring.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class CommonDao { @Autowired JdbcTemplate jdbcTemplate; public void save(){ jdbcTemplate.update("insert into test(id) values (?)",2); } }
service layer:
package com.demo.spring.service; import com.demo.spring.dao.CommonDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service(value = "commonService") public class CommonService { @Autowired CommonDao commonDao; @Transactional public void saveCommon(){ commonDao.save(); } }
In this method, the transaction on the opposite side of A calls B. B is also A transaction, so how does B proceed.
package com.demo.spring.service; import com.demo.spring.dao.DeptDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service(value = "deptService") public class DeptService { @Autowired DeptDao deptDao; @Autowired CommonService commonService; @Transactional//Add A as transaction management public void saveDept(){ deptDao.save(); commonService.saveCommon();//Call B //Then there is a relative contradiction. A and B have transactions, and a calls the B method. // Then, how should B execute A transaction? Here is the transaction execution } }
Adding and writing method of transaction propagation mode:
@Transactional(propagation=Propagation.REQUIRED)
Seven multicast behaviors are defined in Spring.
Transaction propagation behavior | explain |
---|---|
PROPAGATION_REQUIRED | If there is no current transaction, create a new transaction. If there is already a transaction, join it. This is the most common choice. |
PROPAGATION_SUPPORTS | The current transaction is supported. If there is no current transaction, it will be executed in a non transactional manner. |
PROPAGATION_MANDATORY | Use the current transaction. If there is no current transaction, throw an exception. |
PROPAGATION_REQUIRES_NEW | Create a new transaction. If there is a current transaction, suspend the current transaction. |
PROPAGATION_NOT_SUPPORTED | The operation is performed in a non transactional manner. If there is a current transaction, the current transaction is suspended. |
PROPAGATION_NEVER | Execute in a non transactional manner. If a transaction currently exists, an exception will be thrown. |
PROPAGATION_NESTED | If a transaction currently exists, it is executed within a nested transaction. If there is no current transaction, execute the same as the deployment_ Required similar operations. |
PROPAGATION_REQUIRED
If there is no current transaction, create a new transaction. If there is already a transaction, join it.
From front to back, there is and only one transaction created. A and B have only one transaction, which can be understood as that they are all in one container. They want to live together and die together. The premise is that the label of transaction propagation is written (because promotion_required is also a default transaction processing method)
The specified method must be executed within a transaction. If there is a current transaction, add it to the current transaction. If there is no current transaction, a transaction is created and executed in the transaction. The blogging behavior in this case is the most common and the default propagation behavior of Spring.
Code demonstration:
If (int a = 10/0) errors occur in B's transaction management, the theory is that there is no data saved in the database
package com.demo.spring.service; import com.demo.spring.dao.CommonDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service public class CommonService { @Autowired CommonDao commonDao; //If the communication behavior of a and B is REQUIRED, B will directly join the communication behavior of A // If A has no propagation behavior and B has, then B will create A separate transaction //If something goes wrong in B @Transactional(propagation = Propagation.REQUIRED) public void saveCommon(){ commonDao.save(); int a = 10/0; } }
package com.demo.spring.service; import com.demo.spring.dao.DeptDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service(value = "deptService") public class DeptService { @Autowired DeptDao deptDao; @Autowired CommonService commonService; @Transactional(propagation = Propagation.REQUIRED)//Add A as transaction management public void saveDept(){ deptDao.save(); commonService.saveCommon();//Call B //Then there is a relative contradiction. A and B have transactions, and a calls the B method. // Then, how should B execute A transaction? Here is the transaction execution } }
Code of test run result:
package com.demo.spring.test; import com.demo.spring.service.DeptService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test2 { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); DeptService deptService = applicationContext.getBean("deptService", DeptService.class); deptService.saveDept(); } }
As a result, no input is made in the database. There are errors. Although they are not in the same method, they are managed by (REQUIRED) transactions. Therefore, they can be regarded as one method. They must make mistakes together, and the execution results are all right before they can save the data in the database.
If A does not start the transaction at all, the data in A will be stored in it, but B still cannot. If A transaction is started, one of its errors cannot be stored in the database.
PROPAGATION_SUPPORTS
The current transaction is supported. If there is no current transaction, it will be executed in a non transactional manner.
If A has A transaction, B has A transaction, and the transaction propagation is the same as B (that is, in A container). If A doesn't, then B doesn't.
A transaction exists:
package com.demo.spring.service; import com.demo.spring.dao.DeptDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service(value = "deptService") public class DeptService { @Autowired DeptDao deptDao; @Autowired CommonService commonService; @Transactional(propagation = Propagation.REQUIRED)//Add A as transaction management public void saveDept(){ deptDao.save(); commonService.saveCommon();//Call B //Then there is a relative contradiction. A and B have transactions, and a calls the B method. // Then, how should B execute A transaction? Here is the transaction execution } }
The transaction of B is SUPPORTS, and error is in B
package com.demo.spring.service; import com.demo.spring.dao.CommonDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service(value = "commonService") public class CommonService { @Autowired CommonDao commonDao; //If the propagation mode of A is REQUIRED and the propagation mode of B is SUPPORTS, then B will join A for execution //What is A and what is B @Transactional(propagation = Propagation.SUPPORTS) public void saveCommon(){ commonDao.save(); int a = 10/0; } }
The result is that neither of the two input data to the database will successfully enter the data into the database.
If A has no transactions:
package com.demo.spring.service; import com.demo.spring.dao.DeptDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service(value = "deptService") public class DeptService { @Autowired DeptDao deptDao; @Autowired CommonService commonService; public void saveDept(){ deptDao.save(); commonService.saveCommon();//Call B //Then there is a relative contradiction. A and B have transactions, and a calls the B method. // Then, how should B execute A transaction? Here is the transaction execution } }
B still uses SUPPORTS.
Then, both of them have no transaction processing and are executed step by step according to the normal execution data. When the execution is wrong, the opportunity stops.
The result is that although there are errors, both A and B execute and save the database code. (because error 10 / 0 in B is after code execution).
PROPAGATION_REQUIRES_NEW
Create a new transaction. If there is a current transaction, suspend the current transaction.
When A calls transaction B, whether A has A transaction or not, B will create A transaction.
If A has no transaction, then B is A single small transaction.
If A has A transaction, B creates another transaction. During execution, A transaction is suspended and B transaction is executed. Both A and B have transactions, but the two transactions are irrelevant. They don't affect each other.
The transaction processing method of A is still the default transaction processing, but there will be an error in A
package com.demo.spring.service; import com.demo.spring.dao.DeptDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service(value = "deptService") public class DeptService { @Autowired DeptDao deptDao; @Autowired CommonService commonService; @Transactional(propagation = Propagation.REQUIRED)//Add A as transaction management public void saveDept(){ deptDao.save(); commonService.saveCommon();//Call B int a = 10/0; //The code is from top to bottom. int a = 10/0 is the problem code // But before that, B was called, so B was a separate transaction when it was executed. //So B should be able to store the code normally, while A can't. } }
package com.demo.spring.service; import com.demo.spring.dao.CommonDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service(value = "commonService") public class CommonService { @Autowired CommonDao commonDao; //A's mode of transmission is REQUIRED, and B's mode of transmission is requirements_ NEW // , which means that a new transaction is created, which is a separate transaction, // B will not be affected by A @Transactional(propagation = Propagation.REQUIRES_NEW) public void saveCommon(){ commonDao.save(); } }
A new transaction is created in the transaction of B. As long as B is called, it will execute, and the execution of B will not be affected by A.
Operation results:
No data is stored in the dept table
Data can be stored in the test table:
Scenario in which the transaction takes effect
- Calling a method in the same class will cause @ Transactional to fail
- @Transactional is applied to non public modification methods, that is, it can only be used on public modification
- @Transaction annotation attribute propagation setting error (not a reasonable attribute required by you)
- The exception caught by catch leads to @ Transactional failure (it should be caught by catch, so it can be understood that catch will solve this problem and make the code appear to be free of problems)
- The database engine does not support transactions (only InnoDB engine supports transactions in Mysql)