1. 程式人生 > >Mybatis資料來源與連線池(一)介紹建立過程

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。

使用UnpooledDataSourcegetConnection(),每呼叫一次就會產生一個新的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例項。