1. mybatis (SqlSessionTemplate)的动态代理
a) sqlSession的结构
b)SqlSession 结构
public class SqlSessionTemplate implements SqlSession {
//代理对象 ------1
private final SqlSession sqlSessionProxy;
/**
*//构造方法 --------2
*/
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
//利用jdk的动态代理,生成sqlSessionProxy的代理对象--------3
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
} /**
*/
@Override
public <T> T selectOne(String statement) {
//代用代理对象的目标方法,触发代理对象的产生---------4
return this.sqlSessionProxy.<T> selectOne(statement);
} /**
*/
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
//代理对象执行,实际上执行的是sqlSession的目标方法,proxy没有执行--------5
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
} }
2.没有事务:切换数据源(成功切换数据源)
a)代理对象执行目标时,切换数据源时 (栈结构)
b) 在DataSourceUtils 中,判断conHolder是否为空,
3.存在事务:切换数据源(不会切换数据源)
a) 在执行目标方式时,被spring拦截,检查是否存在事务,(存在事务,调用doBegin方法,为事务准备链接conncetion)
b) 代理对象sqlSessionTemple 执行目标方法中,在DataSourceUtils 中判断connection 已经存在,则直接拿取