基于上篇的示例感受,下面我們探索下MyBatis連接數據庫的細節是如果實現的,在日常使用中是如何能和Druid數據庫連接池等配合起來的
基于上篇的示例代碼:
public class MybatisTest {@Testpublic void test() {try(SqlSession session = buildSqlSessionFactory().openSession()) {PersonMapper personMapper = session.getMapper(PersonMapper.class);personMapper.createTable();personMapper.save(Person.builder().id(1L).name("1").build());Person person = personMapper.getPersonById(1);System.out.println(person);}}public static SqlSessionFactory buildSqlSessionFactory() {String JDBC_DRIVER = "org.h2.Driver";String DB_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";String USER = "sa";String PASS = "";DataSource dataSource = new PooledDataSource(JDBC_DRIVER, DB_URL, USER, PASS);Environment environment = new Environment("Development", new JdbcTransactionFactory(), dataSource);Configuration configuration = new Configuration(environment);configuration.addMapper(PersonMapper.class);SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();return builder.build(configuration);}
}
當前我們想找的是與數據庫建立連接的部分
通過閱讀書籍:《MyBatis3源碼深度解析》,我們大概知道執行是在Executor中,我們跟蹤相關的代碼
經過不懈的努力跟蹤,得到下面的關鍵代碼:
找到了在執行語句中,在Executor中獲取連接的關鍵代碼
public class SimpleExecutor extends BaseExecutor {private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {// 獲取數據庫連接Connection connection = this.getConnection(statementLog);Statement stmt = handler.prepare(connection, this.transaction.getTimeout());handler.parameterize(stmt);return stmt;}
}
繼續跟蹤,來到我們示例中定義的事務管理器:JdbcTransactionFactory
public class JdbcTransaction implements Transaction {public Connection getConnection() throws SQLException {if (this.connection == null) {this.openConnection();}return this.connection;}protected void openConnection() throws SQLException {if (log.isDebugEnabled()) {log.debug("Opening JDBC Connection");}// 從DataSource中獲取this.connection = this.dataSource.getConnection();if (this.level != null) {this.connection.setTransactionIsolation(this.level.getLevel());}this.setDesiredAutoCommit(this.autoCommit);}
}
上面可以看到是從DataSource中獲取的,來到我們定義的:PooledDataSource
public class PooledDataSource implements DataSource {public Connection getConnection() throws SQLException {return this.popConnection(this.dataSource.getUsername(), this.dataSource.getPassword()).getProxyConnection();}private PooledConnection popConnection(String username, String password) throws SQLException {while(conn == null) {synchronized(this.state) {PoolState var10000;if (!this.state.idleConnections.isEmpty()) {......} else if (this.state.activeConnections.size() < this.poolMaximumActiveConnections) {// 獲取數據庫連接池連接conn = new PooledConnection(this.dataSource.getConnection(), this);if (log.isDebugEnabled()) {log.debug("Created connection " + conn.getRealHashCode() + ".");}} else {......}if (conn != null) {......}}}......}
}
我們繼續跟下去:
public class UnpooledDataSource implements DataSource {public Connection getConnection() throws SQLException {return this.doGetConnection(this.username, this.password);}private Connection doGetConnection(String username, String password) throws SQLException {Properties props = new Properties();if (this.driverProperties != null) {props.putAll(this.driverProperties);}if (username != null) {props.setProperty("user", username);}if (password != null) {props.setProperty("password", password);}return this.doGetConnection(props);}private Connection doGetConnection(Properties properties) throws SQLException {this.initializeDriver();// 看到了熟悉的原生的獲取數據庫連接的方式Connection connection = DriverManager.getConnection(this.url, properties);this.configureConnection(connection);return connection;}
}
到這里我們找到了源碼中如何獲取數據庫連接的關鍵代碼
其實就是對于原生數據庫操作的封裝
我們回過頭來看看整個過程中的類調用棧:
可以看到數據庫連接是從DataSource中獲取的,而PooledDataSource是MyBatis自己的一個數據庫連接池,其中使用非池化的UnpooledDataSource
在我們的日常開發中,經常使用MyBatis+Druid等數據庫連接池一起使用,從這里就可以看到,我們簡單替換一下MyBatis初始化時候的DataSource即可
本篇中,我們跟蹤了數據庫如何進行連接獲取,看到日常開發中MyBatis+Druid等數據庫連接的配置使用的背后原理
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态