Aop与jdbc事务与mybatis,配合工作源码解析

Aop与jdbc事务与mybatis,配合工作源码解析

[.(spring和mybatis配合出现mybatis一级缓存失效的问题)]:

1.主要分析的内容

1.spring的jdbc的事务设计(简单的设想)
2.mybatis的一级缓存,二级缓存.(源码大致讲述,后期会着重使用以及与其他工具的配合)
3.aop工作和mybatis配合工作,mybatis一级缓存失效问题.

2.spring的jdbc的事务设计+mybatis

2.1如果自己实现这部分,需要考虑的点.

(在查看源码的时候,可以一一验证自己的猜想,如果确实猜想正确,看看对方是如何设计的)

●满足数据库设计的acid.

●连接connection,实现一个事务隔离,数据库通过这个连接,也实现库内对数据进行的事务的控制.(一个connection,线程级别)

●如果是mybatis(一定有他的连接池),来操控jdbc,他应该实现什么.
    ●连接池中的连接,在连接使用的使用,必须是单独使用,和其他的事务进行隔离,只有事务结束的时候,连接才能复用(清空事务,等其他连接数据).--一个连接,一个事务.
    ●考虑一个问题,在多线程环境中,进行连接的复用,是否会出现线程安全的问题.相当于 getConnection()这个阶段,(只要这个方法,不被同时获得,就可以了).
    
●考虑,sqlsession和连接(connection)的关系,和事务的关系-------首先,connection和事务应该一一对应.sqlsession是一个mybatis的一个特殊载体工具.
    ==>他提供,缓存,连接,配置,mapper等一系列信息.
    ==>发现他的缓存功能,在excutor里面的PerpetualCache一个map来实现的,他不是线程安全的.
                -->这里有一个问题,为什么不把PerpetualCache一级缓存设计成线程安全的,加threadLocal那种.
                -->设计sqlsession,单例,那么配置,连接,mapper等等信息,都变成了多线程环境的共享数据了,
                -->所以不仅仅是缓存有线程安全问题,其他数据也有线程安全的问题
    ==>所以在使用sqlsession的时候,需要考虑他的线程安全性,所以sqlsession的使用就是和线程绑定的.
    		   -->这里看到他的两种设计方案,思路都是和线程绑定.只不过用了不同的事务管理器.
    		   -->spring使用trasanctionSynchronizeManager(提供线程安全)+
    		   -->defaultSqlSessoin(本身线程不安全),
    		   -->单独使用mybatis的话,使用SqlSessionManager(线程安全)
    ==>在翻看代码的时候,并没有发现sqlsession和connection有什么直接关系
    ==>有待解决==>暂时看到的.sqlsession将事务交给事务管理器,根据创建的事务管理器而定,他自己本身就不处理事务了   
●那么连接池,应该和sqlsession进行解耦.由连接池,单独控制connection的获得,而sqlsession只是单独调用连接池. 
    ==>这部分,和aop进行配合的时候,拦截器进行打开连接,并且将事务信息,连接信息保存在了事务管理器中transactionsynchronizeManager中.连接池怎么交互,没仔细看
●事务和线程关系.
一个线程调用里面,可能有多个事务,也就是切面套切面,那么在处理各个切面关系之间的关系(事务传播),
就要根据具体情况做相应的措施.(比如挂起上一个事务,提交的时机,是否创建新事务等等)
●事务和connection的关系:一一对应,如果是一个线程里面有多个事务,那就是切面代码,来解决这期间的关系.(配合线程,因为线程相当于一个人为"大事务")
●事务和sqlsession的关系:
由spring的aop和mybatis的工作原理可知,
		  ==>我在执行器中看到了一对一的事务,并且看到执行之后,清空执行器(清空sqlsession绑定的连接)
		   ==>或者在aop开始的时候就获得transaction,然后进行管理.后续创新sqlsession,也用的一个事务.
           ==>所以,代码设计到最后,就是解决,各个组件中的配合关系,先搞清楚各个组件的工作原理,然后设计逻辑(易于管理,开发,代码扩展),代码设计.

2.2.具体代码走的过程.

写一段异常代码,通过堆栈信息,可以看出,先整体通过拦截器链,第一层是trasactionIntercept (通过判断指针(索引)控制他第一个(切面)拦截器) 开启事务,在依次执行其他拦截器链,方法,在依次返回到最外面.

 执行过程如下 :     
         事务拦截器  TransactionInterceptor;保存了事务属性信息,事务管理器; 同时它是一个MethodInterceptor;
               在目标方法执行的时候;
                   执行拦截器链invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
                   事务拦截器:
               1.先获取事务相关属性
               2.再获取PlatformTranactionManager,如果没有先添加指定任何PlatformTranactionManager,最终会从容器中按照类型获取一个PlatformTranactionManager
               3.开启事务  
               4.执行目标方法(执行其他拦截器==>执行目标代码(你的service内容))invocation.proceedWithInvocation
               5. 如果异常,获取到事务管理器,利用事务管理器回滚操作;
                如果正常,利用事务提交,进行提交.

在这里插入图片描述

1.以上是老版本的spring-mybatis 包下的,事务工作的大致时序图.
2.我看的springboot 2.0 以上版本,加上1.3.2的mybatis.具体代码中的属性内容和上面图可能有出入.
我不太会画uml图,这是别人的图,基本可以知道大致的内容

2.3图解,mybatis,spring事务,aop的关系

在这里插入图片描述

在这里插入图片描述

1.这里需要解释一下,这只是spring业务代码,抽象出来的一个图.以后如果有条件了,理解了更深的业务,会把他变成一个更容易理解的时序图.

3.mybatis的一级缓存,二级缓存.(源码大致讲述,后期会着重使用以及与其他工具的配合)

关于mybatis的一级缓存二级缓存
功能:实现缓存.
工作原理:当都开启的时候,二者的关系类似委托关系,二级没有就找一,一没有查数据库.(委托机制,类似于类加载器的双亲委托机制?)
●一级缓存设计
实现原理:mybatis是通过执行器Excutor中的hashmap 来实现缓存. 既然是缓存数据就得考虑到线程安全问题. 
一级缓存的线程安全问题:
	●使用defaultsqlsession(单独使用这个回有线程安全问题),配合spring使用,sqlsession绑定在一个sqlsessionholder对象里,这个对象与threadlocal绑定==>
所以也是线程安全的
	●使用sqlsessionManager,里面通过threadlocal对象控制sqlsession线程安全(与线程绑定,所以不会出现线程安全问题)
二级缓存的线程安全问题:
不同于一级缓存,他是sqlsesison级别的缓存,所以就是线程级别的缓存.二级缓存相当于全局缓存,以namespace为存储单元.
●二级缓存设计
   ●所以只要控制在namespace级别的cache,线程安全即可.因为cache数据的特殊性.所以使用readwirteLock 锁.来实现  get put  clear 之间的线程安全
   ●锁的范围是cache对象(cache和nammespace对应).
   ●缓存处理器(执行器ExcutorExcutor)来统一控制锁,控制数据的安全性(cache当参数传进来,统一管理即可.)
   ●在加载的时候,根据参数,构造合适excutor   构建者模式ok.构建缓存,各种参数,以及构建各种委托类.(拼装)
注:
   ●cache的处理算法,有好多种,默认的是lru. 当达到0.75*(设定的size)的时候,删除使用次数最少的key     这是他的数据结构  LinkedHashMap  好你妹复杂啊

4.aop工作和mybatis配合工作,mybatis一级缓存失效问题.

1.查看springboot2.0+mybatis1.3 的源码实现后.发现了mybatis一级缓存失效.
    ●原因:在aop执行完代码之后,会清理transactionSynchronizeMnager里面的一些属性信息,其中就包括了,持有sqlSession的 Transactional resources.==>就相当于,清除了该线程内的sqlsession对象.==>那么下一轮(nio模式)在执行mybatis的代码的时候,获取不到sqlsesion,那么就得重新创建.==>有因为,一级缓存是存放在excutor里面,所以一级缓存失效.

解决办法: 不详!!!

原因分析:
可能的原因:
●因为aop工作的代码,需要处理太多的事务,如果这个resources,不清理,就会影响下一轮该线程下的事务信息.所以选择清理.
●如果能在sqlsesison使用后,清除干净掉sqlsession绑定的事务信息(里面有一些参数属性).每次都相当于有事务提交,而单独使用sqlsession,如果出现update,insert等都会出现清空缓存的问题,如果这里,spring提交的时候,在判断一下,是否需要清空缓存,会不会有一些小题大做???
●如果挑好合适的jar包,能让sqlsessoin使用的时候,找到事务信息,并且在aop结束的时候,能够准确判断,是否需要清空缓存??




缓存问题的解决办法:
●查询的问题,api,单独交给sqlsession,貌似不可取,因为在spring的切面内,除非配置一下事务传播特性.
就是单独使用线程安全的mybatis,那该线程内,还是会出现事务信息,还是和spring的aop 有耦合. aop执行之后,还是可能清空一些数据.......我头疼.(sqlsession,不委托spring处理事务????)
●看看有没有其他工具,提供实现缓存的思路,并且和spring的aop能够配合工作.

●那么这里还有其他办法,解决缓存的问题吗???  springboot,使用的时候,推荐配合使用springDataJpa,里面有提供缓存. 这里没有去测试.也没有去看源码,有空继续研究.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值