Spring - declarative transactions
Our journey is the sea of stars, not the dust of the world
Declarative transaction
Review transactions
- Transaction is very important in the project development process. It involves the problem of data consistency, which should not be careless!
- Transaction management is a necessary technology in enterprise application development to ensure data integrity and consistency.
Transaction is to treat a series of actions as an independent unit of work, which are either completed or ineffective.
Transaction four attribute ACID
-
atomicity
-
- A transaction is an atomic operation, which consists of a series of actions. The atomicity of a transaction ensures that the actions either complete or fail to work at all
-
consistency
-
- Once all transaction actions are completed, the transaction is committed. Data and resources are in a consistent state that meets business rules
-
isolation
-
- Multiple transactions may process the same data at the same time, so each transaction should be isolated from other transactions to prevent data corruption
-
Persistence
-
- Once the transaction is completed, no matter what error occurs in the system, the result will not be affected. Typically, the result of a transaction is written to persistent storage
test
Copy the above code into a new project
In the previous case, we added two methods to the UserMapper interface, delete and add users;
//Add a user int addUser(User user); //Delete user by id int deleteUser(int id);
mapper file, we deliberately write delete wrong, test!
<insert id="addUser" parameterType="User"> insert into user (id,name,pwd) values (#{id},#{name},#{pwd}) </insert> <delete id="deleteUser" parameterType="int"> deletes from user where id = #{id} </delete>
Write the implementation class of the interface. In the implementation class, we operate a wave
public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper { //Add some operations public List<User> selectUser() { User user = new User(12,"Xiao Ming","123456"); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.addUser(user); mapper.deleteUser(12); return mapper.selectUser(); } //newly added public int addUser(User user) { UserMapper mapper = getSqlSession().getMapper(UserMapper.class); return mapper.addUser(user); } //delete public int deleteUser(int id) { UserMapper mapper = getSqlSession().getMapper(UserMapper.class); return mapper.deleteUser(id); } }
test
import com.qifei.mapper.UserMapper; import com.qifei.pojo.User; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTranscationTest { public static void main(String[] args) { ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("application.xml"); UserMapper userMapperImpl = classPathXmlApplicationContext.getBean("userMapperImpl", UserMapper.class); for (User user : userMapperImpl.selectUser()) { System.out.println(user); } } }
Error reporting: sql exception. delete is written incorrectly
Result: insertion succeeded!
No transaction management; We want them to succeed only when they succeed. If there is a failure, they will all fail. We should need affairs!
In the past, we all needed to manage affairs manually, which was very troublesome!
However, Spring provides us with transaction management, and we only need to configure it;
Transaction management in Spring
Spring defines an abstraction layer on top of different transaction management APIs, so that developers can use spring's transaction management mechanism without understanding the underlying transaction management API. Spring supports programmatic transaction management and declarative transaction management.
Programming transaction management
- Embed transaction management code into business methods to control transaction commit and rollback
- Disadvantages: additional transaction management code must be included in each transaction operation business logic
Declarative transaction management
- Generally, it works better than programmatic transactions.
- The transaction management code is separated from the business method to realize the transaction management in a declarative way.
- Transaction management is regarded as a crosscutting concern and modularized through aop method. Spring supports declarative transaction management through the Spring AOP framework.
Using Spring to manage transactions, pay attention to the constraint import of header file: tx
<?xml version="1.0" encoding="UTF8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 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">
Transaction manager
- No matter which transaction management strategy (programmatic or declarative) Spring uses, the transaction manager is required.
- Spring's core transaction management abstraction encapsulates a set of technology independent methods.
JDBC transaction
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
After configuring the transaction manager, we need to configure the notification of transactions
<!--Configure transaction notifications--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--What methods are configured and what transactions are used,Configure propagation properties of transactions--> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <tx:method name="search*" propagation="REQUIRED"/> <tx:method name="get" read-only="true"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
spring transaction propagation feature:
Transaction propagation behavior is how transactions propagate among multiple transaction methods when they call each other. spring supports seven transaction propagation behaviors:
- propagation_ Requisited: if there is no transaction at present, create a new transaction. If there is already a transaction, join it. This is the most common choice.
- propagation_supports: supports the current transaction. If there is no current transaction, it will be executed in a non transaction method.
- propagation_mandatory: use the current transaction. If there is no current transaction, an exception will be thrown.
- propagation_required_new: create a new transaction. If there is a current transaction, suspend the current transaction.
- propagation_not_supported: perform operations in a non transactional manner. If there is a transaction, suspend the current transaction.
- propagation_never: execute the operation in a non transactional manner. If the current transaction exists, an exception will be thrown.
- propagation_nested: if a transaction currently exists, it is executed within a nested transaction. If there is no transaction at present, the and propagation are executed_ Required similar operations
The default transaction propagation behavior of Spring is PROPAGATION_REQUIRED, which is suitable for most situations.
Assuming that ServiveX#methodX() works in a transaction environment (that is, they are enhanced by Spring transactions), assuming that there is the following call chain in the program: service1 #method1 () - > service2 #method2 () - > service3 #method3 (), then the three methods of the three service classes work in the same transaction through the transaction propagation mechanism of Spring.
For example, the methods we just mentioned are called, so they will be placed in a group of transactions!
Configure AOP
Import aop header file!
<!--to configure aop Weaving transaction--> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* com.qifei.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config>
Test
Delete the data just inserted and test again!
public class SpringTranscationTest { public static void main(String[] args) { ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("application.xml"); UserMapper userMapperImpl = classPathXmlApplicationContext.getBean("userMapperImpl", UserMapper.class); for (User user : userMapperImpl.selectUser()) { System.out.println(user); } } }
application.xml
<?xml version="1.0" encoding="UTF8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 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"> <import resource="springbeans.xml"/> <bean id="userMapperImpl" class="com.qifei.mapper.UserMapperImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean> <!--to configure JDBC affair--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!--Configure transaction notifications--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--What methods are configured and what transactions are used,Configure propagation properties of transactions--> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <tx:method name="search*" propagation="REQUIRED"/> <tx:method name="get" read-only="true"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--to configure aop Weaving transaction--> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* com.qifei.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config> </beans>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.qifei.pojo"/> </typeAliases> </configuration>
springbeans.xml
<?xml version="1.0" encoding="UTF8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--DataSource:Replace with data source Mybatis Configuration of We use data sources: org.springframework.jdbc.datasource.DriverManagerDataSource--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8"/> <property name="username" value="root"/> <property name="password" value="111111"/> </bean> <!--to configure sqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:com/qifei/mapper/*.xml"/> </bean> </beans>