1. 程式人生 > 實用技巧 >什麼是泛型?,Set集合,TreeSet集合自然排序和比較器排序,資料結構-二叉樹,資料結構-平衡二叉樹

什麼是泛型?,Set集合,TreeSet集合自然排序和比較器排序,資料結構-二叉樹,資料結構-平衡二叉樹

1.SqlSession和SqlSessionFactory的介面定義

SqlSession:

publicinterfaceSqlSessionextendsCloseable{
<T>TselectOne(Stringvar1);
<T>TselectOne(Stringvar1,Objectvar2);
<E>List<E>selectList(Stringvar1);
<E>List<E>selectList(Stringvar1,Objectvar2);
<E>List<E>selectList(Stringvar1,Objectvar2,RowBoundsvar3);
<K,V>Map<K,V>selectMap(Stringvar1,Stringvar2);
<K,V>Map<K,V>selectMap(Stringvar1,Objectvar2,Stringvar3);
<K,V>Map<K,V>selectMap(Stringvar1,Objectvar2,Stringvar3,RowBoundsvar4);
voidselect(Stringvar1,Objectvar2,ResultHandlervar3);
voidselect(Stringvar1,ResultHandlervar2);
voidselect(Stringvar1,Objectvar2,RowBoundsvar3,ResultHandlervar4);
intinsert(Stringvar1);
intinsert(Stringvar1,Objectvar2);
intupdate(Stringvar1);
intupdate(Stringvar1,Objectvar2);
intdelete(Stringvar1);
intdelete(Stringvar1,Objectvar2);
voidcommit();
voidcommit(booleanvar1);
voidrollback();
voidrollback(booleanvar1);
List<BatchResult>flushStatements();
voidclose();
voidclearCache();
ConfigurationgetConfiguration();
<T>TgetMapper(Class<T>var1);
ConnectiongetConnection();
}

SqlSession,資料庫的C、R、U、D及事務處理介面,你懂的。

SqlSessionFactory:

publicinterfaceSqlSessionFactory{
SqlSessionopenSession();
SqlSessionopenSession(booleanvar1);
SqlSessionopenSession(Connectionvar1);
SqlSessionopenSession(TransactionIsolationLevelvar1);
SqlSessionopenSession(ExecutorTypevar1);
SqlSessionopenSession(ExecutorTypevar1,booleanvar2);
SqlSessionopenSession(ExecutorTypevar1,TransactionIsolationLevelvar2);
SqlSessionopenSession(ExecutorTypevar1,Connectionvar2);
ConfigurationgetConfiguration();
}

不解釋,你懂的。

2. SqlSession和SqlSessionFactory的類結構圖

(Made In Intellij Idea IDE)

SqlSession實現類:DefaultSqlSession和SqlSessionManager

SqlSessionFactory實現類:DefaultSqlSessionFactory和SqlSessionManager

3.DefaultSqlSession和DefaultSqlSessionFactory原始碼分析

org.apache.ibatis.session.defaults.DefaultSqlSession.java部分原始碼:

privateConfigurationconfiguration;
privateExecutorexecutor;

@Override
publicvoidselect(Stringstatement,Objectparameter,RowBoundsrowBounds,ResultHandlerhandler){
try{
MappedStatementms=configuration.getMappedStatement(statement);
executor.query(ms,wrapCollection(parameter),rowBounds,handler);
}catch(Exceptione){
throwExceptionFactory.wrapException("Errorqueryingdatabase.Cause:"+e,e);
}finally{
ErrorContext.instance().reset();
}
}

@Override
publicintupdate(Stringstatement,Objectparameter){
try{
dirty=true;
MappedStatementms=configuration.getMappedStatement(statement);
returnexecutor.update(ms,wrapCollection(parameter));
}catch(Exceptione){
throwExceptionFactory.wrapException("Errorupdatingdatabase.Cause:"+e,e);
}finally{
ErrorContext.instance().reset();
}
}

總結:似乎一切的一切,都是從配置物件Configuration中取出材料來,委託給執行器Executor去處理。

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.java部分原始碼:

publicclassDefaultSqlSessionFactoryimplementsSqlSessionFactory{

privatefinalConfigurationconfiguration;

publicDefaultSqlSessionFactory(Configurationconfiguration){
this.configuration=configuration;
}
privateSqlSessionopenSessionFromDataSource(ExecutorTypeexecType,TransactionIsolationLevellevel,booleanautoCommit){
Transactiontx=null;
try{
finalEnvironmentenvironment=configuration.getEnvironment();
finalTransactionFactorytransactionFactory=getTransactionFactoryFromEnvironment(environment);
tx=transactionFactory.newTransaction(environment.getDataSource(),level,autoCommit);
finalExecutorexecutor=configuration.newExecutor(tx,execType);
returnnewDefaultSqlSession(configuration,executor,autoCommit);
}catch(Exceptione){
closeTransaction(tx);//mayhavefetchedaconnectionsoletscallclose()
throwExceptionFactory.wrapException("Erroropeningsession.Cause:"+e,e);
}finally{
ErrorContext.instance().reset();
}
}
//...

建立一個DefaultSqlSession並返回,這裡出現了那個貫穿Mybatis執行流程的Executor介面,非常重要的介面,後續會對其進行仔細分析。

4.SqlSessionManager原始碼分析(重點)

SqlSessionManager同時實現了SqlSession和SqlSessionFactory介面。

org.apache.ibatis.session.SqlSessionManager.java部分原始碼。

publicclassSqlSessionManagerimplementsSqlSessionFactory,SqlSession{

privatefinalSqlSessionFactorysqlSessionFactory;
//proxy
privatefinalSqlSessionsqlSessionProxy;
//保持執行緒區域性變數SqlSession的地方
privateThreadLocal<SqlSession>localSqlSession=newThreadLocal<SqlSession>();

privateSqlSessionManager(SqlSessionFactorysqlSessionFactory){
this.sqlSessionFactory=sqlSessionFactory;
//這個proxy是重點
this.sqlSessionProxy=(SqlSession)Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
newClass[]{SqlSession.class},
newSqlSessionInterceptor());
}

publicstaticSqlSessionManagernewInstance(Readerreader){
returnnewSqlSessionManager(newSqlSessionFactoryBuilder().build(reader,null,null));
}

publicstaticSqlSessionManagernewInstance(Readerreader,Stringenvironment){
returnnewSqlSessionManager(newSqlSessionFactoryBuilder().build(reader,environment,null));
}
//...
//設定執行緒區域性變數sqlSession的方法
publicvoidstartManagedSession(){
this.localSqlSession.set(openSession());
}

publicvoidstartManagedSession(booleanautoCommit){
this.localSqlSession.set(openSession(autoCommit));
}
//...
@Override
public<T>TselectOne(Stringstatement,Objectparameter){
returnsqlSessionProxy.<T>selectOne(statement,parameter);
}

@Override
public<K,V>Map<K,V>selectMap(Stringstatement,StringmapKey){
returnsqlSessionProxy.<K,V>selectMap(statement,mapKey);
}
//...

變數sqlSessionFactory:相當於DefaultSqlSessionFactory的例項(不是proxy)。

變數sqlSessionProxy:是JDK動態代理出來的proxy(是proxy)。

動態代理的目的,是為了通過攔截器InvocationHandler,增強目標target的方法呼叫。

target:DefaultSqlSession的例項。

所有的呼叫sqlSessionProxy代理物件的C、R、U、D及事務方法,都將經過SqlSessionInterceptor攔截器,並最終由目標物件target實際完成資料庫操作。

org.apache.ibatis.session.SqlSessionInterceptor.java的原始碼。

privateclassSqlSessionInterceptorimplementsInvocationHandler{
publicSqlSessionInterceptor(){
//PreventSyntheticAccess
}

@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
finalSqlSessionsqlSession=SqlSessionManager.this.localSqlSession.get();
if(sqlSession!=null){
try{
//1、存線上程區域性變數sqlSession(不提交、不回滾、不關閉,可線上程生命週期內,自定義sqlSession的提交、回滾、關閉時機,達到複用sqlSession的效果)
returnmethod.invoke(sqlSession,args);
}catch(Throwablet){
throwExceptionUtil.unwrapThrowable(t);
}
}else{
//2、不存線上程區域性變數sqlSession,建立一個自動提交、回滾、關閉的SqlSession(提交、回滾、關閉,將sqlSession的生命週期完全限定在方法內部)
finalSqlSessionautoSqlSession=openSession();
try{
finalObjectresult=method.invoke(autoSqlSession,args);
autoSqlSession.commit();
returnresult;
}catch(Throwablet){
autoSqlSession.rollback();
throwExceptionUtil.unwrapThrowable(t);
}finally{
autoSqlSession.close();
}
}
}
}

注意:SqlSession的生命週期,必須嚴格限制在方法內部或者request範圍(也稱之為Thread範圍),執行緒不安全,執行緒之間不能共享。(官方文件有明確說明)

1、request範圍使用SqlSession

sqlSessionManager.startManagedSession();
try{
sqlSessionManager.query1();
sqlSessionManager.query2();
sqlSessionManager.update1();
sqlSessionManager.update2();
//...
}catch(Throwablet){
sqlSessionManager.rollback();
}finally{
sqlSessionManager.close();
}

一次性執行了一系列的方法業務,最後統一異常回滾,統一關閉sqlSession,全程建立1次sqlSession,銷燬1次sqlSession。只是個例子,具體如何使用執行緒本地變數sqlSession,完全取決於你自己。

2、method範圍使用SqlSession

SqlSessionManager.query1();
SqlSessionManager.query2();

以上虛擬碼,各自分別開啟了一個SqlSession,並銷燬了各自的SqlSession。即,建立了2次SqlSession,銷燬了2次SqlSession。

注:SqlSessionManager似乎是廢棄不使用的了,但是,它並不妨礙我們探究其原始碼

原文:https://my.oschina.net/zudajun/blog/665956