Spring事务源码Day01

框架的理解

框架是整个或部分系统的可重用设计

@Service
public class UserService {
    @Resource
    JdbcTemplate jdbcTemplate;
    //常用ORM框架-MyBatis,Hibernate,JdbcTemplate,JPA支持

    /**
     * 使用spring注解管理事务
     */
    @Transactional(rollbackFor = {Exception.class})
    public void insertUser(User user) {
        //插入用户表
        jdbcTemplate.execute("INSERT INTO user_table VALUES('" + user.getId() + "','" + user.getUserName() + "','" + user.getPassword() + "')");
        //插入日志记录表
        jdbcTemplate.execute("INSERT INTO log_table VALUES('" + UUID.randomUUID().toString() + "','新增用户:" + user.getUserName() + "')");
        //模拟异常
        int i = 1 / 0;
    }

    @Resource
    DataSource dataSource;

    /**
     * 不使用框架进行事务管理
     */
    public void deleteUser(String userId) throws Exception {
        //数据库连接
        Connection connection = dataSource.getConnection();
        //关闭事务自动提交
        connection.setAutoCommit(false);
        //执行SQL语句
        Statement statement = connection.createStatement();
        try {
            //---------业务---------
            //删除指定id用户
            statement.execute("DELETE FROM user_table WHERE id='" + userId + "'");
            //插入日志记录表
            statement.execute("INSERT INTO log_table VALUES('" + UUID.randomUUID().toString() + "','删除用户:" + userId + "')");
            //模拟异常
            int i = 1 / 0;
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            connection.rollback();
        }
    }
}

不用框架如何进行事务管理

jdbc-基于连接的层面去控制事务

ORM框架的工作流程:

ORM框架

简单模拟实现JdbcTemplate

@Component//spring托管,创建对象,注入等可复用的功能是oop的体现
public class MyJdbcTemplate {
    @Qualifier
    DataSource dataSource;

    public void execute(String sql) throws Exception {
        //数据库连接   每次获取的都是新的连接
        Connection connection = dataSource.getConnection();
        //关闭自动提交
        connection.setAutoCommit(false);
        //执行SQL语句
        Statement statement = connection.createStatement();
        try {
            statement.execute(sql);
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            connection.rollback();
        }
    }
}

再次使用只需传入sql语句,无需关心连接等细节。实现了代码的复用。

但此时每次执行SQL语句都是新的连接,无法做事务的控制。

ORM框架只关心绑定参数生成SQL,pojo对象结果映射,SQL的执行。 

不在ORM框架中进行事务的控制。


在JdbcTemplate中可以看到是通过调用DataSourceUtils.getConnection()方法获取连接的

它间接调用了TransactionSynchronizationManager(事务同步管理器,用来存放连接)

mybatis

在mybatis中SqlSession就好比是一个数据库的连接

通过SqlSessionUtils工具类的getSqlSession()方法可以得到它的实例

可以看到该方法中也是通过TransactionSynchronizationManager来获取连接的。

所有要和Spring框架集成的ORM框架都需要从这里来获取连接。

TransactionManager

简单实现TransactionMannager

此时存在问题,当多个用户访问同一个controller方法,此时tomcat会用多线程来处理多个请求对该方法的访问,那么多个线程在通过Transaction获取数据库连接时就会获取到同一个连接。那么如果A用户的操作成功,B用户的操作失败了,就需要进行回滚。由于他们使用的是同一个连接,就会导致A用户的操作同样被回滚。

ThreadLocal

此时就引入了ThreadLocal,它是Java中的一种特殊变量。

ThreadLocal:一个线程级别的变量,就是每个线程都拥有了自己独立的一个变量,多线程间的竞争条件被它彻底消除,在并发模式下是绝对安全的变量。

用法:ThreadLocal<T> var=new ThreadLocal<T>();

会自动在每个线程创建一个T的副本,副本之间彼此独立,互不影响。可以用ThreadLocal存储一些参数,以便在线程中多个方法中使用,用来代替方法传参的做法。

测试

在自己定义的TransactionManager中使用TheadLocal以解决上面的问题

此时就可以保证在一个线程的情况下,使用的是同一个连接,就可以在业务层面进行事务管理了。

Spring中的事务

不使用注解管理 

spring注解

注解只是一段标记,谁定义的给谁看。

自定义注解

使用注解标记方法为是需要事务的,但此时是不起作用的

要想要它起作用就涉及到aop。对代码进行进一步封装

AOP

功能增强,动态的将新代码的逻辑切入到指定方法的指定位置

 

上图中,可以看出在使用事务时,发生变化的仅仅是业务逻辑的部分

通过AOP和注解增强业务方法来实现事务

实际的方法执行时按照AOP重新定义的

Spring是通过cglib来实现AOP的

cglib

模拟spring初始化过程

TransactionInterceptor

public class TransactionInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (method.isAnnotationPresent(Transactional.class)) {
            System.out.println("TransactionInterceptor:如果方法加了Transactional注解,则执行前,先执行");
        }
        //调用被代理方法
        Object object = methodProxy.invokeSuper(o, objects);
        return object;

    }
}

cglib采用继承的方式来实现对被代理方法的增强,子类重写父类的方法。重点在于子类是动态生成的

生成的子类类似下图(用作理解)

生成的子类

总结

了解了框架的意义

为什么使用框架?

        框架是开发者定制的可重用应用框架,是模板化的代码帮我们实现很多基础的功能,我们只需要专心于需要实现的业务逻辑,而不需要考虑很多底层功能。

事务

在不使用框架是如何实现事务?

        通过连接的层面来处理。

为什么不在ORM框架下管理事务?

        ORM框架只关心绑定参数生成SQL,pojo对象结果映射,SQL的执行。事务是在连接层面的,不是它的职责,它只需在TransactionManager中获取到连接即可。

Spring如何管理事务?

        通过TransactionManager中ThreadLocal类型变量来保证多线程情况下,每一个线程所执行的操作在同一连接下。只需在业务逻辑前后进行事务操作即可。

        定义方法拦截器在业务方法被调用时拦截,通过注解和AOP将事务操作动态的添加到业务方法,注解用来标识需要进行事务操作的业务方法。而AOP通过cglib代理生成被代理方法的子类用继承的方式对事务进行增强。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值