mybatis
Mybatis是一个orm框架,帮助我们更好的在java中编写和管理SQL语句
主要的运行过程:
- 主配置文件,配置mapper文件的位置,以及数据源,缓存,插件等配置信息,项目运行起来后会解析该文件,相关信息存储在Configuration对象中
- mapper文件,写sql,与mapper接口对应起来,实现sql和java代码分离,通过解析,会保存在Configuration对象中,key:全路径类名+方法名 ,value:MappedStatement对象,里面包含该方法sql的各种信息,二级缓存在该对象中
- sqlSession是主要的类,用来执行sql的增删改查,要生成它需要一个SqlSessionFactory工厂类,生产出来的sqlSession实现类DefaultSqlSession,其中一级缓存就是在这个类中
- sqlSession执行增删改查操作;也可以通过获取Mapper接口,通过接口来进行sql方法调用,获取到的Mapper接口是通过jdk的动态代理生成代理对象完成的,主要的动态代理逻辑在MapperProxy类中,然后通过调用sqlSession的增删改查方法进行sql执行。
- 下面介绍sqlSession的实现类DefaultSqlSession的select方法过程涉及到的重要类以及过程
- Executor:SqlSessionFactory的openSession在创建Executor的时候会把插件对应的拦截了该类中的方法进行动态代理,完成增强,该执行器的作用是生成sql语句(**MappedStatement 中的语句生成工具 **通过xml中写的sql是否有需要填充属性的分为动态sql和原始sql),以及一二级缓存的获取和更新,在这里通过Transaction获取数据库连接
- StatementHandler:也可以通过插件 进行拦截的方法,会创建ResultSetHandler和ParameterHandler;然后通过connection创建生成jdbc的PreparedStatement,然后调用parameterHandler填充参数
- ParameterHandler:使用paredStatement的setxxxx方法填充参数,在填充的时候要知道要填充的数据类型对应sql的数据类型,好调用对应的paredStatement的setxxx方法,这个时候需要TypeHandler的各种类型的实现,来调用paredStatement.setxxx方法
- 最后执行paredStatement.execute(sql)
- ResultSetHandler:处理执行后返回的jdbc的ResultSet,这里也需要TypeHandler处理数据库类型和java类型对应起来,调用对应的实现类的方法,设置给对应的java对象的属性
mybatis-spring
mapper对象注入IOC容器
- 通过
**@MapperScan**
注解导入MapperScannerRegistrar(实现ImportBeanDefinitionRegistrar)->MapperScannerConfigurer(实现的BeanDefinitionRegistryPostProcessor)->**ClassPathMapperScanner#doScan**
要扫描所有的mapper接口,beandefinition改成MapperFactoryBean的class,设置MapperFactoryBean的各种属性,比如:当前mapper接口的的全路径类名,SqlSessionTemplate对象 - MapperFactoryBean:这是实现了FactoryBean接口,getObject中通过sqlSession#getMapper获取到对应Mapper的动态代理后的对象, 每个Mapper接口都有一个MapperFactoryBean
sqlSessionTemplate:
- 里面通过动态代理SqlSessionInterceptor,修改获取SqlSession的逻辑,主要是为了同一个事务线程中可以共用sqlSession,存储在threadLocal中。同时注入几个事务状态感知钩子类(通过TransactionSynchronizationManager.registerSynchronization())
- 真正干活的sqlSession还是通过SqlSessionFactory生成DeFaultSqlSession。
mybatis-spring和spring事务
在mybatis中,负责事务处理的接口是Transaction(里面设置数据源);主要功能用来获取连接,事务提交和回滚
mybatis和spring整合后不会连接获取和进行提交事务,统一交给spring jdbc中的事务处理。
通过实现了mybatis中Transaction接口的SpringManagedTransaction类,该类中的获取连接又调用spring-jdbc中的工具获取,同时通过isConnectionTransactional属性控制不能再该类中进行提交和回滚,统一把这些回滚和提交工作交给spring事务框架。
spring事务处理大致流程:
- 通过TransactionInterceptor拦截器拦截目标方法
- 通过DataSourceTransactionManager获取事务,主要获取数据库连接资源并绑定到当前线程中的(TransactionSynchronizationManager),以及参数设置,read only参数会执行sql.
- 存储当前事务信息到TransactionInfo.oldTransactionInfo中,事务传播的时候需要
- 执行mapper的方法。MapperProxy代理(mybatis-plus中是MybatisMapperProxy); sqlSession是SqlSessionTemplate->SqlSessionInterceptor(动态代理,会通过sqlsession工厂获取sqlSession,并且作为资源绑定到当前线程中,所以同一个事务中可以使用一级缓存)
- 提交或者回滚事务
- 提交事务
- triggerBeforeCommit :触发TransactionSynchronization#beforeCommit, 重要实现:mybatis-spring整合中有个SqlSessionUtils.SqlSessionSynchronization.beforeCommit,会执行sqlSession的commit,并不会在这里提交事务(因为事务管理使用了SpringManagedTransaction),只是刷掉sqlSession的缓存等
- triggerBeforeCompletion:触发触发TransactionSynchronization#beforeCompletion ,重要实现:mybatis-spring整合中有个SqlSessionUtils.SqlSessionSynchronization.beforeCompletion,会执行sqlSession.close方法,关闭sqlSession
- 传播级别嵌套事务的时候,子事务执行的时候,如果有回滚点,释放掉回滚点
- 事务执行提交操作,connection.commit()
- TransactionSynchronization.afterCommit
- 释放资源,数据库连接资源
TransactionSynchronizationManager
:管理线程中的事务状态,以及事务资源在线程中的绑定,比如:数据库连接
ResourceHolderSupport
:事务中的资源通过该基类,他实现了通过计数方式看当前是否释放资源 ,比如:ConnectionHolder,SqlSessionHolder
TransactionSynchronization
: 可以实现钩子函数,在事务执行各个状态可以感知到
事务挂起:就是保留现有的连接,参数信息,等资源,用对象保存起来。然后清空当前线程的资源,重新获取连接