spring事务详解(基于注解和声明的两种实现⽅式)
Spring事务( Transaction )
事务的概念
事务是⼀些sql语句的集合,作为⼀个整体执⾏,⼀起成功或者⼀起失败。
使⽤事务的时机
⼀个操作需要多天sql语句⼀起完成才能成功
程序中事务在哪⾥说明
加在业务类的⽅法上⾯(public⽅法上⾯),表⽰业务⽅法执⾏时,需要事务的⽀持。
不同的事务管理器
不同的数据库访问技术,处理事务是不同的
1. 使⽤jdbc访问数据库,事务处理
public void updateAccount(){
Connection con = .....;
con.setAutoCommit(false);
state.insert();
state.update();
statemit();
con.setAutoCommit(true);
}
2. MyBatis执⾏数据库,处理事务
public void updateAccount(){
SqlSession sqlSession = SqlSessionFactory.openSession(false);
spring roll怎么读
try{
sqlSession.insert(...);
sqlSession.update(...);
sqlSessionmit();
}catch(Exception e){
}
}
spring统⼀管理事务,把不同的数据库访问技术的事务处理统⼀起来
使⽤spring的事务管理器,管理不同数据库访问技术的事务处理。开发⼈员只需要掌握spring的事务处理⼀个⽅案,就可以实现使⽤不同数据库访问技术的事务管理。
尽管事务⾯向的是spring,有spring管理事务,做事务提交和回滚。
spring事务管理器
spring框架使⽤事务管理器对象,管理所有的事务。
事务管理器接⼝: PlatFormTransactionManager
作⽤:定义了事务的操作,主要是commit() , rollback()
事务管理器有很多的实现类:⼀种数据库访问计数有⼀个实现类。由实现类具体完成事务的提交,回滚。
这意味着:JDBC或者MyBatis访问数据库有⾃⼰的事务管理实现类:DataSourceTransactionManager
hibernate框架,他的事务管理器实现类:HibernateTransactionManager
事务管理器的⼯作⽅式
spring集中统⼀管理事务,分配管理事务给具体的事务管理器对象。
事务提交和回滚的时机
当业务正常执⾏的时候,没有异常,事务是提交的。如果业务代码中出现了运⾏时异常,事务会发⽣回滚。
异常的分类:
Error :错误,回滚事务
Exception:
运⾏时异常:RuntimeException和他的⼦类都是运⾏时异常,在程序执⾏过程中抛出的异常
受查异常:在编写代码时需要处理的异常(编译都⽆法通过),会提交事务。
⽅法抛出运⾏时异常事务回滚,其他的情况都是执⾏事务。
spring事务管理的实现⽅式:AOP中的环绕通知
环绕通知:在⽬标⽅法的前后都可以增加功能,不需要修改代码。
// spring给业务⽅法在执⾏时,增加事务的切⾯功能(⼀下为⼤致的实现步骤,不是真正的执⾏代码)
@Around("execution(* com.wang.*.*(..))")
public Object myAround(ProceedingJoinPoint pjp){
try{
PlatformTransactionManager.beginTransaction(); // 使⽤spring的事务管理器,开启事务
pjp.proceed(); // 执⾏⽬标⽅法
PlatformTransactionManagermit(); // 业务⽅法正常执⾏,事务提交
}catch(Exception e){
}
}
事务定义接⼝(TransactionDefinition )
事务定义接⼝TransactionDefinition中定义了事务描述相关的三类常量:事务隔离级别,事务传播⾏为,事务默认超时时限,及他们的操作。
给业务⽅法说明事务的属性。
隔离级别
定义
控制事务之间的影响速度
具体值
DEFAULT:采⽤DB默认的事务隔离级别。Mysql的默认为REPEATABLE_READ,Oracle默认为READ_COMMITTED
READ_UNCOMMITTED:读未提交。未解决任何并发问题
READ_COMMITTER:读已提交。解决脏读,存在不可重复读和幻读
REPETABLE_READ:可重复读。解决脏读,不可重复读,存在幻读
SERIALIZABLE:串⾏化。不存在并发问题。
事务超时时间
以秒为单位,整数值,默认为-1
超时时间:表⽰⼀个业务⽅法最长的执⾏时间,到达时间没有执⾏完毕,spring会回滚事务。
传播⾏为
传播⾏为有7个值
定义:业务⽅法在调⽤的时候,事务在⽅法之间的传递和使⽤。
使⽤传播⾏为,表⽰⽅法有⽆事务。
PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_SUPPORTS
以上三个需要掌握
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
1. PROPAGATION_REQUIRED:spring默认传播⾏为,⽅法在调⽤的时候,如果存在事务就是⽤当前的事务,如果没有事务,就新建
⼀个事务,⽅法在新事务中执⾏。
2. PROPAGATION_SUPPORTS:⽅法有事务可以正常执⾏,没有事务也可以正常执⾏。(查询操作)
3. PROPAGATION_REQUIRES_NEW:⽅法需要⼀个新事务。如果调⽤⽅法的时候,存在⼀个事务,则原来的事务暂停,知道新事务
执⾏完毕。如果⽅法调⽤的时候,没有事务,则新建⼀个事务,在新事务中执⾏代码。
spring框架使⽤⾃⼰的注解@Transactional控制事务
@Transactional注解,使⽤注解的属性控制事务(隔离级别,传播⾏为,超时)
其中的属性:
propagation:事务的传播⾏为,他使⽤的Propagation类的枚举值,例如:Propagation.REQUIRED;
isolation:表⽰隔离级别,使⽤Isolation类的枚举值,表⽰隔离级别,默认是:Ioslation.DEFAULT;
readOnly:boolean类型的值,表⽰数据库操作是不是只读的,默认为false
timeout:事务超时,默认是-1,整数值,单位是秒,例如:timeout=20;
rollbackFor:表⽰回滚的异常类列表,他的值是⼀个数组,每个值是异常类型的class。
rollbackForClassName:表⽰回滚的异常类列表,是String类型的值
noRollbackFor:不需要回滚的异常类列表,是class类型的
noRollbackForClassName:不需要回滚的异常类列表,是String类型的值
该注解放置的位置:
1. 在业务⽅法上⾯,实在public⽅法上⾯(⼤多数)
2. 在类的上⾯(⼏乎见不到)
注解的使⽤步骤
1. 在spring配置⽂件中,声明事务的内容;
声明事务管理器,说明使⽤哪个事务管理器对象;
声明使⽤注解管理事务,开启注解驱动
2. 在类的源代码中,加⼊@Transactional
事务的控制模式:
1. 编程式,在代码中编程控制事务
2. 声明式事务,不⽤编码
步骤⼀:
<!--声明事务管理器(连接到数据库,做事务提交,事务回滚)-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<!--指定数据源-->
<property name="dataSource" ref="myDataSource"/>
</bean>
<!--开启事务注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--最后导⼊的包是以tx结尾-->
步骤⼆:
在具体的⽅法上加上@Transactional注解
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
timeout = 20,
rollbackFor = {NullPointerException.class}
)
@Override
public void buy(Integer goodId, Integer amount) throws Exception {
System.out.println("buy⽅法的执⾏");
Sale sale = new Sale();
sale.setGid(goodId);
sale.setNums(amount);
/
/ ⽣成销售记录
saleDao.insertSale(sale);
// 查询商品
Good good = goodDao.selectById(goodId);
if (good == null){
throw new Exception("商品不存在");
}else if (Amount() < amount){
throw new Exception("库存不⾜");
}
// 更新库存
Good good1 = new Good();
good1.setId(goodId);
good1.setAmount(amount);
goodDao.updateGood(good1);
System.out.println("buy⽅法的完成");
}
rollbackFor说明
1. 框架⾸先检查⽅法抛出的异常是不是在rollbackFor数组中,如果在⼀定会发⽣回滚;
2. 如果⽅法抛出的异常不在rollbackFor数组中,框架会继续检查抛出的异常是不是RuntimrException,如果
是RuntimeException,⼀定会发⽣回滚。
使⽤rollbackFor可以实现发⽣受检查异常时让其发⽣回滚。
注解的使⽤特点
直接使⽤@Transactional会使⽤默认值
spring框架⾃⼰提供的事务控制
适合中⼩型项⽬,注解都放置在了源代码中,不利于优化
使⽤⽅便效率⾼
使⽤Aspectj框架在spring配置⽂件中,声明事务控制
使⽤aspectj的aop,声明事务控制叫做声明式事务
使⽤步骤
1. 加⼊spring-aspectj的依赖
2. 在spring的配置⽂件声明事务属性
声明事务管理器
声明业务⽅法需要的事务属性
声明切⼊点表达式
步骤
基本上是模板化的⽅法
<!--声明式事务-->
<!--1.声明事务管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager2">
<property name="dataSource" ref="myDataSource"/>
</bean>
<!--2.声明业务⽅法的事务属性(隔离级别,传播⾏为,超时)
id:给业务⽅法配置事务段代码起个名字,唯⼀值
transaction-manager:事务管理器的id
-->
<tx:advice id="serviceAdvice" transaction-manager="transactionManager2">
<!--给具体的业务⽅法增加事务的说明-->
<tx:attributes>
<!-- 给具体的业务⽅法,说明他需要的事务属性
name:业务⽅法名称,配置name的值 1.业务⽅法的名称(类中的某⼀个⽅法) 2.带有部分通配符的⽅法名称 3.使⽤*
propagation:指定传播⾏为
isolation:隔离级别
read-only:是否只读,默认为false
timeout:超时时间
rollback-for:指定回滚的异常类列表,使⽤的异常类的全限定名称(多个异常时⽤都好分割)
-->
<tx:method name="buy"
isolation="DEFAULT"
propagation="REQUIRED"
timeout="20"
rollback-for="java.lang.NullPointerException"
/>
<!--在业务⽅法有命名规则的时候,可以对⼀些⽅法使⽤事务-->
<tx:method name="add*" propagation="REQUIRED" timeout="20" isolation="DEFAULT"/>
<tx:method name="delete*" propagation="REQUIRED" timeout="20" isolation="DEFAULT"/>
<!--以上⽅法以外的-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--通过上述⽅法的声明,但是我们并不知道是哪个类的⽅法,让上述声明⽣效的⽅法:切⼊点表达式--> <!--声明切⼊点表达式:表⽰哪些包中的哪些类的⽅法参与事务-->
<aop:config>
<!--声明切⼊点表达式
expression:切⼊点表达式,表⽰哪些类中的哪些⽅法要参与事务
id:切⼊点表达式的名称,唯⼀值
-->
<aop:pointcut id="servicePointCut" expression="execution(* *..service..*.*(..))"/>
<!-- 关联切⼊点表达式和事务的通知-->
<aop:advisor advice-ref="serviceAdvice" pointcut-ref="servicePointCut"/>
</aop:config>
优缺点
缺点:理解难,配置复杂
优点:代码和事务分开。控制事务源代码不⽤修改。
能快速的了解和掌握项⽬的全部事务。适合⼤型项⽬。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。