精华内容
下载资源
问答
  • 须知 @Transactional 底层使用TransactionInterceptor类在方法执行前后开启事务和关闭事务 ...接口和实现类,test1中不加@Transactional,test2加@Transactional,外部调用test1()方法 结果:test2方法失败时,事务并

    须知

    @Transactional 底层使用TransactionInterceptor类在方法执行前后开启事务和关闭事务

    spring的动态代理,分为两种:jdk自身代理和cglib代理方式

    参考:https://blog.csdn.net/a837199685/article/details/68930987

    objenesis参考:http://objenesis.org/index.html  主要用于不用构造方法初始化实例

    场景

    case1

    接口和实现类,test1中不加@Transactional,test2加@Transactional,外部调用test1()方法

    结果:test2方法失败时,事务并不会回滚

    //接口
    public interface CeshiService {
        void test1();
    }
    
    
    //test1方法上没有Transactional注解,test2方法上有Transactional注解
    @Service
    public class CeshiServiceImpl implements CeshiService{
    
        public void test1(){
            test2();
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void test2() {
            Db.update("INSERT INTO \"public\".\"ceshi\"(\"id\", \"name\") VALUES (2, '2');");
            throw new Exception("异常");
        }
    }
    

    分析:

    debug发下,CeshiServiceImpl中的this指向的是CeshiServiceImpl@11343 实例,并不是$.Proxy代理对象,那么当也就决定了内部调用test2时,不会走动态代理的链路,那么事务也就不会生效

    case2

    普通类,test1中不加@Transactional,test2加@Transactional,外部调用test1()方法

    结果:test2方法失败时,事务并不会回滚

    //test1方法上没有Transactional注解,test2方法上有Transactional注解
    @Service
    public class CeshiService{
    
        public void test1(){
            test2();
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void test2() {
            Db.update("INSERT INTO \"public\".\"ceshi\"(\"id\", \"name\") VALUES (2, '2');");
            throw new Exception("异常");
        }
    }
    

    分析:

    debug发下,CeshiServiceImpl中的this指向的是CeshiServiceImpl@11342 实例,并不是Enhanced代理对象,那么当也就决定了内部调用test2时,不会走动态代理的链路,那么事务也就不会生效

    如何生效

    1. 首先开启exposeProxy,然后((CeshiService) AopContext.currentProxy()).test2();去调用test2内部方法

    @Transactional 代码分析

    TransactionInterceptor类

    public Object invoke(final MethodInvocation invocation) throws Throwable {
            Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
            //主要来此处的invokeWithinTransaction方法,把真正的方法包围了
            return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
                public Object proceedWithInvocation() throws Throwable {
                    return invocation.proceed();
                }
            });
    }
    
    

    TransactionAspectSupport中的invokeWithinTransaction方法

    protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
    			throws Throwable {
    
    		// If the transaction attribute is null, the method is non-transactional.
            //获取注解属性
    		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    
    		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
    			// Standard transaction demarcation with getTransaction and commit/rollback calls.
                //开启事务
    			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
    			Object retVal = null;
    			try {
    				// This is an around advice: Invoke the next interceptor in the chain.
    				// This will normally result in a target object being invoked.
                    //继续执行下一个链路
    				retVal = invocation.proceedWithInvocation();
    			}
    			catch (Throwable ex) {
    				// target invocation exception
                    //里面执行事务的提交或回滚
    				completeTransactionAfterThrowing(txInfo, ex);
    				throw ex;
    			}
    			finally {
    				cleanupTransactionInfo(txInfo);
    			}
    			commitTransactionAfterReturning(txInfo);
    			return retVal;
    		}
    
    		else {
    			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
    			try {
    				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
    						new TransactionCallback<Object>() {
    							@Override
    							public Object doInTransaction(TransactionStatus status) {
    								TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
    								try {
    									return invocation.proceedWithInvocation();
    								}
    								catch (Throwable ex) {
    									if (txAttr.rollbackOn(ex)) {
    										// A RuntimeException: will lead to a rollback.
    										if (ex instanceof RuntimeException) {
    											throw (RuntimeException) ex;
    										}
    										else {
    											throw new ThrowableHolderException(ex);
    										}
    									}
    									else {
    										// A normal return value: will lead to a commit.
    										return new ThrowableHolder(ex);
    									}
    								}
    								finally {
    									cleanupTransactionInfo(txInfo);
    								}
    							}
    						});
    
    				// Check result: It might indicate a Throwable to rethrow.
    				if (result instanceof ThrowableHolder) {
    					throw ((ThrowableHolder) result).getThrowable();
    				}
    				else {
    					return result;
    				}
    			}
    			catch (ThrowableHolderException ex) {
    				throw ex.getCause();
    			}
    		}
    	}
    

     

    protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
    		if (txInfo != null && txInfo.hasTransaction()) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
    						"] after exception: " + ex);
    			}
                // 注解上指定的回滚异常类型是否匹配
    			if (txInfo.transactionAttribute.rollbackOn(ex)) {
    				try {
                 //回滚					txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
    				}
    				catch (TransactionSystemException ex2) {
    					logger.error("Application exception overridden by rollback exception", ex);
    					ex2.initApplicationException(ex);
    					throw ex2;
    				}
    				catch (RuntimeException ex2) {
    					logger.error("Application exception overridden by rollback exception", ex);
    					throw ex2;
    				}
    				catch (Error err) {
    					logger.error("Application exception overridden by rollback error", ex);
    					throw err;
    				}
    			}
    			else {
    				// We don't roll back on this exception.
    				// Will still roll back if TransactionStatus.isRollbackOnly() is true.
    				try {
    //提交事务					txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    				}
    				catch (TransactionSystemException ex2) {
    					logger.error("Application exception overridden by commit exception", ex);
    					ex2.initApplicationException(ex);
    					throw ex2;
    				}
    				catch (RuntimeException ex2) {
    					logger.error("Application exception overridden by commit exception", ex);
    					throw ex2;
    				}
    				catch (Error err) {
    					logger.error("Application exception overridden by commit error", ex);
    					throw err;
    				}
    			}
    		}
    	}

    rollbackOn方法,从此可以看到,默认只要当是RuntimeException或Error异常时才会回滚,非RuntimeException的Exception默认不会回滚

    	@Override
    	public boolean rollbackOn(Throwable ex) {
    		return (ex instanceof RuntimeException || ex instanceof Error);
    	}
    

    总结

    我们发现不论是jdk动态代理还是cglib动态代理,执行类方法时,this对象始终是原始实例,也就决定了,内部调用时,不会触发动态代理里面的方法。

     

     

    展开全文
  • springboot @Transactional调用失效问题

    千次阅读 2018-08-24 10:29:56
    spring的数据库事务约定的实现原理是AOP,而AOP的原理是动态代理,在自调用的过程中,是类自身调用,而不是代理对象去调用,那么不会产生AOP,这样spring就不能把你的代码植入到约定的流程中,于是就产生了失败...

    spring的数据库事务约定的实现原理是AOP,而AOP的原理是动态代理,在自调用的过程中,是类自身的调用,而不是代理对象去调用,那么不会产生AOP,这样spring就不能把你的代码植入到约定的流程中,于是就产生了失败场景。

    解决方案:

    用一个service去调用另一个service,这样就是代理对象的调用。

    参考以下代码

     

    展开全文
  • 错误原因: 调用方法saveA 和 saveB 是通过 实例对象调用的,而非Spring代理的Bean。 解决办法: 通过注入自身Bean调用本类中的方法,即可。

    错误原因:

    调用方法saveA  和  saveB  是通过 实例对象调用的,而非Spring代理的Bean。

     

    解决办法:

    通过注入自身Bean调用本类中的方法,即可。

    展开全文
  • @Transactional 失效总结

    2018-08-21 09:47:24
    @Transactional底层实现是SpringAOP技术,而...3. 自调用方法:即,一个类的一个方法调用自身另外一个方法,如下: package com.cmb.service.impl; import java.util.List; import org.springframework.bea...

    @Transactional底层实现是SpringAOP技术,而SpringAOP技术是动态代理;

     

    1. 静态方法;

    2. 非public方法;

    3. 自调用方法:即,一个类的一个方法调用自身另外一个方法,如下:

    package com.cmb.service.impl;
    
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.cmb.mapper.RoleMapper;
    import com.cmb.pojo.Role;
    import com.cmb.service.RoleService;
    
    @Service
    public class RoleServiceImpl implements RoleService {
    
    	@Autowired
    	private RoleMapper roleMapper = null;
    	
    	@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
    	public int insertRole(Role role) {
    		return roleMapper.insertRole(role);
    	}
    
    	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    	public int insertRoleList(List<Role> roleList) {
         
    		int count = 0;
    		for(Role role : roleList){
    			try{
    				//调用自身类的方法,产生自调用问题
    				count+= insertRole(role);
    			}catch(Exception e){
    				e.printStackTrace();
    			}
    		}
    		return count;
    	}
    	
    }
    

    其中 ,

    //调用自身类的方法,产生自调用问题
    				count+= insertRole(role);

    会出现此问题。

    展开全文
  • 注解@Transactional的底层实现是spring AOP,而spring AOP技术使用的是动态代理。 对于静态(static) 方法 和 非 (public) 方法,注解@Transactional失效... 类方法的自调用 :一个类方法调用自身另外一个方法 ...
  • 5. 自身调用的问题 6. 数据源没有配置事务管理器 @Transactional 实现原理: 1) 事务开始时,通过AOP机制,生成一个代理connection对象, 并将其放入 DataSource 实例的某个与 DataSourceTransactionManager 相关...
  • 最近发现有个老的系统有个事务问题,后面查资料发现,@Transactional使用有问题导致事务失效了 注意事项:已自己写了demo...若该类自身的另一个非@Transactional修饰的方法要调用,会有自调用事务不生效问题, 若...
  • @Transactional的自调用失效问题

    千次阅读 2018-02-01 20:52:23
    注解@transactional的底层实现是Spring AOP技术,而Spring AOP技术使用的是动态代理。这就意味着对于静态(static... 所谓的自调用是指一个类的一个方法去调用自身另外一个方法的过程。看代码: @Transactional(pr
  • 最近在项目中用到Spring 2.5 + Hibernate 3.2,在做事务处理的过程中用到了自身嵌套的事务的问题,使用声明式的事务处理无法解决该问题,查看Spring 2.5的文档《9.5.6. 使用 @Transactional》一节中看到: <!--如果...
  • 我们在用Spring框架开发Web项目过程中,经常需要用同一个service中的一个方法调用另一个方法,如果此时调用方没有添加事务注解@Transactional,而在被调用方添加事务注解@Transactional,当被调用方法中出现异常,这...
  • 在一个类内部有2个方法foo和bar,其中bar方法配有注解(@Transactional),即bar是事务执行的,而foo不是事务执行,当foo方法内部调用bar方法后,bar方法的事务是不生效的。示例代码如下: public class ...
  • 记spring线程调用事务不回滚的坑

    千次阅读 2020-03-26 16:05:55
    一个需求,最开始打算用多线程分别插入多个库,埋了 int a=1/0测试回滚,结果发现并没有回滚 ...原因:线程调用自身类的方法,并不会用到spring aop的代理类,所以只是执行了一个普普通通的方法。...
  • 项目开发完后,在进行后端集成测试的时候发现用户Service层抛出异常后,...方法上面有@Transactional注解,并且调用的是mapper方法,不存在自身调用,排除 不支持事务------>@Transactional注解使用的默认传播..
  • 相关问题 一、@Transactional的失效问题 ...自调用,就是一个类的一个方法去调用自身另外一个方法的过程。如下: @Autowired private RoleDao roleDao; @Transactional(propagation = Propagation.REQUI
  • 数据库引擎不支持事务 mysql5.5.5 默认存储引擎是InnoDB(支持事务),之前是MyISAM(不...自身调用问题 事务开启必须在本类的开始(也就是说外部调用事务才会生效,不可以本类的方法调用本类的事务,因为这样的话没.
  • 1.简介在上篇文章中讲到了使用@Transactional注解失效的几种场景,其中有一个就是自身调用的问题,当时的解决办法就是使用@Autowired注解将本类注入到ioc容器中再调用方法,这样显然不太好,本篇文章中就讲一下在类...
  • Mybatis

    2018-08-08 11:15:56
    @Transactional底层实现是SpringAOP,而SpringAOP技术使用的是动态代理,意味着对于静态和非public方法注解@Transactional是失效的,还有极其容易犯的错误,自调用(一个类里的方法里调用自身类的另一个方法),自己...
  • 类中的方法调用同一个类中的另一个方法时,注解会失效; 如:@Cacheable,@Transactional 因为注解是通过代理类实现中,调用自身的方法当然不会生效。 你明白了吗? ...
  • Spring事务失效的原因

    2020-02-22 09:56:40
    Spring的@Transactional...自身调用问题; 异常被吃了; 异常类型错误。 数据库引擎不支持事务 以MySQL为例,其MyISAM引擎是不支持事务操作的,InnoDB才是支持事务的引擎,一般要支持事务都会使用InnoDB。 注:从...
  • 在使用spring框架的时候...),proxy是代理模式,仅有外部方法调用才会被代理截获,自身方法调用,即使配置了@Transactional注解,事务也无法生效,也不能应用在非public方法上;而aspectj模式与代理模式不同,aspe...
  • 在同一个service中有A函数和B函数,由于A调用B函数时都需要事务(用@Transactional),并放到同一个事务中,所以使用 @Autowired peivatr XxxxService self; 的方式注入自身,然而在SpringBoot启动过程中bean...
  • 当用spring 的注解方式去管理bean的时候。使用诸如 @Transactional这样的注解,spring会在幕后悄悄的生成一些代码,...这些动态生成的代码将对(target object)被代理对象的调用转移到自身上,这就是所谓的“代理模式
  • 9.6.1 使用@Transactional注解 9.6.2 通过AspectJ LTW引入事务切面 9.7 集成特定的应用服务器 9.7.1 BEA WebLogic 9.7.2 BEA WebLogic 9.8 小结 第10章 Spring的事务管理难点剖析 10.1 DAO和事务管理的牵绊 10.1.1 ...
  • 9.6.1 使用@Transactional注解 9.6.2 通过AspectJ LTW引入事务切面 9.7 集成特定的应用服务器 9.7.1 BEA WebLogic 9.7.2 BEA WebLogic 9.8 小结 第10章 Spring的事务管理难点剖析 10.1 DAO和事务管理的牵绊 10.1.1 ...

空空如也

空空如也

1 2
收藏数 25
精华内容 10
关键字:

transactional自身调用