博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring事务--this调用事务生效方案
阅读量:4144 次
发布时间:2019-05-25

本文共 11304 字,大约阅读时间需要 37 分钟。

先结合源码部分看一下执行流程,然后说一下解决方案(本列使用cglib代理,jdk动态代理类似)

话不多说,先看一下代理拦截器方法:

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {			Object oldProxy = null;//这是咱们的目标类被各种切面封装后的代理对象			boolean setProxyContext = false;			Object target = null;			TargetSource targetSource = this.advised.getTargetSource();			try {				if (this.advised.exposeProxy) {//很重要,设置了暴露代理才会执行下一步内容					// Make invocation available if necessary.					oldProxy = AopContext.setCurrentProxy(proxy);//设置代理,并保存旧代理(1)					setProxyContext = true;				}				// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...				target = targetSource.getTarget();				Class
targetClass = (target != null ? target.getClass() : null); List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//拦截器链 Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {//没有拦截器 // We can skip creating a MethodInvocation: just invoke the target directly. // Note that the final invoker must be an InvokerInterceptor, so we know // it does nothing but a reflective operation on the target, and no hot // swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // We need to create a method invocation...//咱们事务执行这里 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy);//重新设置自己的代理类 } } }

进一步解析(1)处的内容:

public final class AopContext {	//使用threadlocal存储代理对象	private static final ThreadLocal currentProxy = new NamedThreadLocal<>("Current AOP proxy");	private AopContext() {	}//可以在任何地方通过threadlocal获取proxy对象	public static Object currentProxy() throws IllegalStateException {		Object proxy = currentProxy.get();		if (proxy == null) {			throw new IllegalStateException(					"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");		}		return proxy;	}//设置代理时,放到threadlocal中	@Nullable	static Object setCurrentProxy(@Nullable Object proxy) {		Object old = currentProxy.get();		if (proxy != null) {			currentProxy.set(proxy);		}		else {			currentProxy.remove();		}		return old;	}}

通过上面的源码分析,

1.开启暴露代理
2.我们可以直接通过AopContext 获取到Proxy对象,从而调用上面被各种切面织入的方法,进而实现代理.
理论不如实践,进行一下对比springboot环境:
开启暴露代理:@EnableAspectJAutoProxy(exposeProxy = true)

这一部分是事务不生效实例:

@Servicepublic class TranService{    @Autowired    private TranDao tranDao;    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)    public void add() {        User aaa = new User();        aaa.setAge(22);        aaa.setCtime(new Date());        aaa.setUserId(2);        aaa.setUserName("aaa");        tranDao.save(aaa);        try {            b();        }catch (Exception e){            e.printStackTrace();        }    }    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)    public void b() {        User aaa = new User();        aaa.setAge(33);        aaa.setCtime(new Date());        aaa.setUserId(3);        aaa.setUserName("bbb");        tranDao.save(aaa);        throw new RuntimeException("111");    }}

说明一下上面的代码:按spring事务的规则,调用add()方法士应该开启一个事务,然后b()也加了事务,推断出想在b()调用时,开启单独事务,那么期望结果是a()提交,b()回滚

2019-07-17 21:26:04.623 DEBUG 7976 --- [  restartedMain] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.example.demotran.tran.TranService.add]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Throwable2019-07-17 21:26:04.623 DEBUG 7976 --- [  restartedMain] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(76567159
)] for JPA transaction2019-07-17 21:26:04.623 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@255421fa]2019-07-17 21:26:04.639 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(76567159
)] for JPA transaction2019-07-17 21:26:04.639 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Participating in existing transactionHibernate: select user0_.user_id as user_id1_0_0_, user0_.age as age2_0_0_, user0_.ctime as ctime3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.user_id=?2019-07-17 21:26:04.717 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(76567159
)] for JPA transaction2019-07-17 21:26:04.717 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Participating in existing transactionHibernate: select user0_.user_id as user_id1_0_0_, user0_.age as age2_0_0_, user0_.ctime as ctime3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.user_id=?java.lang.RuntimeException: 111 at com.example.demotran.tran.TranService.b(TranService.java:42) ......2019-07-17 21:26:04.717 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit2019-07-17 21:26:04.717 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(76567159
)]//两条数据都进行了插入,没有回滚Hibernate: insert into t_user (age, ctime, user_name, user_id) values (?, ?, ?, ?)Hibernate: insert into t_user (age, ctime, user_name, user_id) values (?, ?, ?, ?)2019-07-17 21:26:04.733 DEBUG 7976 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(76567159
)] after transaction

看一下符合期望的编码:

package com.example.demotran.tran;import org.springframework.aop.framework.AopContext;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;import java.util.Date;@Servicepublic class TranService{    @Autowired    private TranDao tranDao;    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)    public void add() {        User aaa = new User();        aaa.setAge(22);        aaa.setCtime(new Date());        aaa.setUserId(2);        aaa.setUserName("aaa");        tranDao.save(aaa);        try {            TranService tranService = (TranService) AopContext.currentProxy();            tranService.b();        }catch (Exception e){            e.printStackTrace();        }    }    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)    public void b() {        User aaa = new User();        aaa.setAge(33);        aaa.setCtime(new Date());        aaa.setUserId(3);        aaa.setUserName("bbb");        tranDao.save(aaa);        throw new RuntimeException("111");    }}

看一下执行日志:

//开启事务2019-07-17 21:28:34.108 DEBUG 7940 --- [  restartedMain] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.example.demotran.tran.TranService.add]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Throwable2019-07-17 21:28:34.108 DEBUG 7940 --- [  restartedMain] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(176172822
)] for JPA transaction2019-07-17 21:28:34.124 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@58c34766]2019-07-17 21:28:34.124 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(176172822
)] for JPA transaction2019-07-17 21:28:34.124 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Participating in existing transactionHibernate: select user0_.user_id as user_id1_0_0_, user0_.age as age2_0_0_, user0_.ctime as ctime3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.user_id=?2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(176172822
)] for JPA transaction//挂起了当前事务2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Suspending current transaction, creating new transaction with name [com.example.demotran.tran.TranService.b]//开启了一个新的实体管理器为事务操作2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(1157613382
)] for JPA transaction2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@1e1d8bf4]2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1157613382
)] for JPA transaction2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Participating in existing transactionHibernate: select user0_.user_id as user_id1_0_0_, user0_.age as age2_0_0_, user0_.ctime as ctime3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.user_id=?2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Initiating transaction rollback//回滚了事务2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Rolling back JPA transaction on EntityManager [SessionImpl(1157613382
)]2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(1157613382
)] after transaction//重启了当前事务2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Resuming suspended transaction after completion of inner transactionjava.lang.RuntimeException: 111 at com.example.demotran.tran.TranService.b(TranService.java:41) ......2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit2019-07-17 21:28:34.170 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(176172822
)]//最终只有一条数据插入库中Hibernate: insert into t_user (age, ctime, user_name, user_id) values (?, ?, ?, ?)2019-07-17 21:28:34.186 DEBUG 7940 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(176172822
)] after transaction

好了,今天就到这里.如果你有更好的方法,敬请留言,相互学习.

转载地址:http://uduti.baihongyu.com/

你可能感兴趣的文章
章节导学第6章 数组
查看>>
章节导学第7章 函数
查看>>
章节导学第8章 预处理
查看>>
C语言教材市场的分析
查看>>
章节导学第9章 指针
查看>>
章节导学第10章 用户自定义数据类型
查看>>
章节导学第11章 文件
查看>>
章节导学第12章 位运算
查看>>
浅谈变量的原始值、存储状态、实际值和输出值
查看>>
printf函数的盲点
查看>>
再也不要讨论类似(i++)+(i++)+(i++)表达式的值了!
查看>>
第一讲:结构型与数组
查看>>
第二讲:类的封闭性
查看>>
第三讲:再谈类
查看>>
第四讲:具有合法状态的对象
查看>>
第五讲:类的组合
查看>>
第六讲:析构函数及复制构造函数
查看>>
C语言序列点浅析
查看>>
sql之内外连接
查看>>
C#事件(event)解析
查看>>