10.spring声明式事务
一.回顾事务
-
事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!
-
事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。
1.事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。
2.事务四个属性ACID
-
原子性(atomicity)
-
事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
-
-
一致性(consistency)
-
一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
-
-
隔离性(isolation)
-
可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
-
-
持久性(durability)
-
事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
-
二.Spring中的事务管理
1.测试事务的一致性
步骤:(在上一个的博客项目的基础上)
-
在UserMapper接口中添加两个方法
-
addUser:添加用户
-
deleteUser:删除用户
-
-
在UserMapper.xml中编写SQL语句,故意将delete写成deletes导致出错
-
修改UserMapperImpl类
-
添加addUser方法
-
添加deleteUser方法
-
修改selectUser方法,让它先添加一个用户,在删除一个用户最后返回所有用户
-
在UserMapper接口中添加两个方法
1 public interface UserMapper { 2 3 List<User> selectUser(); 4 5 //添加用户 6 int addUser(User user); 7 8 //删除用户 9 int deleteUser(int id); 10 }
在UserMapper.xml中编写SQL语句,故意将delete写成deletes导致出错
1 <insert id="addUser" parameterType="user"> 2 insert into mybatis.user (id, name, pwd) value (#{id},#{name},#{pwd}); 3 </insert> 4 5 <delete id="deleteUser" parameterType="_int"> 6 deletes from mybatis.user where id = #{id}; 7 </delete>
修改UserMapperImpl类
1 public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper { 2 3 4 public List<User> selectUser() { 5 User user = new User(7,"小明","123456"); 6 UserMapper mapper = getSqlSession().getMapper(UserMapper.class); 7 mapper.addUser(user); 8 mapper.deleteUser(7); 9 return mapper.selectUser(); 10 } 11 12 @Override 13 public int addUser(User user) { 14 return getSqlSession().getMapper(UserMapper.class).addUser(user); 15 } 16 17 @Override 18 public int deleteUser(int id) { 19 return getSqlSession().getMapper(UserMapper.class).deleteUser(id); 20 } 21 }
直接运行测试程序发现,添加了用户但没有删除用户,事务没有回滚一致性被破坏
2.Spring的事务管理分为两类:
-
编程式事务管理(不好,不使用)
-
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
-
缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
-
-
声明式事务管理(好,使用)
-
一般情况下比编程式事务好用。
-
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
-
将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
-
3.使用声明式事务管理保证事务的ACID
步骤:
-
修改spring-dao.xml,导入头部约束信息
-
修改spring-dao.xml
-
添加声明式事务
-
添加结合了AOP配置事务通知
-
添加结合了AOP配置切点
-
修改spring-dao.xml,导入头部约束信息tx
- xmlns:tx="http://www.springframework.org/schema/tx"
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd
1 <beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:tx="http://www.springframework.org/schema/tx" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop.xsd 9 http://www.springframework.org/schema/tx 10 http://www.springframework.org/schema/tx/spring-tx.xsd">
修改spring-dao.xml
1 <!--4.配置声明式事务 2 ref:引用我们的数据源 3 --> 4 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 5 <property name="dataSource" ref="dataSource" /> 6 </bean> 7 8 <!--5.结合AOP切入,保证事务的一致性--> 9 <!--配置事务通知--> 10 <tx:advice id="txAdvice" transaction-manager="transactionManager"> 11 <tx:attributes> 12 <!--配置哪些方法使用什么样的事务,配置事务的传播特性 13 1.事务的传播特性:多个事务方法相互调用时,事务如何在这些方法间传播 14 2.read-only="true":只读不可操作数据 15 3.propagation:用于配置事务的传播特性 16 4.propagation="REQUIRED":如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择(默认)。 17 --> 18 <tx:method name="add" propagation="REQUIRED"/> 19 <tx:method name="delete" propagation="REQUIRED"/> 20 <tx:method name="update" propagation="REQUIRED"/> 21 <tx:method name="query" read-only="true"/> 22 <tx:method name="*" propagation="REQUIRED"/> 23 </tx:attributes> 24 </tx:advice> 25 26 <!--6.配置AOP事务切入 27 配置切点为mapper包下的所有类和方法,用于保证事务的ACID 28 --> 29 <aop:config> 30 <aop:pointcut id="txPointcut" expression="execution(* ustc.wzh.mapper.*.*(..))"/> 31 <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> 32 </aop:config>
此时测试发现没有添加,事务发生了回滚保证了一致性
将UserMapper.xml中的delete语句修复,依旧执行成功,保证事务一致性
4.总结:
为什么需要配置事务?
-
如果不配置,就需要我们手动提交控制事务;
-
事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!