上篇简单调试了一个实例,现在仔细看看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>