mybatis Guice 事务源码解析
http://mybatis.org/guice/getting-started.html
https://blog.csdn.net/bingospunky/article/details/79541494
https://zhuanlan.zhihu.com/p/133807626?utm_source=wechat_session&utm_medium=social&utm_oi=1003056052560101376&utm_content=sec
在攻读了 mybatis-guice源码后,得以准确切入,制造事务代理:mybatis guice 事务代理切面



通过调试跟踪,guice-mybatis,整个过程最核心的,同数据源所有mapper生成mapperProxy对象各不相同,但在mapperProxyFactory.newInstance时都会在mapperProxy注入同一个sqlSessionManager --mapperProxyFactory.newInstance(sqlSessionManager) SqlSessionManager 实现了SqlSession,存在MapperProxy里面的sqlSession字段,后来在mybatis guice 事务代理切面中,我们用反射取之来操作事务
然后,就变成了:
mapper1/mapper2.xxx -> sqlSessionManager.xxx -> sqlSessionProxy.xxx -> sqlSessinManager.interceptor -> localSqlSession / openSession -> DefaultSqlSesion.xxx
与一般过程容易搞混:new DefaultSqlSession -> defaultSqlSession.getMapper(Mapper.class) -> mapperRegistry.getMapper(Mapper.class, defaultSqlSession) -> mapperProxyFactory.newInstance(defaultSqlSession) DefaultSqlSession 也实现了SqlSession
问题:
1 mybatis何时用事务con,何时用非事务con
2 SqlSession与Connection的对应关系
3 mybatis 事务是有传播,如何传播?
4 mapper的sqlSession被注入了一个sqlSessionManager?yet可能是mybatis guice框架干的,可结合mybatis-spring的干法
<dependency>
<groupId>com.digitalpetri.modbus</groupId>
<artifactId>modbus-master-tcp</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-guice</artifactId>
<version>3.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.inject/guice -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
public class Main {
public static void main(String []f) throws Exception {
// System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Properties myBatisProperties = new Properties();
myBatisProperties.setProperty("mybatis.environment.id", "test");
myBatisProperties.setProperty("JDBC.driver", "com.mysql.jdbc.Driver");
myBatisProperties.setProperty("JDBC.username", "root");
myBatisProperties.setProperty("JDBC.password", "memories");
myBatisProperties.setProperty("JDBC.url", "jdbc:mysql://127.0.0.1:53306/mytest");
myBatisProperties.setProperty("JDBC.autocommit", "true");
Injector injector = Guice.createInjector(
new MyBatisModule() {
@Override
protected void initialize() {
Names.bindProperties(binder(), myBatisProperties);
bindDataSourceProviderType(PooledDataSourceProvider.class);
// No implementation for org.apache.ibatis.transaction.TransactionFactory was bound.
bindTransactionFactoryType(JdbcTransactionFactory.class);
// bindTransactionInterceptors();
addMapperClass(MyMapper.class);
addMapperClass(MyMapper2.class);
}
});
SqlSessionFactory sessionFactory = injector.getInstance(SqlSessionFactory.class);
SqlSessionManager sessionManager = injector.getInstance(SqlSessionManager.class);
MyMapper myMapper = injector.getInstance(MyMapper.class);
MyMapper2 myMapper2 = injector.getInstance(MyMapper2.class);
// myMapper.list();
// myMapper2.list();
MyService myService = injector.getInstance(MyService.class);
// try {
// myService.insertTran();
// } catch (Exception e) {
// e.printStackTrace();
// }
// myService.insertNonTran();
myService.trannon();
}
结论:
1 在SqlSessionManager.SqlSessionInterceptor中,判断threadLocal中有无sqlSession
SqlSession sqlSession = (SqlSession)SqlSessionManager.this.localSqlSession.get();
if(sqlSession != null) {
try {
return method.invoke(sqlSession, args);
} catch (Throwable var19) {
throw ExceptionUtil.unwrapThrowable(var19);
}
} else {
SqlSession autoSqlSession = SqlSessionManager.this.openSession();
Throwable var6 = null;
Object var8;
try {
try {
Object t = method.invoke(autoSqlSession, args);
2
DefaultSqlSession-BaseExecutor-Transaction-Connection
一对一,值得注意的是Connection是个接口,本例就是com.mysql.jdbc.JDBC4Connection@2a62b5bc

resetAutoCommit 我们在myorm【重点】也吃过药
3 TransactionalMethodInterceptor中isSessionInherited,直接使用局部变量
boolean isSessionInherited = this.sqlSessionManager.isManagedSessionStarted();
public boolean isManagedSessionStarted() {
return this.localSqlSession.get() != null;
}
} finally {
if(!isSessionInherited) {
try {
if(needsRollback) {
if(this.log.isDebugEnabled()) {
this.log.debug(debugPrefix + " - SqlSession of thread: " + Thread.currentThread().getId() + " rolling back");
}
this.sqlSessionManager.rollback(true);
} else {
if(this.log.isDebugEnabled()) {
this.log.debug(debugPrefix + " - SqlSession of thread: " + Thread.currentThread().getId() + " committing");
}
this.sqlSessionManager.commit(transactional.force());
浙公网安备 33010602011771号