北京网站整站优化,广州知名网站推广,安宁网站建设熊掌号,国外网站用什么dns好Spring 事务 文章目录 Spring 事务1. 简介2. Spring事务管理器3. 基本使用4. 属性剖析5. 声明式事务问题场景5.1 事务不生效5.2 事务不回滚5.3 大事务问题 6. 编程式事务 1. 简介
编程式事务#xff1a;指手动编写程序来管理事务#xff0c;即通过编写代码的方式直接控制事务…Spring 事务 文章目录 Spring 事务1. 简介2. Spring事务管理器3. 基本使用4. 属性剖析5. 声明式事务问题场景5.1 事务不生效5.2 事务不回滚5.3 大事务问题 6. 编程式事务 1. 简介
编程式事务指手动编写程序来管理事务即通过编写代码的方式直接控制事务的提交和回滚。主要优点是灵活性高可以按照自己的需求来控制事务的粒度、模式等等。但是一般编写大量的事务控制代码容易出现问题对代码的可读性和可维护性有一定影响。声明式事务指使用注解或 XML 配置的方式来控制事务的提交和回滚。
下面除了第6节编程式事务其他都是指声明式事务。
2. Spring事务管理器
Spring声明式事务对应依赖
spring-tx 包含声明式事务实现的基本规范事务管理器规范接口和事务增强等等spring-jdbc 包含 DataSource 方式事务管理器实现类 DataSourceTransactionManagerspring-orm 包含其他持久层框架的事务管理器实现类例如Hibernate/Jpa 等
Spring声明式事务对应事务管理器接口 较常使用的事务管理器是 org.springframework.jdbc.datasource.DataSourceTransactionManager 将来整合 JDBC方式、JdbcTemplate方式、Mybatis方式的事务实现
DataSourceTransactionManager类中的主要方法
doBegin() 开启事务doSuspend() 挂起事务doResume() 恢复挂起的事务doCommit()提交事务doRollback() 回滚事务
3. 基本使用
添加依赖
!-- 声明式事务依赖--
dependencygroupIdorg.springframework/groupIdartifactIdspring-tx/artifactIdversion6.0.6/version
/dependency开启事务注解EnableTransactionManagement添加事务管理器到 IoC 容器中
/**
* 装配事务管理实现对象
* param dataSource
* return
*/
Bean
public TransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);
}在类上或方法上使用 Transactional 在类上使用则会影响到类中的每个方法同时类级别标记的 Transactional 注解中设置的事务属性也会延续影响到方法执行时的事务属性。除非在方法上又设置了 Transactional 注解。对一个方法来说离它最近的 Transactional 注解中的事务属性设置生效。
4. 属性剖析 timeout 默认 -1 表示永不超时超时则会事务回滚 rollbackFor 表示遇到属于该异常的类进行事务回滚默认 遇到 RuntimeException 及其子类和 Error 及其子类时才会回滚 建议设置 rollbackFor Exception.class 或者 Throwable.class 表示 Exception及其子类 或 Throwable 的异常都会触发回滚同时不影响Error的回滚 propagation 事务的传播行为默认 Propagation.REQUIRED 一共有七种一般只使用前两种 事务传播行为类型说明REQUIRED如果当前没有事务就新建一个事务如果已经存在一个事务中加入到这个事务中。这是最常见也是默认的选择。REQUIRES_NEW新建事务如果当前存在事务把当前事务挂起。SUPPORTS支持当前事务如果当前没有事务就以非事务方式执行。MANDATORY使用当前的事务如果当前没有事务就抛出异常。NOT_SUPPORTED以非事务方式执行操作如果当前存在事务就把当前事务挂起。NEVER以非事务方式执行如果当前存在事务则抛出异常。NESTED如果当前存在事务则在嵌套事务内执行。如果当前没有事务则执行与 REQUIRED 类似的操作 isolation 用于设置事务的隔离级别 Isolation.DEFAULT 一般不修改 readOnly 默认 false设置为 true 则只能做读操作用于数据库针对查询优化一般不使用
5. 声明式事务问题场景
5.1 事务不生效
未开启事务 未使用开启事务注解 EnableTransactionManagement未被Spring管理 被代理类需被Spring管理才能使用 AOP 功能访问权限问题 只有 public 权限修饰的方法才支持声明式事务方法用 final 或 static 修饰 spring 事务底层用了 jdk 动态代理或者 cglib 生成代理类这两个关键字将导致重写代理类的该方法多线程调用 不同线程获取到的数据库连接不一样从而必然是两个不同的事务表不支持事务 数据库表引擎是 myisam 或其他不支持事务的引擎方法内调用另一个同类方法如下add方法中调用了事务方法 updateStatus()
Service
public class UserService {Autowiredprivate UserMapper userMapper;public void add(UserModel userModel) {userMapper.insertUser(userModel);updateStatus(userModel);}Transactionalpublic void updateStatus(UserModel userModel) {doSameThing();}
}updateStatus() 方法拥有事务的能力是因为 spring aop 生成代理了对象但这种方式调用了 this 对象的方法所以 updateStatus 方法不会生成事务。
修改方式
新加一个 Service 将方法中挪到新的 Service 中通过新 Service 调用在该 Service 中注入自己再将调用改为 userService.updateStatus(userModel)使用 AopContext.currentProxy() 调用即改为 ((UserService)AopContext.currentProxy()).updateStatus(userModel) 推荐
Service
public class UserService {Autowiredprivate UserMapper userMapper;public void add(UserModel userModel) {userMapper.insertUser(userModel);((UserService)AopContext.currentProxy()).updateStatus(userModel)}Transactionalpublic void updateStatus(UserModel userModel) {doSameThing();}
}5.2 事务不回滚
错误的传播机制 设置了 propagation Propagation.NEVERtry…catch…吞了异常在 catch 中不抛出任何异常或抛了别的异常 spring 事务也不会回滚rollbackFor参数不合理 当发生了不属于 rollbackFor 定义的异常类及其子类的异常时事务将不会回滚
5.3 大事务问题
通常情况下我们会在方法上加 Transactional 注解添加事务功能比如
Transactional
public void add(UserModel userModel) throws Exception {query1();query2();query3();roleService.save(userModel);update(userModel);
}但 Transactional 注解如果被加到方法上有个缺点就是整个方法都包含在事务当中了。上面的这个例子中在 UserService 类中其实只有这两行才需要事务但是这种写法会导致所有的 query() 方法也被包含在同一个事务中。如果 query 方法非常多调用层级很深而且有部分查询方法比较耗时的话会造成整个事务非常耗时而从造成大事务问题。
6. 编程式事务
5中所提到的问题都是声明式事务的一般建议少使用声明式事务但并不是说一定不能用它如果项目中有些业务逻辑比较简单而且不经常变动使用 Transactional 注解开启事务也无妨因为它更简单开发效率更高但是千万要小心事务失效的问题。大项目更建议使用基于 TransactionTemplate 的编程式事务即通过手动编写代码实现的事务。
基于 TransactionTemplate 模板的编程式事务的使用
注入 TransactionTemplate 模板到 IoC 容器中
Bean
public DataSource dataSource() {DruidDataSource dataSource new DruidDataSource();dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setUrl(url);dataSource.setDriverClassName(driver);return dataSource;
}Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);
}Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager) {return new TransactionTemplate(platformTransactionManager);
}注入到需要使用的类中并使用如下两个方法之一 execute(TransactionCallbackT action)有返回值executeWithoutResult(ConsumerTransactionStatus action) 无返回值
Autowize
private TransactionTemplate transactionTemplate;Transactional
public void add(UserModel userModel) throws Exception {query1();query2();query3();transactionTemplate.executeWithoutResult((status - {try {roleService.save(userModel);update(userModel);} catch (Exception e) {status.setRollbackOnly();}}));
}异常调用 status.setRollbackOnly() 方法进行回滚