Mybatis資料來源與連線池(一)介紹建立過程
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">小白學習技術,總會遇到各種新知識撲面而來,而未曾深究過的尷尬局面,比如從一開始自學Servlet,JDBC的時候就碰到過資料來源和連線池的概念,只是懵懂理解為資料庫就是資料來源,連線池可以提高效能,節省應用程式與資料庫連線的建立與釋放的時間。最近看到一篇部落格說ORM框架中資料來源的組織直接影響到框架的效能問題,也就是說資料來源的組織工作是在框架中完成的,而不是資料庫本身完成的。下面的主要內容也基本上是參考前輩的部落格然後實際操作完成的。我們下載MyBatis的jar包和原始碼jar包,發現關於資料來源DataSource的package:org.apache.itbtis.datasource。</span>
個人感覺不管是怎麼樣,應該都要經歷我們最初學的JDBC程式碼,建立連線Connection
,建立Statement或者PreparedStatement等操作。只是一些技術把這些封裝好了。
上圖其中的unpooled是不使用連線池的資料來源,pooled是使用連線池的資料來源,jndi是使用JNDI實現的資料來源,它是通過JNDI上下文中取值。
而且還看到了熟悉的MyBatis定義的抽象工廠介面:org.apache.ibatis.datasource.DataSourceFactory,又是通過工廠模式建立資料來源DataSource物件的,對於我們這種小白,都還不清楚工廠模式到底有什麼好處,只知道用來建立物件。
通過看MyBatis的官方文件的入門介紹的mybatis配置檔案程式碼:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org/dtd/mybatis-3-config.dtd" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <enviroment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </enviroment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml" /> </mappers> </configuration>
它是使用dataSource元素配置資料來源,DataSource物件的建立發生在MyBatis初始化的過程中。
其中type屬性根據上面介紹推敲出可以設定三個值:
【1】POOLED MyBatis會建立PooledDataSource例項
【2】UNPOOLED MyBatis會建立UnpooledDataSource例項
【3】JNDI MyBatis會從JNDI服務上查詢DataSource例項,然後返回使用
MyBatis在初始化時,會解析MyBatis配置檔案,根據dataSource元素的type屬性建立相應型別的資料來源DataSource。這裡有個疑問:三種類型的資料來源到底有什麼區別??
MyBatis是通過工廠模式建立資料來源DataSource物件的。
抽象工廠介面org.apache.ibatis.datasource.DataSourceFactory很簡單:
通過它的getDataSource()方法返回資料來源DataSOurce
MyBatis建立了DataSource例項後,會將其放到Configuration物件內的Environment物件中, 供以後使用。這一點正如MyBatis官方文件中介紹的通過程式碼方式建立SqlSessionFactory
那DataSource什麼時候建立Connection物件給我們用呢?使我們需要的時候才會建立,也就是說我們要執行SQL語句的時候才會建立。比如以下程式碼:
String resource = "mybatis-config.xml";
Reader reader = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.selectList("SELECT * FROM STUDENTS");
只當當執行sqlSession.selectList的時候才會建立Connection物件protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommmit);
}
上面介紹的是使用連線池的資料來源物件,那UNPOOLED的呢?同樣的步驟:
MyBatis首先會例項化一個UnpooledDataSourceFactory工廠例項,然後通過.getDataSource()方法返回一個UnpooledDataSource例項物件引用,我們假定為dataSource。
使用UnpooledDataSource的getConnection(),每呼叫一次就會產生一個新的Connection例項物件。
UnPooledDataSource的getConnection()方法實現如下:
/*
UnpooledDataSource的getConnection()實現
*/
public Connection getConnection() throws SQLException
{
return doGetConnection(username, password);
}
private Connection doGetConnection(String username, String password) throws SQLException
{
//封裝username和password成properties
Properties props = new Properties();
if (driverProperties != null)
{
props.putAll(driverProperties);
}
if (username != null)
{
props.setProperty("user", username);
}
if (password != null)
{
props.setProperty("password", password);
}
return doGetConnection(props);
}
/*
* 獲取資料連線
*/
private Connection doGetConnection(Properties properties) throws SQLException
{
//1.初始化驅動
initializeDriver();
//2.從DriverManager中獲取連線,獲取新的Connection物件
Connection connection = DriverManager.getConnection(url, properties);
//3.配置connection屬性 :例如是否自動提交autoCommit和隔離級別isolationLevel
configureConnection(connection);
return connection;
}
本質就是我們平時寫的最普通的JDBC程式碼
總結:從上述的程式碼中可以看到,我們每呼叫一次getConnection()方法,都會通過DriverManager.getConnection()返回新的java.sql.Connection例項。