SpringMVC 事务回滚机制

Spring事物中,由Spring来负责管理数据库的数据连接,@Transactional只有应用到public方法才会有效,因为在获取事务注解时,会调用AbstractFallbackTransactionAttributeSource的computeTransactionAttribute方法。

private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) {
		// Don't allow no-public methods as required.
        // 不是public方法 不允许
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}
    // 省略下面代码
}

这个方法会检查目标方法的修饰符是不是public,若不是public,就不会获取@Transactional的属性信息。最终不会让TransactionInterceptor 来拦截该目标方法进行事务管理。

Spring捕获到 throw new RuntimeException 时,事物会回归;


	@Transactional
	public void insertRole(RoleBean roleBean) {
		roleDao.insertRole(roleBean);
		throw new RuntimeException();
	}

Spring捕获到throw new Exception时,事物不会回归;(下列代码无法编译,只是说明)


	@Transactional
	public void insertRole(RoleBean roleBean) {
		roleDao.insertRole(roleBean);
		throw new Exception();
	}

如果这时候想要捕获Exception 的异常,需要在注释@Transactional(rollbackFor=Exception.class),如果是多个,可以rollbackFor={Exception.class,Exceptions.class}(下列代码无法编译,只是说明)


	@Transactional(rollbackFor=Exception.class)
	public void insertRole(RoleBean roleBean) {
		roleDao.insertRole(roleBean);
		throw new Exception();
	}

 
Spring aop  异常捕获原理:被拦截的方法需显式抛出异常,不能自己进行try catch,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获throw new RuntimeException的异常。

如果在事物方法中加入try catch,Spring 无法捕获异常,事物就无法回滚数据。数据正常存储,无法进行回滚。


	@Transactional
	public void insertRole(RoleBean roleBean) {
		try {
			roleDao.insertRole(roleBean);
			throw new RuntimeException();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

所以如果再cathc 后面加个方法,不管两个delete方法加不加事物,也可以执行成功。(Spring 事物默认是,如果方法运行时,有一个事物了,那么就加入这个事物,否则就创建一个新事物;因为 insertRole 加了事务,在其之内 roleDao.insertRole() 会被包裹事务,同时最后两行 deleteRoleId1和 deleteRoleId2也会在同一个事务管理下,虽然 deleteRoleId1显示注明要加事务管理但是没有特别注明传播级别,因此在默认的事务传播行为(propagation=Propagation.REQUIRED )。所以deleteRoleId1在有事务注解的情况下,如果外部方法 insertRole 没有事务它会自己建一个新事务;但是 insertRole 已经有事务了,所以 deleteRoleId1会加入 insertRole 的事务,而不会使用自己的事物)


	@Transactional
	public void insertRole(RoleBean roleBean) {
		try {
			roleDao.insertRole(roleBean);
			throw new RuntimeException();
		} catch (Exception e) {
			e.printStackTrace();
		}
		deleteRoleId1(roleId);
		deleteRoleId2(roleId);
	}

	@Transactional
	public void deleteRoleId1(Integer roleId) {
		roleDao.deleteRoleId(roleId);
	}

	public void deleteRoleId2(Integer roleId) {
		roleDao.deleteRoleId(roleId);
	}

所以如果想Spring 进行事物回归,那就不要自己捕获事物,或者捕获事物在catch中抛出一个错误,那么Spring 事物就会回滚


	@Transactional
	public void insertRole(RoleBean roleBean) {
		try {
			roleDao.insertRole(roleBean);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
	
	@Transactional
	public void insertRole(RoleBean roleBean) {
		if (roleBean != null) {
			roleDao.insertRole(roleBean);
		}else{
			throw new RuntimeException();
		}
	}

如果 insertRole没有事务,调用有事务的deleteRoleId,即使deleteRoleId方法不捕获异常,那么Spring 事务也无法回滚数据,因为Spring 事务是AOP 动态代理,自己调用自己的方法,并不会产生代理对象,也就不会有AOP。这就是Spring 事务的自调用失效。(即insertRole方法加上@Transactional事务注解,那么数据会回滚,参考前文事务的传播)



	public void insertRole(RoleBean roleBean) {
		deleteTerminalByRoleId(3);
	}

	@Transactional
	public void deleteRoleId(int roleId) {
		roleDao.deleteRoleId(roleId);
		throw new RuntimeException();
	}

 

以上就是目前了解的Spring 回滚机制,有问题可以互相讨论学习。

你可能感兴趣的:(Spring,spring,事物回滚,事物不回滚)