我们在实现业务逻辑时,经常会有这种需求:

1、在当前事务A中开启新事务B,事务B中发生异常不可以回滚A,事务B成功执行后返回事务B的返回值;

2、在当前事务A中开启新事务B,事务B中发生异常要求回滚A,事务B成功执行后返回事务B的返回值;

3、在当前事务A中开启新事务B,事务B中发生异常不可以回滚A,事务B成功执行后不需要返回;

4、在当前事务A中开启新事务B,事务B中发生异常要求回滚A,事务B成功执行后不需要返回;

5、注册后置事务B,即当前事务A成功提交后才会执行事务B,事务B异常的话不抛出,只打印异常日志;

6、注册后置事务B,即当前事务A异常时执行事务B,事务B异常的话不抛出,只打印异常日志;

一、配置事务模版

<!--事务模版
1.标志REQUIRES_NEW会新开启事务,外层事务异常外部事务会会馆,不会回滚内部事务的提交
2.标志REQUIRES_NEW的内部事务的异常,内部事务会回滚,外部事务也会回滚-->
<bean id="transactionTemplateNew" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW"/>
</bean>

二、定义接口

/**
* @author zhaojiatao
* @date 2019-07-14
*/
public interface ICommonTransactionService { /**
* 开启一个新事务来执行函数,有返回值;与外部事务互相隔离,发生异常只回滚本事务,不会互相影响
* @param action
* @param <T>
* @urn
*/
<T> T newTransactionExecuteAndReturnWithOutThrowable(Supplier<T> action); /**
* 开启一个新事务来执行函数,有返回值;内部事务发生异常时会向外抛出异常,内部事务和外部事务均回滚
* @param action
* @param <T>
* @urn
*/
<T> T newTransactionExecuteAndReturnThrowable(Supplier<T> action) throws Exception; /**
* 开启一个新事务来执行函数,无返回值;与外部事务互相隔离,发生异常只回滚本事务,不会互相影响
* @param f
*/
void newTransactionRunVoidWithOutThrowable(Runnable f); /**
* 开启一个新事务来执行函数,无返回值;内部事务发生异常时会向外抛出异常,内部事务和外部事务均回滚
* @param f
*/
void newTransactionRunVoidThrowable(Runnable f) throws Exception; /**
* 如果当前存在事务,则等当前事务提交后,回头来开启一个新事务执行,如果内部捕捉异常,不往外抛出;如果外部事务提交前外部事物异常,则此函数不会被执行
* https://docs.spring.io/spring/docs/1.2.7/javadoc-api/org/springframework/transaction/support/TransactionSynchronizationAdapter.html
* @param f
*/
void registerTransactionAfterCommitNoThrowable(Runnable f); /**
* 当前事务提交或者回滚后执行 Invoked after transaction commit/rollback
* https://docs.spring.io/spring/docs/1.2.7/javadoc-api/org/springframework/transaction/support/TransactionSynchronizationAdapter.html
* @param f
*/
void registerTransactionAfterRollBackNoThrowable(Runnable f); }

三、接口实现

/**
* @author zhaojiatao
* @date 2019-07-14
*/ @Slf4j
@Service("commonTransactionService")
public class CommonTransactionServiceImpl implements ICommonTransactionService { @Autowired
@Qualifier("transactionTemplateNew")
TransactionTemplate transactionTemplateNew; @Override
public <T> T newTransactionExecuteAndReturnWithOutThrowable(Supplier<T> action) {
//执行带有返回值<Object>的事务管理
return transactionTemplateNew.execute(transactionStatus-> {
try {
return action.get();
} catch (Exception e) {
log.error("newTransactionExecuteAndReturnNoThrowable发生异常",e);
//回滚
transactionStatus.setRollbackOnly();
return null;
}
});
} @Override
public <T> T newTransactionExecuteAndReturnThrowable(Supplier<T> action) {
//执行带有返回值<Object>的事务管理
return transactionTemplateNew.execute(transactionStatus-> {
try {
return action.get();
} catch (Exception e) {
log.error("newTransactionExecuteAndReturnNoThrowable发生异常",e);
//回滚
transactionStatus.setRollbackOnly();
throw e;
}
});
} @Override
public void newTransactionRunVoidWithOutThrowable(Runnable f) {
//执行无返回值的事务管理
transactionTemplateNew.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
//业务代码
f.run();
} catch (Exception e){
log.error("newTransactionRunVoidNoThrowable发生异常",e);
//回滚
transactionStatus.setRollbackOnly();
} }
}); } @Override
public void newTransactionRunVoidThrowable(Runnable f) {
//执行无返回值的事务管理
transactionTemplateNew.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
//业务代码
f.run();
} catch (Exception e){
log.error("newTransactionRunVoidNoThrowable发生异常",e);
//回滚
transactionStatus.setRollbackOnly();
throw e;
} }
}); } @Override
public void registerTransactionAfterCommitNoThrowable(Runnable f) {
try{
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
f.run();
}
});
} else {
f.run();
}
}catch (Exception e){
log.error("执行后置事务发生异常",e);
} } @Override
public void registerTransactionAfterRollBackNoThrowable(Runnable f) {
try{
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCompletion(int status) {
log.error("执行事务回滚后置事务,status={}",status);
f.run();
}
});
} else {
f.run();
}
}catch (Exception e){
log.error("当前事务回滚后置事务发生异常",e);
}
} }

四、调用

@Test
@Transactional(rollbackFor = Exception.class)
public void commonTransactionServiceTest() throws Exception { //1、newTransactionExecute 开启新事务 有返回值
String result=commonTransactionService.newTransactionExecuteAndReturnWithOutThrowable(
()->{
QueryObj queryObj = new QueryObj();
queryObj.setQuerydo(new OrderDO());
queryObj.addQueryParam(new QueryParam("id = #{id}", "347"));
OrderDO orderDO = orderDAO.querySingle(queryObj);
return JSON.toJSONString(orderDO);
}
); log.info(result); //2、newTransactionRun 开启新事务 无返回值
commonTransactionService.newTransactionRunVoidWithOutThrowable(
()->{
QueryObj queryObj = new QueryObj();
queryObj.setQuerydo(new OrderDO());
queryObj.addQueryParam(new QueryParam("id = #{id}", "347"));
OrderDO orderDO = orderDAO.querySingle(queryObj);
log.info(JSON.toJSONString(orderDO));
}
); int[] ids=new int[]{0}; //3、在新事务中insert数据
commonTransactionService.newTransactionRunVoidWithOutThrowable(
()->{
OrderDO orderDO=new OrderDO();
orderDO.setId(350L);
orderDO.setOrderCode("350350");
orderDO.setCustomerId(81L);
orderDO.setBusinessModel(LoanOrderBusinessModelEnum.SELF_SECOND_CAR_ICBC_DIRECT.getCode());
ids[0]=orderDAO.create(orderDO);
log.info( ids[0]+"");
//只回滚内部事务,不回滚外部事务
System.out.println(1/0);
}
); //4、在外部事务提交后执行的后置新事务insert数据
commonTransactionService.registerTransactionAfterCommitNoThrowable(
()->{
OrderDO orderDO=new OrderDO();
orderDO.setId(351L);
orderDO.setOrderCode("351351");
orderDO.setCustomerId(81L);
orderDO.setBusinessModel(LoanOrderBusinessModelEnum.SELF_SECOND_CAR_ICBC_DIRECT.getCode());
ids[0]=orderDAO.create(orderDO);
log.info( ids[0]+"");
} ); //5、在外部事务中insert数据
if(true){
OrderDO orderDO=new OrderDO();
orderDO.setId(352L);
orderDO.setOrderCode("352352");
orderDO.setCustomerId(81L);
orderDO.setBusinessModel(LoanOrderBusinessModelEnum.SELF_SECOND_CAR_ICBC_DIRECT.getCode());
ids[0]=orderDAO.create(orderDO);
log.info( ids[0]+"");
} //6、在新事务中插入数据并异常
commonTransactionService.newTransactionRunVoidThrowable(
()->{
OrderDO orderDO=new OrderDO();
orderDO.setId(353L);
orderDO.setOrderCode("353353");
orderDO.setCustomerId(81L);
orderDO.setBusinessModel(LoanOrderBusinessModelEnum.SELF_SECOND_CAR_ICBC_DIRECT.getCode());
ids[0]=orderDAO.create(orderDO);
log.info( ids[0]+"");
System.out.println(1/0);
}
); //注意验证这个异常是无法回滚commonTransactionService.newTransactionRun的
//注意验证这个异常会导致commonTransactionService.registerTransactionAfterCommitNoThrowable无法执行,因为事务没有提交
// System.out.println(1/0);
System.out.println(1); }

使用lambda表达式优雅你的事务代码的更多相关文章

  1. Lambda表达式, 可以让我们的代码更优雅.

    在C#中, 适当地使用Lambda表达式, 可以让我们的代码更优雅. 通过lambda表达式, 我们可以很方便地创建一个delegate: 下面两个语句是等价的 Code highlighting p ...

  2. Java 8 Lambda表达式,让你的代码更简洁

    Lambda表达式是Java 8一个非常重要的新特性.它像方法一样,利用很简单的语法来定义参数列表和方法体.目前Lambda表达式已经成为高级编程语言的标配,像Python,Swift等都已经支持La ...

  3. golang如何优雅的编写事务代码

    目录 前言 需求 烂代码示例 重构套路 一.提前返回去除if嵌套 二.goto+label提取重复代码 三.封装try-catch统一捕获panic 前言 新手程序员概有如下特点 if嵌套特别多.重复 ...

  4. 委托学习笔记后续:泛型委托及委托中所涉及到匿名方法、Lambda表达式

    引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到和委托相关的匿名方法.Lambda表达式及泛型委托记录 ...

  5. Lambda表达式的前世今生

    Lambda 表达式 早在 C# 1.0 时,C#中就引入了委托(delegate)类型的概念.通过使用这个类型,我们可以将函数作为参数进行传递.在某种意义上,委托可理解为一种托管的强类型的函数指针. ...

  6. 掌握 Java 8 Lambda 表达式

    Lambda 表达式 是 Java8 中最重要的功能之一.使用 Lambda 表达式 可以替代只有一个函数的接口实现,告别匿名内部类,代码看起来更简洁易懂.Lambda 表达式 同时还提升了对 集合 ...

  7. 泛型委托及委托中所涉及到匿名方法、Lambda表达式

    泛型委托及委托中所涉及到匿名方法.Lambda表达式 引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到 ...

  8. C++雾中风景8:Lambda表达式

    上一篇C++的博客是Long Long ago了,前文讲到在看Lambda表达式的内容.笔者首次接触Lambda表达式应该是学习Python语言的时候,当时也不太明白这种表达方式的精髓,后续接触了Sc ...

  9. 【原创】从策略模式闲扯到lambda表达式

    引言 策略模式,讲这个模式的文章很多,但都缺乏一个循序渐进的过程.讲lambda表达式的文章也很多,但基本都是堆砌一堆的概念,很少带有自己的见解.博主一时兴起,想写一篇这二者的文章.需要说明的是,在看 ...

随机推荐

  1. 新iPhone泄密12人被捕,苹果这是下狠手的节奏

    一直以来,苹果在保密这件事儿上就秉持着强硬态度.还记得当年乔老爷子在的时候,苹果的保密工作在科技行业算得上是首屈一指.每款iPhone及其他新品在正式发布前,几乎不会被曝出什么消息.而这,或许也是&q ...

  2. 自己组装一台1U服务器

    视频资料链接 自己组装一台1U服务器 执行思路: 1.评估访问了,根据需求确定服务器要求 2.根据要求选择硬件:冗余.稳定等 3.搜索主流服务器参数进行对比,及对比价格 4.咨询IDC机房价格 DIY ...

  3. E - Apple Tree POJ - 2486

    E - Apple Tree POJ - 2486 Wshxzt is a lovely girl. She likes apple very much. One day HX takes her t ...

  4. 数据类型操作简单对比(R和Python)

    一.R方面 R中类型:向量(vector).数据框.矩阵.列表 数据处理转换时:数值型num.因子(factor).字符型等等 1)matrix feature:1.二维数组2.每个元素必须有相同的数 ...

  5. mac下使用opencv编译安装新模块contrib

    opencv-4.0.1 opencv_contrib-4.0.1 提供ippicv下载链接: https://pan.baidu.com/s/1OIJRUqPqAtpMetku8qX36w cont ...

  6. JDBC-使用Java连接数据库-基础篇

    这是小主第一次写Java连接数据库博客,初学Java之时,Java连接数据库是我最头疼的,不过经过一个月的学习,也差不多略有收获,所以给大家分享一下. Java连接数据库大约需要五大步骤: 创建数据库 ...

  7. CSS3新属性:在网站中使用访客电脑里没有安装的字体

    CSS的font-family属性使网页可以使用客户电脑里的字体,从而得到多姿多彩的WEB页面,但当客户端没有你想要使用的字体时怎么办呢?我们总不能让每个访问者都去安装一个字体吧?事实上,这是可以的! ...

  8. P3252 [JLOI2012]树

    题目描述 在这个问题中,给定一个值S和一棵树.在树的每个节点有一个正整数,问有多少条路径的节点总和达到S.路径中节点的深度必须是升序的.假设节点1是根节点,根的深度是0,它的儿子节点的深度为1.路径不 ...

  9. PAT Basic 1075 链表元素分类(25) [链表]

    题目 给定⼀个单链表,请编写程序将链表元素进⾏分类排列,使得所有负值元素都排在⾮负值元素的前⾯,⽽[0, K]区间内的元素都排在⼤于K的元素前⾯.但每⼀类内部元素的顺序是不能改变的.例如:给定链表为 ...

  10. c语言中用简单方法对多维数组进行初始化

    例:int array[4][3] = {1,2,3,4,5,6,7,8,9,10,11,12}; 说明:a.由4*3可知,本二维数组包含12个元素,因此初始化时array[0][0] = 1 ,ar ...