参考: https://blog.csdn.net/u013517797/article/details/82926410
https://blog.csdn.net/lsziri/article/details/80656600
https://blog.csdn.net/tianyaleixiaowu/article/details/73123242
概念
事务: 如果一个包含多个步骤的业务操作被事务管理, 那么这些操作要么同时成功, 要么同时失败.
事务的四大特性
- 原子性: 是不可分隔的最小操作单位, 要么同时成功, 要么同时失败
- 持久性: 当事务提交或回滚后, 数据库会持久化的保存数据
- 隔离性: 多个事务之间会相互独立
- 一致性: 事务操作前后, 数据总量不变
事务的隔离级别
问题:
- 脏读: 一个事务读取到另一个事务没有提交的数据
- 不可重复读(虚读): 在同一个事务中, 两次读取到的数据不一样
- 幻读: 一个事务操作数据表中所有记录, 另一个事务添加了一条数据, 则第一个事务查询不到自己的修改
隔离级别:
1. read uncommitted:读未提交, 表示一个事务可以读取到另一个事务还未提交的数据
产生的问题:脏读、不可重复读、幻读
2. read committed:读已提交 (Oracle), 表示一个事务只能读取到另一个事务已经提交的数据
产生的问题:不可重复读、幻读
3. repeatable read:可重复读 (MySQL默认), 表示一个事务在整个过程中可以重复执行某个查询, 并且每次返回的记录都相同, 即使在多次查询之间有新增的数据满足该查询, 这些新增的记录也会被忽略
产生的问题:幻读
4. serializable:串行化, 所有的事务依次逐个执行.
可以解决所有的问题
- 注意:隔离级别从小到大安全性越来越高,但是效率越来越低
数据库查询隔离级别:
select @@tx_isolation;
数据库设置隔离级别:
set global transaction isolation level 级别字符串;
事务的传播行为
- REQUIRED :如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- SUPPORTS :如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- MANDATORY :如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- REQUIRES_NEW :创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- NOT_SUPPORTED :以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- NEVER :以非事务方式运行,如果当前存在事务,则抛出异常。
- NESTED :如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED 。

声明式事务
使用
在启动类开启@EnableTransactionManagement, 然后在类或方法上注解@Transactional即可
可以通过propagation以及isolation指定传播范围以及隔离级别
示例:
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
注解失效场景
- @Transactional 注解只能应用到 public 可见度的方法上, 其余失效
- 默认情况下,Spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚
补充:
unchecked Exception(非受检异常==运行期异常): NPE, ClassCastException, OutOfIndexException…
checked Exception(受检异常==编译器异常): IOException, TimeoutException, SQLException, ClassNotFoundException…
- 如果在同一个类中,一个非@Transaction的方法调用有@Transaction的方法不会生效,因为不走代理
- 不同服务,非@Transaction的方法调@Transaction的方法,里层有事务,但外层没有事务,也需注意
例:
1.throw new Exception—>不生效, 因为只回滚RuntimeException下面的异常, 其余类型需要手动配置@Transactional(rollbackFor = Exception.class)
2.Mysql—mylsam引擎不支持事务
3.注解修饰的方法try—catch后事务不生效, 无异常抛出
编程式事务
使用
transactionTemplate使用
@Autowiredprivate TransactionTemplate transactionTemplate;@Overridepublic Integer insert() {Integer i = transactionTemplate.execute(new TransactionCallback<Integer>() {@Overridepublic Integer doInTransaction(TransactionStatus transactionStatus) {try {Integer i = userMapper.insert();// 除0错误演示System.out.println(1 / 0);return i;} catch (Exception e) {transactionStatus.setRollbackOnly();return 0;}}});return i;}------------------上面例子用Lambda表达式优化下@Overridepublic Integer insert() {return transactionTemplate.execute(t -> {try {return userMapper.insert();} catch (Exception e) {t.setRollbackOnly();}return 0;});}------------------@Overridepublic Integer insert() {transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {try {userMapper.insert();// 除0错误用以演示System.out.println(1 / 0);} catch (Exception e) {transactionStatus.setRollbackOnly();}}});return null;}
PlatformTransactionManager使用
@Autowiredprivate PlatformTransactionManager transactionManager;@Overridepublic Integer insert() {DefaultTransactionDefinition definition = new DefaultTransactionDefinition();definition.setPropagationBehavior(Propagation.REQUIRED.value());definition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);definition.setTimeout(-1);TransactionStatus status = transactionManager.getTransaction(definition);try {Integer i = userMapper.insert();// 除0错误演示System.out.println(1 / 0);this.transactionManager.commit(status);return i;} catch (Exception var8) {this.transactionManager.rollback(status);throw var8;}}
参考学习
巨益事务类
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.greatonce.core.database;import org.springframework.transaction.PlatformTransactionManager;import org.springframework.transaction.TransactionStatus;import org.springframework.transaction.annotation.Isolation;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.support.DefaultTransactionDefinition;public class ManualTransactionTemplate {private PlatformTransactionManager transactionManager;public ManualTransactionTemplate(PlatformTransactionManager transactionManager) {this.transactionManager = transactionManager;}public void execute(ManualTransactionTemplate.TransactionRunnable runnable) {this.execute(Propagation.REQUIRED, Isolation.DEFAULT, -1, runnable);}public void execute(Propagation propagation, ManualTransactionTemplate.TransactionRunnable runnable) {this.execute(propagation, Isolation.DEFAULT, -1, runnable);}public void execute(Propagation propagation, Isolation isolation, int timeout, ManualTransactionTemplate.TransactionRunnable runnable) {DefaultTransactionDefinition definition = new DefaultTransactionDefinition();definition.setPropagationBehavior(propagation.value());definition.setIsolationLevel(isolation.value());definition.setTimeout(timeout);TransactionStatus status = this.transactionManager.getTransaction(definition);try {runnable.run();this.transactionManager.commit(status);} catch (Exception var8) {this.transactionManager.rollback(status);throw var8;}}public <T> T executeWithResult(ManualTransactionTemplate.TransactionCallable<T> callable) {return this.executeWithResult(Propagation.REQUIRED, Isolation.DEFAULT, -1, callable);}public <T> T executeWithResult(Propagation propagation, ManualTransactionTemplate.TransactionCallable<T> callable) {return this.executeWithResult(propagation, Isolation.DEFAULT, -1, callable);}public <T> T executeWithResult(Propagation propagation, Isolation isolation, int timeout, ManualTransactionTemplate.TransactionCallable<T> callable) {DefaultTransactionDefinition definition = new DefaultTransactionDefinition();definition.setPropagationBehavior(propagation.value());definition.setIsolationLevel(isolation.value());definition.setTimeout(timeout);TransactionStatus status = this.transactionManager.getTransaction(definition);try {T t = callable.call();this.transactionManager.commit(status);return t;} catch (Exception var8) {this.transactionManager.rollback(status);throw var8;}}@FunctionalInterfacepublic interface TransactionCallable<V> {V call();}@FunctionalInterfacepublic interface TransactionRunnable {void run();}}
使用
getTransactionTemplate().execute(() -> {b2bStockOutOrderDetailService.batchModify(outOrderDetails);stockOccupancyService.batchCreate(occupancies);updateOrder.setAuditedTime(LocalDateTime.now());update(updateOrder);});---------------int count = getTransactionTemplate().executeWithResult(() -> insertBatch(collection));
事务实测
同一个类中两个方法的调用
情况一: 实测安全!
@Transactionalpublic void method1() {method2();}@Transactionalpublic void method2() {}
情况二: 实测安全!
@Transactionalpublic void method1() {method2();}private void method2() {}
情况三: 实测安全!
@Transactionalpublic void method1() {method2();}public void method2() {}
情况四: 不安全!
public void method1() {method2();}@Transactionalpublic void method2() {}
