Mybatis作爲一個ORM框架目前在企業級開發中使用之非常多,說到ORM框架Mybatis其實並不算一個完整的ORM框架這個在Mybatis文檔中也有說明,確實Mybtais只是實現了訪問數據庫的過程我們還是需要自己去寫sql語句,當然正是這種妙處使得Mybatis的靈活性非常大。SqlSessionFactory是mybatis中的重要組件,下面我們還是回到編程式使用mybatis的例子上面來,上一篇文章已經分析了Configuration對象的初始化過程了,初始化後將會根據Configuration對象生成SqlSessionFactory組件,下面將具體分析下過程。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="false"/>
</settings>
<typeAliases>
<typeAlias type="com.github.wenbo2018.dao.UserDao" alias="User"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/> <!--事務管理類型-->
<dataSource type="POOLED">
<property name="username" value="test"/>
<property name="password" value="123456"/>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.1.150/ssh_study"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="userMapper.xml"/>
</mappers>
</configuration>
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
session.close();
}
public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
這面代碼生成了SqlSessionFactory,可以看出默認的實現是DefaultSqlSessionFactory,SqlSessionFactory接口比較簡單主要是一些打開並獲取SqlSession的方法。默認使用下面方法:
SqlSession sqlSession = sqlSessionFactory.openSession();
最終調用的方法是:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
代碼中首先獲取到Environment信息,接口從環境Environment獲取到事務工廠TransactionFactory,默認Environment沒有事務工廠的會使用ManagedTransactionFactory,一般情況下直接使用mybatis會使用JDBC事務(暫時不考慮與Spring集成)。
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
這句代碼生成了通過事務工廠獲取到了一個事務這裏使用的是JDBC事務,
final Executor executor = configuration.newExecutor(tx, execType);這句代碼是生成一個Executor,Executor是mybatis的重要組件之一,是執行sql的重要部分,後續詳細分析,我們看看他是如何生成。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
executorType從前面可以看到默認使用的是ExecutorType.SIMPLE模式。故這裏執行的是executor = new SimpleExecutor(this, transaction);這句代碼,我們也可以通過以下方法來執行生成具體的Executor:
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
各種executor的區別這裏暫時不分析,後續詳細分析。如果cacheEnabled開關被打開的話會使用CachingExecutor,默認情況下cacheEnabled=false,故這裏使用的是SimpleExecutor。
executor = (Executor) interceptorChain.pluginAll(executor);
這句代碼是將executor注入的攔截器鏈中,之前分析過我們可以自己編寫插件這樣執行sql語句時會執行攔截調用。暫時不具體分析調用過程,初步看代代碼這裏使用了一個裝飾器模式。
final Executor executor = configuration.newExecutor(tx, execType);
這句代碼後得到的是SimpleExecutor,接着構造sqlsession,使用的是DefaultSqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
autoCommit這裏是false表明默認會數據庫會關閉自動提交和開啓事務,屬於一次性事務要麼成功要麼失敗,當前所有的操作都爲一個事務處理,若autoCommit=true會打開自動提交,一個條語句的執行失敗不會影響到其他語句。