Spring 声明式事务管理(1)

3 月,跳不动了?>>> hot3.png

Spring 声明式事务管理介绍

    说明:本文基于 jdk 1.8 ,spring-framework 5.1.7.RELEASE。

    Spring 的声明式事务也就是通过配置的方式来管理事务,而不通过硬编码的方式来管理事务。关系型数据库对事务的主要操作包含:事务提交 , 事务回滚。Spring 事务管理的主要操作包含:事务提交,事务回滚,事务挂起 。 Spring 申明式事务管理是建立在 Spring AOP 技术的基础之上, 本质上也就是建立在动态代理对象技术之上 (JdkDynamicAopProxy , CglibAopProxy)。

3e961c71057d11c1b5d8e5a9c057d6151ec.jpg  

Spring 事务传播机制介绍

1. 什么是事务的传播机制?

        当事务函数 A 内部调用了另一个事务函数 B ,在调用到函数 B 后作用于函数 A 上的事务是否作用于函数 B 内或者如何作用,这就是事务的传播。

2. Spring 支持的事务传播机制

        2.1    PROPAGATION_REQUIRED 

              该函数必须有一个事务,如果不存在就创建一个,如果已经有一个存在的事务那么就使用这个存在的事务。在这种传播机制下使用的始终是同一个事务。

              

        2.2    PROPAGATION_SUPPORTS 

             支持当前存在的事务; 如果不存在则执行非事务性。

        2.3    PROPAGATION_MANDATORY

                强制性的支持当前事务,如果当前事务不存在则抛出异常。

        2.4    PROPAGATION_REQUIRES_NEW

                创建一个新事务,挂起当前已经存在的事务。

                

        2.5    PROPAGATION_NOT_SUPPORTED

                不支持当前事务; 而是总是以非事务方式执行。

        2.6    PROPAGATION_NEVER

                从不支持事务,如果存在当前事务抛出异常。

        2.7    PROPAGATION_NESTED

                使用具有多个保存点的单个物理事务,它可以回滚到该事务。 这种部分回滚允许内部事务作用域触发其作用域的回滚,外部事务能够继续物理事务,尽管已经回滚了一些操作。 此设置通常映射到JDBC保存点,因此它仅适用于JDBC资源事务。 

 

Spring 事务管理的线程依赖性

        Spring 事务管理是和当前线程绑定的,需要跨函数传递的变量都存储在 ThreadLocal 中比如数据库连接 Connection 对象。所以 Spring 的事务传播也只能是基于当前线程,如果在另一个线程中调用一个事务函数那么就是一个新的事务了。TransactionSynchronizationManager  是用来保存一些事务操作过程中的共享数据。

public abstract class TransactionSynchronizationManager {

	private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

	private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<>("Transactional resources");

	private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
			new NamedThreadLocal<>("Transaction synchronizations");

	private static final ThreadLocal<String> currentTransactionName =
			new NamedThreadLocal<>("Current transaction name");

	private static final ThreadLocal<Boolean> currentTransactionReadOnly =
			new NamedThreadLocal<>("Current transaction read-only status");

	private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
			new NamedThreadLocal<>("Current transaction isolation level");

	private static final ThreadLocal<Boolean> actualTransactionActive =
			new NamedThreadLocal<>("Actual transaction active");

    // ......

}

Spring 事务代理对象说明

        去面试的时候面试官问到 spring 事务相关问题时,会经常问这么一个问题 。  

        问题 :saveUser(UserEntity user) 函数内部调用了 getUserById(Long uid) 函数,那么 getUserById(Long uid) 能否被事务作用? 

        答案: 不能。因为在这个 UserServiceImpl 内部调用自己对象内部的函数使用的是本对象(也就是 this) , 而这个 this 并不是一个代理对象所以并不会有事务作用。

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public UserEntity getUserById(Long uid) {
        return null;
    }
    
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void saveUser(UserEntity user) {
        // save user
        
        this.getUserById(user.getId());
    }
}

    如果这个问题你回答对了,面试官可能会问如果我想有事务作用的调用 getUserById(Long uid) 函数该如何做?这里有两种办法,第一种是将 UserServiceImpl 的代理对象注入到 UserServiceImpl 中 。@Autowired UserService proxyUserService 。 这个 proxyUserService  就是被事务代理的对象,用这个对象去调用就可以让事务起作用。

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private UserService proxyUserService;



    @Transactional(rollbackFor = Throwable.class)
    @Override
    public UserEntity getUserById(Long uid) {
        return null;
    }
    
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void saveUser(UserEntity user) {
        // save user
        
        proxyUserService.getUserById(user.getId());
    }
}

       

        第二种方法就是使用 AopContext 获取到当前类的代理对象,然后用获取到的代理对象去进行调用。

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public UserEntity getUserById(Long uid) {
        return null;
    }
    
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void saveUser(UserEntity user) {
        // save user
        
        UserService userService = (UserService) AopContext.currentProxy();
        userService .getUserById(user.getId());
    }
}
发布了132 篇原创文章 · 获赞 2 · 访问量 565

猜你喜欢

转载自blog.csdn.net/weixin_45839894/article/details/105198299
今日推荐