【Spring事务底层实现原理】

@Transactional注解

Spring使用了TransactionInterceptor拦截器,该拦截器主要负责事务的管理,包括开启、提交、回滚等操作。当在方法上添加@Transactional注解时,Spring会在AOP框架中对该方法进行拦截,TransactionInterceptor会在该方法执行前后,对事务进行切面处理,Spring会基于该类生成一个代理对象,把这个代理对象作为bean。当调用这个代理对象的方法时,如果有事务处理,则会先关闭事务的自动功能,然后执行方法的具体业务逻辑,如果业务逻辑没有异常,那么代理逻辑就会直接提交,如果出现任何异常,那么直接进行回滚操作。

事务管理器

Spring还提供了多种事务管理器,包括JDBC事务管理器、Hibernate事务管理器、JTA事务管理器等等,可以满足不同数据访问层的需求。事务通知是Spring事务机制中的一个重要组成部分,主要用于判断哪些方法需要被事务管理,以及如何管理事务。

Spring事务底层实现原理

应用启动时会创建一个代理类,把事务逻辑织入到代理类中,然后用代理类替代目标类,并放入上下文容器中。当实际调用目标类的事务方法时,被代理类拦截,先执行拦截器中的事务逻辑,再执行目标类的业务逻辑,最后处理异常回滚和提交。这样就能实现简单、方便、可控的事务管理。

示例代码

这里给出一个简单的示例代码:

定义一个接口,包含需要进行事务管理的方法:

java 复制代码
public interface UserService {
    void addUser(User user);
    void deleteUser(String id);
    void updateUser(User user);
    User getUser(String id);
}

实现这个接口的目标类:

java 复制代码
public class UserServiceImpl implements UserService {
    @Override
    public void addUser(User user) {
        //添加用户的业务逻辑
    }
    @Override
    public void deleteUser(String id) {
        //删除用户的业务逻辑
    }
    @Override
    public void updateUser(User user) {
        //更新用户的业务逻辑
    }
    @Override
    public User getUser(String id) {
        //查询用户的业务逻辑
        return null;
    }
}

定义一个事务拦截器类:

java 复制代码
/**
 * TransactionInterceptor 是一个实现了 MethodInterceptor 接口的拦截器类
 */
public class TransactionInterceptor implements MethodInterceptor {
    /**
     * TransactionManager 对象,用于管理事务
     */
    private TransactionManager txManager;
    /**
     * 用于注入 TransactionManager 对象
     * @param txManager TransactionManager 对象
     */
    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }
    /**
     * 实现 MethodInterceptor 接口的 invoke 方法,用于拦截指定方法
     * @param invocation MethodInvocation 对象,用于获取被拦截的方法及其参数
     * @return 执行方法的返回结果
     * @throws Throwable 抛出异常
     */
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object result;
        try {
            // 开启事务
            txManager.start();
            // 执行被拦截的方法,并获取方法执行的返回结果
            result = invocation.proceed();  
            // 提交事务
            txManager.commit();
        } catch (Exception e) {
            // 回滚事务
            txManager.rollback();
            throw e;
        }
        return result;
    }
}

定义一个上下文容器类:

java 复制代码
public class ApplicationContext {
    private Map<String, Object> beanMap = new HashMap<>(); // 用于存放bean的map
    // 注册bean
    public void registerBean(String name, Object bean) {
        beanMap.put(name, bean); // 将bean存放到map中
    }
    // 获取bean
    public Object getBean(String name) {
        Object bean = beanMap.get(name); // 从map中获取bean
        if (bean instanceof Advised) { // 如果bean是Advised类型,说明使用了AOP
            return ((Advised)bean).getTargetSource().getTarget(); // 返回目标对象
        }
        return bean; // 返回原始对象
    }
}

在应用启动时,创建一个代理工厂类,使用上述事务拦截器对目标类进行代理:

java 复制代码
/**
 * 代理工厂类,用于创建代理对象
 */
public class ProxyFactory {
    /**
     * 创建代理对象
     * @param target 目标对象,需要被代理的对象
     * @param interceptor 事务拦截器,代理对象需要加入该拦截器
     * @return 返回代理对象
     */
    public static Object createProxy(Object target, TransactionInterceptor interceptor) {
        DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
        AdvisedSupport advisedSupport = new AdvisedSupport();
        advisedSupport.setTarget(target); // 设置目标对象
        advisedSupport.addAdvice(interceptor); // 添加事务拦截器
        return proxyFactory.createAopProxy(advisedSupport).getProxy(); // 创建代理对象并返回
    }
}

然后在应用启动时,创建容器并注册代理类:

java 复制代码
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ApplicationContext();
        UserService target = new UserServiceImpl(); //创建目标类
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTxManager(new TransactionManager()); //设置事务管理器
        UserService proxy = (UserService) ProxyFactory.createProxy(target, interceptor); //创建代理类
        context.registerBean("userService", proxy); //注册代理类到上下文容器中
        //使用代理类进行业务操作
        User user = new User();
        context.getBean("userService").addUser(user);
    }
}

这样,当执行代理类的方法时,就会先执行事务拦截器中的事务逻辑,再执行目标类的业务逻辑。如果出现异常,会进行回滚。这样就实现了简单、方便、可控的事务管理。

相关推荐
utmhikari1 小时前
【架构艺术】Go语言微服务monorepo的代码架构设计
后端·微服务·架构·golang·monorepo
蜡笔小新星1 小时前
Flask项目框架
开发语言·前端·经验分享·后端·python·学习·flask
计算机学姐1 小时前
基于Asp.net的驾校管理系统
vue.js·后端·mysql·sqlserver·c#·asp.net·.netcore
欢乐少年19043 小时前
SpringBoot集成Sentry日志收集-3 (Spring Boot集成)
spring boot·后端·sentry
夏天的味道٥4 小时前
使用 Java 执行 SQL 语句和存储过程
java·开发语言·sql
冰糖码奇朵6 小时前
大数据表高效导入导出解决方案,mysql数据库LOAD DATA命令和INTO OUTFILE命令详解
java·数据库·sql·mysql
好教员好6 小时前
【Spring】整合【SpringMVC】
java·spring
浪九天7 小时前
Java直通车系列13【Spring MVC】(Spring MVC常用注解)
java·后端·spring
小斌的Debug日记7 小时前
框架基本知识总结 Day16
redis·spring
堕落年代8 小时前
Maven匹配机制和仓库库设置
java·maven