1. 程式人生 > >ibatis 3 學習筆記 2

ibatis 3 學習筆記 2

上篇簡單除錯了一個例項,現在仔細看看ibatis 3 user guide上的內容,接下來的幾篇準備整理user guide上的內容,最後通過一個綜合的例子來實踐。

關於實體對映檔案中namespace,以前的版本是可選的內容,現在被用來與介面繫結,也就是說把介面的實現轉移到xml檔案中來了,以後的維護會相當的方便。

第一篇的根據id查詢學生的例子中,稍做修改:
建立StudentDAO介面
package cn.pf.ibatis.dao;

import java.util.List;

import cn.pf.ibatis.domain.Student;

/**
* StudentDAO介面
* @author  pf
* @version 2010-3-16下午03:05:36
*/


public interface StudentDAO {
public Student queryStudentById(int id);
}

更改 student.xml中的mapper元素namespace屬性


test.java中呼叫改為

Student student;
StudentDAO studentDAO = session.getMapper(StudentDAO.class);
try{
//student = (Student)session.selectOne("cn.pf.ibatis.domain.StudentMapper.selectStudent", 1);

student = studentDAO.queryStudentById(1);
}finally{
session.close();
}

System.out.println(student.toString());

生命週期

SqlSessionFactoryBuilder:
用於建立SqlSessionFactory的工具類,在建立SqlSessionFactory以後無需再讓它存在於應用程式中,文件上說它的生命週期最好在區域性方法內,所以在程式碼中看到
//根據資原始檔內容建立session工廠
SqlSessionFactory sqlMapper = new

SqlSessionFactoryBuilder().build(reader);
沒用引用指向SqlSessionFactoryBuilder,會被gc回收。

SqlSessionFactory:
一旦建立,SqlSessionFactory就應該存在於整個應用程式生命週期,因為根據資原始檔建立SqlSessionFactory物件需要很大的開銷,所以保留在整個應用的生命週期中,最佳實踐中推薦使用spring等依賴注入的框架從而管理SqlSessionFactory的單例生命週期。

SqlSession:
每一個執行緒都應該有自己的SqlSession物件,SqlSession物件不是執行緒安全的所以不應該被共享,如果使用web框架,應該將SqlSession的生命週期看作HTTP Request的生命週期,在返回HTTP Response的時候關閉SqlSession

SqlSession session = sqlSessionFactory.openSession();
try {
    // do work
} finally {
    session.close();
}

Mapper Instances:
Mapper Instances是繫結ibatis對映檔案實現的介面,Mapper Instances的生命週期應該與SqlSession一樣,但是Mapper Instances最好在一個方法中被建立,在方法結束時被銷燬。

SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
// do work
} finally {
session.close();
}


配置檔案

配置檔案的層次結構如下:
• configuration
    o properties
    o settings
    o typeAliases
    o typeHandlers
    o objectFactory
    o plugins
    o environments
     environment
          • transactionManager
          • dataSource
    o mappers

1 properties:
用來定義外部properties配置檔案資訊。比如
<properties resource="org/apache/ibatis/example/config.properties">
    <property name="username" value="dev_user"/>
    <property name="password" value="F2Fa3!33TYyg"/>
properties>

<dataSource type="POOLED">
    <property name="driver" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
dataSource>

那麼username和password被替換成dev_user和F2Fa3!33TYyg,而drive和url屬性將讀取config.properties中的內容從而取得具體值

properties還可以通過SqlSessionFactoryBuilder的build方法作為引數傳入:

SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props);
// ... or ...
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);

property載入順序:
1、properties元素內部
2、外部properties檔案
3、SqlSessionFactoryBuilder的build方法引數
也就是說,build方法引數中的properties優先順序高於前兩個,因為它是最後被載入,所以會覆蓋前兩種載入方法載入的properties值。

2 settings

Setting 描述 合法值 預設值
cacheEnabled 是否使用全域性快取 true|false true
lazyLoadingEnabled 是否使用全域性懶載入 true|false true
multipleResultSetsEnabled 是否允許返回多個結果集合(需要相容的驅動) true|false true
useColumnLabel 使用列標籤取代列名(不同驅動表現不同) true|false true
useGeneratedKeys 允許jdbc自動生成主鍵 true|false false
enhancementEnabled(該屬性在測試的時候報錯,提示不存在,查閱資料好像文件裡寫錯了,這個屬性已經取消) 全域性性地啟用或禁用執行時位元組碼增強,以優化enhancementEnabled訪問Java Bean屬性的效能,同時優化延遲載入的效能。 true|false false
defaultExecutorType 配置預設執行方式
SIMPLE: nothing special
REUSE: reuses prepared statemets
BATCH:reuses statements and batches updates
SIMPLE
REUSE
BATCH
SIMPLE
defaultStatementTimeout 資料庫超時時間 Any positive
integer
Not Set
(null)

例子:

    cacheEnabled" value="true"/>
    lazyLoadingEnabled" value="true"/>
    multipleResultSetsEnabled" value="true"/>
    useColumnLabel" value="true"/>
    useGeneratedKeys" value="false"/>
    enhancementEnabled" value="false"/>
    defaultExecutorType" value="SIMPLE"/>
    defaultStatementTimeout" value="25000"/>

3 typeAliases

java類別名

<typeAliases>
    <typeAlias alias="Author" type="domain.blog.Author"/>
    <typeAlias alias="Blog" type="domain.blog.Blog"/>
    <typeAlias alias="Comment" type="domain.blog.Comment"/>
    <typeAlias alias="Post" type="domain.blog.Post"/>
    <typeAlias alias="Section" type="domain.blog.Section"/>
    <typeAlias alias="Tag" type="domain.blog.Tag"/>
typeAliases>


4 typeHandlers

Type Handler Java Types JDBC Types
BooleanTypeHandler Boolean,boolean Any compatible BOOLEAN
ByteTypeHandler Byte,byte Any compatible NUMERIC or BYTE
ShortTypeHandler Short,short Any compatible NUMERIC or SHORT INTEGER
IntegerTypeHandler Integer,int Any compatible NUMERIC or INTEGER
LongTypeHandler Long,long Any compatible NUMERIC or LONG INTEGER
FloatTypeHandler Float,float Any compatible NUMERIC or FLOAT
DoubleTypeHandler Double,double Any compatible NUMERIC or DOUBLE
BigDecimalTypeHandler BigDecimal Any compatible NUMERIC or DECIMAL
StringTypeHandler String CHAR,VARCHAR
ClobTypeHandler String CLOB,LONGVARCHAR
NStringTypeHandler String NVARCHAR,NCHAR
NClobTypeHandler String NCLOB
ByteArrayTypeHandler byte[] Any compatible byte stream type
BlobTypeHandler byte[] BLOB,LONGVARBINARY
DateTypeHandler Date(java.util) TIMESTAMP
DateOnlyTypeHandler Date(java.util) DATE
TimeOnlyTypeHandler Date(java.util) TIME
SqlTimestampTypeHandler Timestamp(java.sql) TIMESTAMP
SqlDateTypeHadler Date(java.sql) DATE
SqlTimeTypeHandler Time(java.sql) TIME
ObjectTypeHandler Any OTHER,or unspecified
EnumTypeHandler Enumeration Type VARCHAR – any string compatible type,as the code is stored(not the index)

也可以通過實現TypeHandler介面來實現自定義的型別轉換器

// ExampleTypeHandler.java
public class ExampleTypeHandler implements TypeHandler {
    public void setParameter(
        PreparedStatement ps, int i, Object parameter,JdbcType jdbcType)
    throws SQLException {
        ps.setString(i, (String) parameter);
    }
    public Object getResult(
        ResultSet rs, String columnName)
    throws SQLException {
        return rs.getString(columnName);
    }
    public Object getResult(
        CallableStatement cs, int columnIndex)
    throws SQLException {
        return cs.getString(columnIndex);
    }
}
// MapperConfig.xml

    String" jdbcType="VARCHAR"
    handler="org.apache.ibatis.example.ExampleTypeHandler"/>
這樣會覆蓋原來ibatis預設的string varchar轉換器

5 objectFactory

ibatis使用objectFactory去建立result object的例項物件,這裡可以自己繼承DefaultObjectFactory類實現自己的ObjectFactory

// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
    public Object create(Class type) {
        return super.create(type);
    }
    public Object create(
        Class type,
        List constructorArgTypes,
        List
// MapperConfig.xml
org.apache.ibatis.example.ExampleObjectFactory">
    someProperty" value="100"/>

6 plugins

ibatis允許外掛截斷以下方法呼叫
Executor(update,query,flushStatements,commit,rollback,getTransaction,close,isClosed)
ParameterHandler(getParameterObject,setParameters)
ResultSetHandler(handleResultSets,handleOutputParameters)
StatementHandler(prepare,parameterize,batch,update,query)
必須在理解這些方法的基礎上很小心的使用外掛,不然很容易破壞ibatis的核心

// ExamplePlugin.java
@Intercepts({@Signature(
    type= Executor.class,
    method = "update",
    args = {MappedStatement.class,Object.class})})
   
    public class ExamplePlugin implements Interceptor {
        public Object intercept(Invocation invocation) throws Throwable {
            return invocation.proceed();
        }
        public Object plugin(Object target) {
            return Plugin.wrap(target, this);
        }
        public void setProperties(Properties properties) {
        }
}

// MapperConfig.xml

org.apache.ibatis.example.ExamplePlugin">
    someProperty" value="100"/>

7 environments

這個是ibatis 3非常好的一個配置,允許配置多個不懂執行環境引數,不過每個SqlSessionFactory只可以在一種環境下被建立。
利用SqlSessionFactory的build函式
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,environment);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,environment,properties);
如果不知名environment引數,則應用預設的環境引數
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);

xml中如下配置:

default="development">
    development">
        JDBC">
            " value=""/>
        
    POOLED">
        driver" value="${driver}"/>
        url" value="${url}"/>
        username" value="${username}"/>
        password" value="${password}"/>
    
    


幾個注意點:
預設environment id: default="development">
environment id:development">
事務控制型別:JDBC">
   JDBC:根據jdbc控制事務的提交和回滾
    MANAGED:將事務控制轉交給容器
資料來源型別:POOLED">
   UNPOOLED:不使用池技術,在請求到來時直接開啟或者關閉資料庫連線
        必須配置的引數:driver、url、username、password
        可選引數:使用driver.xxx來配置,如:driver.encoding=UTF8
    POOLED:使用資料庫連線池
        poolMaximumActiveConnections:同一時間內最大連線數 預設10
            
        poolMaximumIdleConnections:連線最大空閒數目
            
        poolMaximumCheckoutTime:連線被每個任務佔用的最大時間 預設20000ms
            
        poolTimeToWait:連線池中無可用連線時,執行緒的等待時間 預設20000ms
            
        poolPingQuery:資料庫連線狀態檢測語句,類似於ping的功能 預設NO PING QUERY SET
            
        poolPingEnabled:是否允許ping檢測 預設false
           
        poolPingConnectionsNotUsedFor:對超過指定空閒時間的資料庫連線進行狀態監測 預設0 (必須在poolPingEnabled設定true情況下)
            
   JNDI:
        initial_context:可選,沒看明白,原文:This property is used for the Context lookup from the InitialContext
        data_source:JNDI資料庫名稱
        使用env.xxx配置可選引數,如:env.encoding=UTF8

8 mappers

配置實體對映檔案的路徑
// Using classpath relative resources <mappers> <mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/> <mapper resource="org/apache/ibatis/builder/BlogMapper.xml"/> <mapper resource="org/apache/ibatis/builder/PostMapper.xml"/> mappers> // Using url fully qualified paths <mappers> <mapper url="file:///var/sqlmaps/AuthorMapper.xml"/> <mapper url="file:///var/sqlmaps/BlogMapper.xml"/> <mapper url="file:///var/sqlmaps/PostMapper.xml"/> mappers>