9、Spring中的事务
1、事务的ACID
- 原子性
- 一致性
- 隔离性
- 多个业务可能操作同一个资源,防止数据损坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中!
声明式事务: AOP
编程式事务:需要再代码中,进行事务的管理
spring处理事务需要做什么?
spring处理事务的模型,使用的步骤:都是固定的。把事务使用的信息提供给spring就可以了 1)事务内部提交, 回滚事务:使用的事务管理器对象,代替你完成commit, rollback 事务管理:器是一个接口和他的众多实现类。 接口: PlatformTransactionManager. , 定义了事务重要方法commit ,rollback 实现类: spring把每--种数据库访问技术对应的事务处理类都创建好了。 mybatis访问数据库- - spring创建好的是DataSourceTransactionManager hibernate访问数据库- - spring创建的是HibernateTransactionManager 怎么使用: 你需要告诉spring你用是那种数据库的访问技术,怎么告诉spring呢? 声明数据库访问技术对于的事务管理器实现类, 在spring的配置文件中使用<bean>声明就可以了 例如,你要使用mybatis访问数据库,你应该在xml配置文件中配置: <bean id=xxx"class="...DataSourceTransactionManacer" >
2)事务的传播行为:
控制业务方法是不是有事务的,是什么样的事务的。
7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。
PROPAGATION_ REQUIRED;
spring默认,没有事务就新建事务
PROPAGATION_ REQUIRES_ NEW;
总是新建一个事务,如果有事务就将当前事务挂起、
PROPAGATION_ SUPPORTS;
方法在执行时有事务也可以,没有事务也不影响-->查询操作
以上三个需要掌握的
PROPAGATION MANDATORY
PROPAGATION_ NESTED
PROPAGATION_ NEVER
PROPAGATION_ NOT_ SUPPORTED
spring框架中处理事务的方案一、(使用配置文件):
-原始数据:
1、一个业务接口:UserMapper
public interface UserMapper { // 查询所有用户 List<User> getUserAll(); // 添加用户 int addUser(User user); // 删除用户 int deleteUser(int id); }
2、业务接口的实现类:UserMapperImpl
import com.zhixi.pojo.User; import org.mybatis.spring.SqlSessionTemplate; import java.util.List; public class UserMapperImpl implements UserMapper { private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } /** * 查询所有用户 */ public List<User> getUserAll() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); addUser(new User(5,"小五","123")); deleteUser(4); return mapper.getUserAll(); } /** * 添加用户 */ public int addUser(User user) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.addUser(user); } /** * 根据用户id删除用户 */ public int deleteUser(int id) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.deleteUser(id); } }
3、UserMapper.xml定义CRUD方法
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zhixi.dao.UserMapper"> <select id="getUserAll" resultType="user"> select * from user; </select> <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> </mapper>
4、测试文件
@Test public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserMapper userMapper = context.getBean("userMapperImpl", UserMapper.class); List<User> userAll = userMapper.getUserAll(); for (User user : userAll) { System.out.println(user); } }
说明:
1.在UserMapperImpl类中查询用户方法的时候,增加了一个添加用户的方法,一个删除用户的方法、
2.在xml中故意把删除方法写错,在以往经验,肯定会报错,删除4号用户不会执行成功,然后添加5号用户的方法会执行
3.通过上面的结果可以看到,添加用户的方法确实执行了,但是并不符合我们的事务业务规范,同时成功或者同时失败
4、spring的配置文件中添加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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <import resource="classpath:applicationContext.xml"/> <bean id="userMapperImpl" class="com.zhixi.dao.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> <!--开启Spring中的事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--对配置的连接mysql的jdbc执行事务操作--> <constructor-arg ref="datasource"/> </bean> <!--结合Aop实现事务的植入--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 给哪些方法配置事务: name:方法名称 1 )完整的方法名称,不带有包和类。 2 )方法可以使用通配符,*表示任意字符 propagation : 传播行为,REQUIRED【默认】 isolation:隔离级别,默认DEFAULT rollback-for:你指定的异常类名,全限定类名。发生异常一定回滚 --> <tx:attributes> <tx:method name="addUser" propagation="REQUIRED" isolation="DEFAULT"/> <tx:method name="getUserAll" propagation="REQUIRED"/> <tx:method name="deleteUser" propagation="REQUIRED"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置事务切入--> <aop:config> <!-- 配置切入点表达式:指定哪些包中类, 要使用事务 id:切入点表达式的名称,唯一值 expression :切入点表达式, 指定哪些类要使用事务, aspectj会创建代理对象 --> <aop:pointcut id="exPoint" expression="execution(* com.zhixi.dao.*.*(..))"/> <!--配置增强类--> <aop:advisor advice-ref="txAdvice" pointcut-ref="exPoint"/> </aop:config> </beans>
5、测试
我们把数据还原到之前的、再来执行一下上面的语句,看下5号用户还会不会被添加成功了、
可以看到我们的sql确实执行错误了,但是5号用户并没有被添加成功,说明了事务成功!
=====================================================================================================================================
我们再把delete语句修改正确,看是不是会执行:添加5号用户,删除4号用户:
执行成功!
![](https://img2020.cnblogs.com/blog/2126720/202101/2126720-20210104152152529-714688479.png)
spring框架中处理事务的方案二、(使用注解):
1 spring框架中提供的事务处理方案
2 1.适合中小项目使用的注解方案。
3 spring框架自己用aop实现给业务方法增加事务的功能,使 用@Transactional注解增加事务。
4 @Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
5 可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等
@Transactional的可选属性:
- propagation:用于设置事务传播属性。该属性类型为Propagation 枚举,默认值为lsolation.REQUIRED
- isolation:用于设置事务隔离级别。该属性类型为Isolation 枚举,默认值为lsolation.DEFAULT。
-
readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为boolean, 默认值为true,在数据库查询时可设置为真
- rollbackFor:表示方法抛出什么异常,才进行回滚、
@Transactional注解的步骤:
1.需要在spring的xml配置文件声明事务管理器对象,和指定数据库:
<!--开启Spring中的事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--对配置的连接mysql的jdbc执行事务操作--> <constructor-arg ref="datasource"/> </bean>
2.开启事务注解驱动,告诉spring框架,我要使用注解的方式管理事务。
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
</tx:advice>
<tx:annotation-driver id="transactionInterceptor" transaction-manager="transactionManager">
</tx:advice>
spring使用aop机制,创建@Transactional所在的类 代理对象,给方法加入事务的功能。
spring给业务放法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知:
Around("你要增加的事务功能的业务方法名称")
0bject myAround() {
spring开启事务
try{
业务代码
spring事务管理.commit();
}catch(Exception e){
spring事务管理.rollback();
}
}
3、在方法上面加入@Transaction
下面黄色背景的注解参数可以直接写成:@Transactional,或者可以直接把注解加到public类上,说明这个类下所有的方法都是被事务管理
/** * 添加用户 */ @Transactional( propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false, rollbackFor = {Exception.class} ) public int addUser(User user) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.addUser(user); }