在Spring AOP切面中启用新事务

39 篇文章 534 订阅

在工作中有一个在切面中需要记录一下操作日志的需求,而且要求这些操作日志要存入数据库,并且无论业务层有什么异常,日志照常记录,那就不能沿用业务层的事务,而是需要新启一个事务了。
sping的声明式事务就是靠AOP来实现的,一般事务都在业务层中启用,那如果要在AOP的逻辑中启用一个新的事务要怎么做呢?比如下面的例子:

//定义一个切点,这里指com.lidehang.remote包下所有的类的方法
@Pointcut("execution(public * com.lidehang.remote..*.*(..))")
 public void remote(){}

//切点指定的方法执行完返回后调用
@AfterReturning(returning = "ret", pointcut = "remote()")
 public void doAfterReturning(JoinPoint joinPoint,Object ret) throws Throwable {
 	//一些切面逻辑,包含了数据库操作,为了即便业务层的原事务回滚也不会影响切面中的数据库操作,需要启用新的事务
...
 }

经过我的测试,通过在doAfterReturning方法上加上注解@Transactional,并指定传播行为是REQUIRES_NEW依然不行。因为@Transactional也是声明式事务,本身就是AOP实现的,在AOP的代码中使用不起作用。所以就只能使用spring的编程式事务了,需要引入TransactionTemplate。如下:

@Autowired
private TransactionTemplate transactionTemplate;

@AfterReturning(returning = "ret", pointcut = "remote()")
 public void doAfterReturning(JoinPoint joinPoint,Object ret) throws Throwable {
//声明式事务在切面中不起作用,需使用编程式事务
//设置传播行为:总是新启一个事务,如果存在原事务,就挂起原事务
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionTemplate.execute(new TransactionCallback<T>() {
@Override
		public T doInTransaction(TransactionStatus arg0) {
 			//一些切面逻辑,包含了数据库操作
...
}
});
 }

通过以上的步骤,切面里的逻辑会在新事务中执行,执行完就会提交,和业务层中的原事务无关,即便执行完切面逻辑后继续执行业务代码的过程中出现异常,业务层中的数据库操作因为有原事务而回滚,但切面中的数据库操作不会回滚,因为这是个新的事务!

  • 692
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Java Spring AOP (Aspect Oriented Programming) 是一种编程范式,它通过将应用的业务逻辑和系统关注点(如日志、事务管理等)分离,提高了代码的可维护性和复用性。下面是一个简单的Spring AOP切面(Aspect)的Demo示例: 首先,你需要在Spring配置文件启用AOP支持,并定义一个切面(Aspect): ```xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aspectj="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 启用AOP --> <aop:aspectj-autoproxy/> <!-- 定义切面 --> <bean id="myAspect" class="com.example.MyAspect"> <!-- 配置通知(advice) --> <property name="beforeAdvice" ref="beforeAdvice"/> </bean> <!-- 定义通知 --> <bean id="beforeAdvice" class="com.example.BeforeAdvice"/> </beans> ``` 然后,创建一个`MyAspect`切面类,通常包含通知(advice),例如前置通知(BeforeAdvice): ```java import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class MyAspect { @Before("execution(* com.example.service.*.*(..))") public void beforeAdvice(JoinPoint joinPoint) { // 在方法执行前添加的操作,如日志记录 System.out.println("Method " + joinPoint.getSignature() + " is about to execute."); } } ``` 在这个例子,`@Before`注解定义了一个前置通知,它将在`com.example.service`包下的所有方法执行前执行。 接下来,创建`BeforeAdvice`类,这是一个具体的通知实现: ```java public class BeforeAdvice { // 可能包含一些自定义逻辑,比如参数检查或资源获取 } ``` 相关问题--: 1. Spring AOP的通知有哪些类型? 2. `@Aspect`注解在Spring AOP的作用是什么? 3. 如何在Spring配置切点(execution表达式)?
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值