Spring(五) spring事务处理
文章目录
一、spring的事务管理
1.1 什么是事务
事务是指一组sql语句的集合, 集合中有多条sql语句
可能是insert , update ,select ,delete, 我们希望这些多个sql语句都能成功,
或者都失败, 这些sql语句的执行是一致的,作为一个整体执行
1.2 什么时候使用事务
当我的操作,涉及得到多个表,或者是多个sql语句的insert,update,delete。需要保证
这些语句都是成功才能完成我的功能,或者都失败,保证操作是符合要求的。
注意: java中事务代码应该放在service类的业务方法上,因为业务方法会调用多个dao方法,执 行多个sql语句
1.3 JDBC与mybatis如何处理事务
jdbc访问数据库,处理事务 Connection conn ; conn.commit(); conn.rollback();
mybatis访问数据库,处理事务, SqlSession.commit(); SqlSession.rollback();
hibernate访问数据库,处理事务, Session.commit(); Session.rollback();
1.4 不同数据库中的事务处理方式的缺点
- 不同的数据库访问技术,处理事务的对象,方法不同,
需要了解不同数据库访问技术使用事务的原理 - 掌握多种数据库中事务的处理逻辑。什么时候提交事务,什么时候回顾事务
- 处理事务的多种方法。
总结: 就是多种数据库的访问技术,有不同的事务处理的机制,对象,方法。
1.5 怎么解决不同技术的缺点
spring提供一种处理事务的统一模型, 能使用统一步骤,方式完成
多种不同数据库访问技术的事务处理。
使用spring的事务处理机制,可以完成mybatis访问数据库的事务处理
使用spring的事务处理机制,可以完成hibernate访问数据库的事务处理。
二、spring如何处理事务
2.1 事务管理器
接口:PlatformTransactionManager ,定义了事务重要方法 commit ,rollback
实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了。
主要用到两个接口实现类:
- mybatis访问数据库—spring创建好的是DataSourceTransactionManager
- hibernate访问数据库----spring创建的是HibernateTransactionManager
使用方式:你需要告诉spring 你用是那种数据库的访问技术
声明数据库访问技术对于的事务管理器实现类, 在spring的配置文件中使用声明
例如:你要使用mybatis访问数据库,你应该在xml配置文件中
<!--声明式事务处理:和源代码完全分离-->
<!--1.声明事务管理器对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource"/>
</bean>
2.2 说明事务类型
需要说明的事务属性有:
-
事务的隔离级别:有4个值。
- DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
- READ_UNCOMMITTED:读未提交。未解决任何并发问题。
- READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
- REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
- SERIALIZABLE:串行化。不存在并发问题。
-
事务的超时时间:表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。
单位是秒, 整数值, 默认是 -1. (一般不做修改) -
事务的传播行为: 控制业务方法是不是有事务的, 是什么样的事务的。
7个传播行为,表示你的业务方法调用时,事务在方法之间是如何使用的。-
PROPAGATION_REQUIRED(常用,默认)
指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中
-
PROPAGATION_REQUIRES_NEW(常用)
总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。
-
PROPAGATION_SUPPORTS(常用)
指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。
-
PROPAGATION_MANDATORY
-
PROPAGATION_NESTED
-
PROPAGATION_NEVER
-
PROPAGATION_NOT_SUPPORTED
-
2.3 事务提交事务,回滚事务的时机
-
当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit
-
当你的业务方法抛出运行时异常或ERROR, spring执行回滚,调用事务管理器的rollback
运行时异常的定义: RuntimeException 和他的子类都是运行时异常, 例如:NullPointException , NumberFormatException
-
当你的业务方法抛出非运行时异常, 主要是受查异常时,提交事务
受查异常:在你写代码中,必须处理的异常。例如IOException, SQLException
2.4 总结spring的事务
- 管理事务的是 事务管理和他的实现类
- spring的事务是一个统一模型
- 指定要使用的事务管理器实现类,使用
- 指定哪些类,哪些方法需要加入事务的功能
- 指定方法需要的隔离级别,传播行为,超时
需要为spring指定:项目中类的信息,方法的名称,方法的事务传播行为
三、spring框架中提供的两种事务处理方案
有两种方式:
- 使用 Spring 的事务注解管理事务(掌握)
- 使用 AspectJ 的 AOP 配置管理事务(掌握)
3.1 使用 Spring 的事务注解管理事务
适合中小项目使用的, 注解方案。
spring框架自己用aop实现给业务方法增加事务的功能, 使用@Transactional注解增加事务。
@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等
使用 @Transactional 的步骤:
-
声明事务管理器(要指定dataSource,即之前声明数据源)
<!--声明事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--连接数据库信息,指定数据源--> <property name="dataSource" ref="myDataSource"/> </bean>
-
开启事务注解驱动 tx结尾的driven(赋值事务管理器id)
<!--开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象 transaction-manager:事务管理器的id--> <tx:annotation-driven transaction-manager="transactionManager"/>
-
service层在需要开启事务的public方法上加**@Transactional注解**
/** * rollbackFor:表示发生指定的异常一定回滚. * 处理逻辑是: * 1) spring框架会首先检查方法抛出的异常是不是在rollbackFor的属性值中 * 如果异常在rollbackFor列表中,不管是什么类型的异常,一定回滚。 * 2) 如果你的抛出的异常不在rollbackFor列表中,spring会判断异常是不是RuntimeException, * 如果是一定回滚。 */ //使用的是事务控制的默认值, 默认的传播行为是REQUIRED,默认的隔离级别DEFAULT //默认抛出运行时异常,回滚事务 // @Transactional( // propagation = Propagation.REQUIRED, // isolation = Isolation.DEFAULT, // readOnly = false, // rollbackFor = {NullPointerException.class, // NotEnoughException.class} // ) @Transactional @Override public void buy(Integer goodId, Integer nums) { }
原理:spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知
@Around("你要增加的事务功能的业务方法名称")
Object myAround(){
开启事务,spring给你开启
try{
buy(1001,10);
spring的事务管理器.commit();
}catch(Exception e){
spring的事务管理器.rollback();
}
}
3.2 使用 AspectJ 的 AOP 配置管理事务(掌握)
适合大型项目,有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,
在spring配置文件中声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。
实现步骤:在xml配置文件中实现。
-
要使用的是aspectj框架,需要在pom文件中加入依赖
pom.xml
<!--aspectj依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.15.RELEASE</version> </dependency>
-
声明事务管理器对象
<!--声明式事务处理:和源代码完全分离--> <!--1.声明事务管理器对象--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="myDataSource"/> </bean>
-
配置事务通知:
声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)
<!--2.声明业务方法它的属性(隔离级别,传播行为,超时时间) id:自定义名称,表示 <tx:advice>和</tx:advice>之间的配置内容 transaction-manager:事务管理器的id --> <tx:advice id="myAdvice" transaction-manager="transactionManager"> <!--<tx:attributes>:配置事务属性--> <tx:attributes> <!--<tx:method name=""/>表示要给剧痛的方法配置事务属性,method可以有多个,分别给不同的方法配置事务属性 name:方法名称 , (1) 完整的方法名称,不带有包和类 (2) 方法可以使用通配符,*表示任意字符 propagation: 传播行为,枚举值 isolation: 隔离级别 rollback: 你指定的异常类名,全限定类型,发生异常一定回滚 --> <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.NullPointerException,com.excep.NotEnoughException"/> <!--使用通配符,指定很多的方法--> <tx:method name="add*" propagation="REQUIRES_NEW"/> <!--指定修改方法--> <tx:method name="modify*"/> <!--指定删除方法--> <tx:method name="remove*"/> <!--查询方法,query,search,find--> <tx:method name="*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice>
-
配置增强器:
指定将配置好的事务通知,织入给谁
<!--配置aop--> <aop:config> <!--配置切入点表达式:指定哪些包中类,要使用事务, id:切入点表达式的名称,唯一值 expression:切入点表达式,指定哪些类要使用事务 aspectj会创建代理对象 --> <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/> <!--配置增加器,关联adivce和pointcut advice-ref:通知,上面的tx:advice那里的配置 pointcut-ref=切入点表达式 --> <aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt"/> </aop:config>