1、申明式事务
a.准备一个方法,例如购买书本,同时需要将库存和用户余额进行修改。
b.在xml中作如下配置:
<!-- 配置事务注解管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
c.在需要开启事务的方法上添加事务标签:即同时进行上述a中两个操作的方法。
@Transactional
public void checkOut(String userName, List<String> isbns) {}
2、事务的传播行为
事务传播属性可以在 @Transactional 注解的 propagation 属性中定义,默
认为REQUIRED
@Transactional(propagation=Propagation.REQUIRED )
1)、REQUIRED具体如下:
来自尚硅谷详解:
|---即purchase()方法与checkout()都添加了事务,但只走checkout()的事务,即如果在checkout()执行的过程发生任何异常都会回滚到checkout()的开始。
|---形象一点就是,purchase()购买第一本书书时没有发生异常,但购买第二本书时发生异常,则会回滚到一本书都没买的时候。
2)、REQUIRES_NEW 具体如下:
来自尚硅谷|----即purchase()方法与checkout()都添加了事务,两个事务都会进行
purchase()方法开始时,会开启其自己的事务,而checkout()的事务就会挂起
等purchase()方法的事务结束后,才会继续checkout()的事务
这样就会导致如果purchase()方法如果出现异常只会回滚到当前purchase()方法未执行以前,而不是整个checkout()未执行以前。
|----形象一点就是,purchase()购买第一本书书时没有发生异常,但购买第二本书时发生异常,则会回滚到第一本书购买完成之后,即第一本书是真正的购买成功。
3)、支持的传播行为有:
来自尚硅谷3、事务的隔离级别
1)、脏读
对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段。之后, 若T2回滚,T1读取的内容就是临时且无效的。
2)、不可重复读
对于两个事务T1,T2,T1读取了一个字段,然后T2 更新了该字段。之后,T1再次读取同一个字段,值就不同了。
3)、幻读
对于两个事务T1,T2,T1从一个表中读取了一个字段, 然后T2在该表中插入了一些新的行。之后,如果T1再次读取同一个表, 就会多出几行.
4)、@Transactional
用 @Transactional 注解声明式地管理事务时可以在 @Transactional 的 isolation 属性中设置隔离级别.
@Transactional(isolation=Isolation.READ_COMMITED )
来自尚硅谷
最常用的就是READ_COMMITED 读已提交
注:事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持.
Oracle 支持的 2 种事务隔离级别:READ_COMMITED , SERIALIZABLE
Mysql 支持 4 中事务隔离级别.
5)、超时和只读属性可以在 @Transactional 注解中定义.超时属性以秒为单位来计算.
@Transactional(propagation=Propagation.REQUIRES_NEW,
isolation=Isolation.READ_COMMITTED,readOnly=false,timeout=3)
public void purchase(String username, String isbn) {}
4、在xml文件里配置事务的属性
<!-- 配置事务属性 -->
<tx:advice transaction-manager="transactionManager" id="txadvice">
<tx:attributes>
<tx:method name="purchase" propagation="REQUIRED"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 配置切入点,需将所有要添加切入点的类放在统一包下,以便于写路径 ,一般在service包下-->
<aop:pointcut expression="execution( * 包名.service.*.*(..))" id="txPointCut"/>
<!-- 将配置的事务与切入点关联起来 -->
<aop:advisor advice-ref="txadvice" pointcut-ref="txPointCut"/>
</aop:config>
网友评论