这是我参与「第四届青训营 」笔记创作活动的第2天
天地不仁,以万物为刍狗
@TOC
前言
@Transactional(propagation = Propagation.REQUIRED,noRollbackForClassName = {"ArithmeticException"}) 事务
一、@Transactional
事务的传播特性: 如果多个事务叠加在一起,XXX事务说话算数 XXX事务的什么特性会决定其名下的其他事务的互斥的特性
@Transactional(propagation = Propagation.REQUIRED,//事务的传播特性
noRollbackForClassName = {"ArithmeticException"},//指定发生什么异常不回滚,使用的是异常的名称
noRollbackFor = ArithmeticException.class,//指定发生什么异常不回滚,使用的异常的类型
rollbackForClassName = "",//指定发生什么异常必须回滚
rollbackFor = ArithmeticException.class,//指定发生什么异常必须回滚
timeout = -1,//连接超市设置,默认值是-1,代表永不超市
readOnly = false,//默认是false,如果是查询操作,必须设置为true(默认是允许增删改操作,但如果是查询操作,必须设置为ture)
isolation = Isolation.DEFAULT//使用数据库自己的隔离级别(mysql数据库的隔离级别是可重复读REPEATABLE READ,oracle数据库的隔离级别是读已提交READ COMMITED)
)
二、Spring的两种事务处理方式
2.1注解式的事务
1.需要在相应xml文件中添加:
<!-- 事务处理-->
<!-- 1.添加事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 因为事务必须关联数据库处理,所以要配置数据源-->
<property name="dataSource" ref="dataSource"/> <!-- 该处dataSource来自第一行import-->
</bean>
<!-- 2.添加事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
2.需要在类的头上添加注解及其参数
@Transactional(propagation = Propagation.REQUIRED,//事务的传播特性
noRollbackForClassName = {"ArithmeticException"},//指定发生什么异常不回滚,使用的是异常的名称
noRollbackFor = ArithmeticException.class,//指定发生什么异常不回滚,使用的异常的类型
rollbackForClassName = "",//指定发生什么异常必须回滚
rollbackFor = ArithmeticException.class,//指定发生什么异常必须回滚
timeout = -1,//连接超市设置,默认值是-1,代表永不超市
readOnly = false,//默认是false,如果是查询操作,必须设置为true(默认是允许增删改操作,但如果是查询操作,必须设置为ture)
isolation = Isolation.DEFAULT//使用数据库自己的隔离级别(mysql数据库的隔离级别是可重复读REPEATABLE READ,oracle数据库的隔离级别是读已提交READ COMMITED)
)
ps: 使用@Transactional注解完成事务控制,此注解可添加到类上,则对类中所有方法执行事务的设定 此注解可添加到方法上,只是对此方法执行事务的处理(当方法数量达到一定程度时,此种方法会及其繁琐)
2.2声明式事务(必须掌握)
在配置文件中添加一次,整个项目遵循事务的设定 Spring非常有名的事务处理方式,声明式事务 要求项目中的方法命名有规范 · 完成增加操作 须得包含以下字眼:add/save/insert/set · 更新操作 包含:update change modify · 删除操作 包含:delete drop remove clear · 查询操作 包含:select find search get
配置事务切面时可以使用通配符 * 来匹配所有方法
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 此配置文件与applicationContext_service.xml的功能一样,只是事务配置不同-->
<!-- 导入applicationContext_mapper.xml-->
<import resource="applicationContext_mapper.xml"/>
<!-- 添加包扫描-->
<context:component-scan base-package="org.example.service.impl"/>
<!-- 添加事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 添加注解事务-->
<tx:annotation-driven order="100"></tx:annotation-driven>
<!-- 配置事务切面-->
<tx:advice id="myadvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*select*" read-only="true"/>
<tx:method name="*find*" read-only="true"/>
<tx:method name="*search*" read-only="true"/>
<tx:method name="*get*" read-only="true"/>
<tx:method name="*insert*" propagation="REQUIRED" no-rollback-for="ArithmeticException"/>
<tx:method name="*add*" propagation="REQUIRED"/>
<tx:method name="*save*" propagation="REQUIRED" no-rollback-for="ArithmeticException"/>
<tx:method name="*set*" propagation="REQUIRED"/>
<tx:method name="*update*" propagation="REQUIRED"/>
<tx:method name="*change*" propagation="REQUIRED"/>
<tx:method name="*modify*" propagation="REQUIRED"/>
<tx:method name="*delete*" propagation="REQUIRED"/>
<tx:method name="*remove*" propagation="REQUIRED"/>
<tx:method name="*drop*" propagation="REQUIRED"/>
<tx:method name="*clear*" propagation="REQUIRED"/>
<tx:method name="***" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!-- 绑定切面和切入点-->
<aop:config>
<aop:pointcut id="mycut" expression="execution(* org.example.service.impl.*.*(..))"/>
<aop:advisor order="1" advice-ref="myadvice" pointcut-ref="mycut"/>
</aop:config>
</beans>
三、为什么添加事务管理器
JDBC: Connection con.commit() con.rollback() MyBatis: SqlSession sqlSession.commit() sqlSession.rollback() Hibernate: Session session.commit() session.rollback()
不同的技术,底层来完成提交和回滚的对象是不一样的 使用事务管理器就可以知道所使用框架及其技术,从而使用对应的对象来进行提交和回滚
事务管理器用来生成相应技术的连接+执行语句的对象。 若使用MyBatis框架,必须使用DataSourceTransactionManager类完成处理
<!-- 1.添加事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 因为事务必须关联数据库处理,所以要配置数据源-->
<property name="dataSource" ref="dataSource"/> <!-- 该处dataSource来自第一行import-->
</bean>
四、Spring事务的传播特性
多个事务之间的合并,互斥,独自运行等都可以通过设置事务的传播特性来解决。 ps:如果是单个事务则看不出效果
- 常用
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。(必被包含事务(增删改必用))
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。 (自己新开事务,不管之前是否有事务)
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。 (支持事务,如果新加入的方法有事务,则支持事务,如果没有,不单开事务)
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。 (不能运行中事务中,如果包在事务中,抛异常)
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。(不支持事务,运行在非事务的环境)
- 不常用:
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。 (必须包在事务中,没有事务则抛异常)
PROPAGATION_NESTED:支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。 (嵌套事务)
总结
项目中的所有事务必须添加到业务逻辑层上(Service) 业务逻辑层才是整个项目的核心处理,才是更复杂的处理
Hibernate和MyBatis 今日事,今日毕