参考: 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使用
@Autowired
private TransactionTemplate transactionTemplate;
@Override
public Integer insert() {
Integer i = transactionTemplate.execute(new TransactionCallback<Integer>() {
@Override
public 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表达式优化下
@Override
public Integer insert() {
return transactionTemplate.execute(t -> {
try {
return userMapper.insert();
} catch (Exception e) {
t.setRollbackOnly();
}
return 0;
});
}
------------------
@Override
public Integer insert() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
userMapper.insert();
// 除0错误用以演示
System.out.println(1 / 0);
} catch (Exception e) {
transactionStatus.setRollbackOnly();
}
}
});
return null;
}
PlatformTransactionManager使用
@Autowired
private PlatformTransactionManager transactionManager;
@Override
public 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;
}
}
@FunctionalInterface
public interface TransactionCallable<V> {
V call();
}
@FunctionalInterface
public interface TransactionRunnable {
void run();
}
}
使用
getTransactionTemplate().execute(() -> {
b2bStockOutOrderDetailService.batchModify(outOrderDetails);
stockOccupancyService.batchCreate(occupancies);
updateOrder.setAuditedTime(LocalDateTime.now());
update(updateOrder);
});
---------------
int count = getTransactionTemplate().executeWithResult(() -> insertBatch(collection));
事务实测
同一个类中两个方法的调用
情况一: 实测安全!
@Transactional
public void method1() {
method2();
}
@Transactional
public void method2() {
}
情况二: 实测安全!
@Transactional
public void method1() {
method2();
}
private void method2() {
}
情况三: 实测安全!
@Transactional
public void method1() {
method2();
}
public void method2() {
}
情况四: 不安全!
public void method1() {
method2();
}
@Transactional
public void method2() {
}