首页 > 其他分享 >事务 还有这些用法,之前都不知道

事务 还有这些用法,之前都不知道

时间:2022-11-12 18:32:28浏览次数:47  
标签:status 事务 Version void 之前 用法 version public

#序 transationTemplate.execute 的写法 第一次 碰到,我之前是 controller -> biz -> service -> mapper 然后用 @Transation 注解搞定事务,至于 同一个类的 方法之间调用,在biz 层就规避了

不懂就问

首先 同一个类中 方法调用因为没有 走 aop 所以 事务不生效,这个应该没毛病吧

问了人家,人家说 能解决 同一类中的 不同方法调用的 事务问题,我不太信。。验证下,如果能行,我以后加入

Spring事务失效的场景

  1. 非public修饰
  2. final修饰也会失效, 动态代理需要重写方法才能生效事务, final修饰则无法重写
  3. static修饰也会失效
  4. 吞了异常, catch住没有抛给spring
  5. 抛了错误的异常, catch住手动抛Exception则不会回滚, 因为spirng事务只会处理RuntimeException和Error
  6. 同一个类中的方法进行互相调用

准备代码

public void a() {
// transactionTemplate.execute(transactionStatus -> {
// b();
// c();
// return true;
// });
Version version = new Version();
version.setVersionName("test00");
version.setProjectId(1L);
versionService.save(version);
b();
c();
}

@Transactional(rollbackFor = Exception.class)
public void b() {
Version version = new Version();
version.setVersionName("test01");
version.setProjectId(1L);
versionService.save(version);
}

@Transactional(rollbackFor = Exception.class)
public void c() {
Version version = new Version();
version.setVersionName("test02");
version.setProjectId(1L);
versionService.save(version);
int i = 1 / 0;
}
复制代码

第一次实验 嗯嗯 确实数据库插入了3条,事务没有生效嘛

那按照大哥的说法 如果用他那种写法 就能保证事务了?

改下代码 试验下

public void a() {
transactionTemplate.execute(transactionStatus -> {
Version version = new Version();
version.setVersionName("test00");
version.setProjectId(1L);
versionService.save(version);
b();
c();
return true;
});
}
复制代码

想想 如果是和大哥的想法一样 数据库应该是 没有插入,好 执行下

嗯嗯 是的 确实没有数据库插入,但是为什么呢? 嗯嗯 大哥说得对

猜想

我第一想法 就是 它这么写 就相当于 我们之前biz 层 对 service 层的调用,自然而言 就保证了事务,毕竟实现了 不同类的调用嘛

验证下

@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
//判断transactionManager 是否为空 嗯嗯 没毛病
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
//
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
} else {
TransactionStatus status = this.transactionManager.getTransaction(this);

Object result;
try {
//执行 真正的代码
result = action.doInTransaction(status);
} catch (Error | RuntimeException var5) {
this.rollbackOnException(status, var5);
throw var5;
} catch (Throwable var6) {
this.rollbackOnException(status, var6);
throw new UndeclaredThrowableException(var6, "TransactionCallback threw undeclared checked exception");
}

this.transactionManager.commit(status);
return result;
}
}
复制代码

扩展

transactionTemplate.executeWithoutResult

在看 transactionTemplate 方法的时候 发现一个 executeWithoutResult 方法,嗯嗯 他是干什么的

看个名字应该是 没有返回值 嗯嗯

default void executeWithoutResult(Consumer<TransactionStatus> action) throws TransactionException {
this.execute((status) -> {
action.accept(status);
return null;
});
}
复制代码

这 。。。不就是套了一层,返回个null么

TransactionSynchronization

public class DoTransactionCompletion implements TransactionSynchronization {

private Runnable runnable;

public DoTransactionCompletion(Runnable runnable){
this.runnable = runnable;
}

@Override public void afterCompletion(int status) {
if(status == TransactionSynchronization.STATUS_COMMITTED){
this.runnable.run();
}
}
}
复制代码
public class TransactionUtils {
public static void doAfterTransaction(DoTransactionCompletion doTransactionCompletion){
if(TransactionSynchronizationManager.isActualTransactionActive()){
TransactionSynchronizationManager.registerSynchronization(doTransactionCompletion);
}
}

public static void main(String[] args) {
TransactionUtils.doAfterTransaction(new DoTransactionCompletion(() -> {
//事务成功才做的操作
}));
}
}
复制代码

例子是 上面的main方法 实现的是 只有事务成功才会执行的操作

其余的可以自己进行判断status 进行控制

但是并不完美,这个写法 是有问题的

  1. 如果使用了 @Transaction REQUIRES_NEW的话 就会出现误完成
  2. 如果里面有多线程 ,也会导致 异常

优化

  1. 我后来把事务的new 单独进行判断,把REQUIRES_NEW的 忽略了
  2. 多线程 之前进行过封装,分为了 1 在同一个事务中,一起提交 2 可以局部提交,局部完成,我根据之前的封装,继续判断,如果是 1 状态,我会执行这个完成操作,否则进行剔除

标签:status,事务,Version,void,之前,用法,version,public
From: https://blog.51cto.com/u_15773567/5843222

相关文章

  • Mysql中REPLACE INTO用法,判断数据是否存在,如果不存在,则插入,如果存在,则先删除此行数据,
    MySQLreplaceinto用法在向表中插入数据的时候,经常遇到这样的情况:1.首先判断数据是否存在;2.如果不存在,则插入;3.如果存在,则先删除后再插入新数据行。MySQL中实现这......
  • Vue中JSX的基本用法
    基本用法首先需要约定一下,使用JSX组件命名采用首字母大写的驼峰命名方式,样式可以少的可以直接基于vue-styled-components写在同一个文件中,复杂的建议放在单独的_Styles.js_......
  • 理解C++中 const 在指针中的用法
    intmain(){ int*constarray; constint*array; inta=10; array=&a;//Youcan'texchangearrayself,arrayjustisaintegar// *array=13;//Thisiserror......
  • eclipse打开时候,发现之前的一些工程项目不见了的解决方法
    emm,最近在学习安装STS,一个springboot的插件,谁觉这个行业变化之迅速,不多学点东西,怎么混得下去(委屈),本来eclipse好好的,所以就倒腾了一番。安装插件没有安装成功,倒是eclipse默......
  • c++ bit 库用法
    c++20加入了一个叫做bit的库,不如来看看里面有什么?bit_cast效果和reinterpret_cast类似,按二进制位取值,constexprfloatN=100;constexprintM=std::bit_cast<int>......
  • Spring 事务扩展及分布式事务可见性问题
      大家注意点,这个@Transactional其实在两种情况下会失效的:第一种就是:在方法内调用的时候,因为它没有经过Bean的代理,所以它没办法依赖Spring的AOP增强去进行事务的控......
  • 9、事务基本操作
    Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。Redis事务的主要作用就是串联多......
  • Redis事务三大特性
    单独的隔离操作事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断没有隔离级别的概念队列中的命令没有提交之前......
  • 【JS】8 种 ES6 中扩展运算符的用法
    扩展操作符 … 是ES6中引入的,将可迭代对象展开到其单独的元素中,所谓的可迭代对象就是任何能用forof循环进行遍历的对象,例如:数组、字符串、Map、Set、DOM节点等。1、拷贝......
  • 浅谈 c++20 ranges 的用法
    ranges库是c++20开始具有的语法,对应的头文件是#include<ranges>。为了防止CE我一般都这么写:#if__cplusplus>=202002L#include<ranges>usingnamespacestd::view......