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,會被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>