Ibatis提供了一种半自动化的O/R Mapping实现框架。它以牺牲工作量和移植性的代价换取了SQL语句设计的自由性和可优化性。
典型Ibatis配置文件
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC"-//iBATIS.com//DTD SQL Map Config 2.0//EN""http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settingscacheModelsEnabled="true" //是否开启缓存
enhancementEnabled="false" //是否开启字节码增强,提高get/set调用性能
lazyLoadingEnabled="true" //是否开启延迟加载
errorTracingEnabled="true" //是否启用错误日志
maxRequests="32" //最大并发请求
maxSessions="10" //最大允许并发SqlMapClient数
maxTransactions="5" //最大并发事务数
useStatementNamespaces="false" /> //是否使用statment命名空间
<transactionManagertype="JDBC"> //传统JDBC事务支持
<dataSource type="SIMPLE"> //简单数据库连接池,对应SimpleDataSourceFactory
<property name="JDBC.Driver"value="com.mysql.jdbc.Driver" />
<property name="JDBC.ConnectionURL"value="jdbc:mysql://localhost:3306/mysql" />
<property name="JDBC.Username" value="root" />
<property name="JDBC.Password" value="password"/>
<propertyname="Pool.MaximumActiveConnections" value="10"/>//数据库连接池最大连接数
<property name="Pool.MaximumIdleConnections"value="5" /> //允许挂起连接数
<propertyname="Pool.MaximumCheckoutTime" value="120000"/>//连接任务允许占用最大时间
<property name="Pool.TimeToWait" value="500"/> //允许等待最长时间
<property name="Pool.PingQuery" value="select 1 fromACCOUNT"/> //连接状态检测语句
<property name="Pool.PingEnabled" value="false"/> //是否开启连接状态检测
<property name="Pool.PingConnectionsOlderThan"value="1" /> //连接状态检测时间设定
<property name="Pool.PingConnectionsNotUsedFor"value="1" />//空闲状态检测时间设定
</dataSource>
</transactionManager>
<!-- JNDI
<transactionManagertype="JDBC">
<dataSource type="JNDI"> //使用J2EE容器实现DataSource,对应实现类JndiDataSourceFactory
<property name="DataSource"value="java:comp/env/jdbc/myDataSource" />
</dataSource>
</transactionManager>-->
<!-- JTA
<transactionManagertype="JTA"> //使用容器提供的JTA服务实现全局事务管理
<property name="UserTransaction"value="java:/ctx/con/UserTransaction" />
<dataSource type="JNDI">
<property name="DataSource"value="java:comp/env/jdbc/myDataSource" />
</dataSource>
</transactionManager> -->
<sqlMapresource="com/ibatis/ao/User.xml" />
</sqlMapConfig>
User模型类
public class User implements Serializable{
private Integer id;
private String name;
private Integer sex;
public User(){}
public User(Integer id,String name,Integersex){
this.id=id;
this.name=name;
this.sex=sex;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
}
模型类映射文件
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC"-//iBATIS.com//DTD SQL Map 2.0//EN""http://toolkit.alibaba-inc.com/dtd/ibatis/sql-map-2.dtd">
<sqlMap namespace="User">
<typeAlias alias="user"type="com.ibatis.ao.User" /> //设置映射路径
<!-- 模块配置 -->
<cacheModel id="userCache"type="LRU"> //设置缓存类型
<flushInterval hours="24" /> //设置缓存有效期
<flushOnExecute statement="updateUser" /> //执行特定statment是清空缓存
<property name="size" value="1000" /> //设置缓存大小
</cacheModel>
<resultMap id="userResult"class="user"> //resultMap结果映射
<result property="id" column="id" />
<result property="name" column="name" />
<result property="sex" column="sex" />
</resultMap>
<!-- Statement配置 -->
<select id="getUser"resultMap="userResult" parameterClass="string"> //parameterClass参数类
<![CDATA[
select
name,
sex
from
t_user
where
name=#name#
]]>
</select>
<select id="getUserById"resultClass="user" parameterClass="Integer"> //resultClass结果类
<![CDATA[
select
name,
sex
from
t_user
where
id=#id#
]]>
</select>
<insert id="insertUser"parameterClass="user">
<![CDATA[
INSERT INTO t_user (
name,
sex
) values (
#name#,
#sex#
)
]]>
</insert>
<delete id="deleteUser"parameterClass="Integer">
<![CDATA[
delete from t_user
WHERE id=#id#
]]>
</delete>
<update id="updateUser"parameterClass="user">
<![CDATA[
update t_user
set
name=#name#,
sex=#sex#
WHERE id=#id#
]]>
</update>
</sqlMap>
测试类
public void testIbatisSqlMap() throwsSQLException{
String resource="sqlmap-config.xml";
try{
Reader reader=Resources.getResourceAsReader(resource);
SqlMapClient sqlMap =SqlMapClientBuilder.buildSqlMapClient(reader); //SqlMapClient核心类
try{
sqlMap.startTransaction();
// User user=new User();
// user.setId(new Integer(1));
// user.setName("Samantha");
// user.setSex(new Integer(11));
// sqlMap.insert("insertUser",user);
Integer key=new Integer(2);
Useruser1=(User)sqlMap.queryForObject("getUserById",key);
sqlMap.commitTransaction();
System.out.println(user1.getName());
}catch (SQLException e) {
e.printStackTrace();
}finally{
sqlMap.endTransaction();
}
}catch (IOException e) {
e.printStackTrace();
}
}
Ibatis高级特性:
1.数据关联:(一对多关联)
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC"-//iBATIS.com//DTD SQL Map 2.0//EN""http://toolkit.alibaba-inc.com/dtd/ibatis/sql-map-2.dtd">
<sqlMap namespace="User">
<typeAlias alias="user"type="com.ibatis.ao.User" />
<typeAlias alias="address"type="com.ibatis.ao.Address" />
<resultMap id="get-user-result"class="user">
<result property="id" column="id" />
<result property="name" column="name" />
<result property="sex" column="sex" />
<result property="addresses" column="id"select="User.getAddressByUserId" />
</resultMap>
<select id="User.getUsers"parameterClass="java.lang.String"
resultMap="get-user-result">
<![CDATA[
select
id,
name,
sex
from t_user
where id = #id#
]]>
</select>
<selectid="User.getAddressByUserId" parameterClass="int"
resultClass="address">
<![CDATA[
select
address,
zipcode
from t_address
where user_id = #userid#
]]>
</select>
</sqlMap>
对应代码:
public void testIbatisSqlMap() throwsSQLException, IOException {
String resource = "sqlmap-config.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
//sqlMap系统初始化完毕
List userList = sqlMap.queryForList("User.getUsers","2");
for(int i = 0; i < userList.size(); i++) {
User user = (User) userList.get(i);
System.out.println("==>" + user.getName());
for (int k = 0; k < user.getAddresses().size(); k++) {
Address addr = (Address)user.getAddresses().get(k);
System.out.println(new String(addr.getAddress()));
}
}
}
这种对应在大数据量的情况下会产生性能问题
如果是一对一关系:
<resultMap >
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="address"column="t_address.address"/>
<result property="zipCode" column="t_address.zipcode"/>
</resultMap>
<selectparameterClass="string"
resultMap="get-user-result">
<![CDATA[
select
*
from t_user,t_address
where t_user.id=t_address.user_id
]]>
</select>
2.延迟加载:当真正访问对象时才执行SQL语句,提高了系统性能。
3.动态映射
<dynamic prepend="WHERE">
<isNotEmpty prepend="AND" property="name">
(name like #name#)
</isNotEmpty>
<isNotEmpty prepend="AND" property="address">
(address like #address#)
</isNotEmpty>
</dynamic>
一元判定:is(Not)PropertyAvailable,is(Not)Null,is(Not)Empty
二元判定:is(Not)Equal,isGreatThan,isGreatEqual,isLessThan,isLessEqual
4.事务管理
传统JDBC事务:
try{
sqlMap.startTransaction();
...
sqlMap.commitTransaction();
}finally{
sqlMap.endTransaction();
}
JTA事务管理:提供了跨数据库事务管理能力
外部事务管理:<transactionManagertype="EXTERNAL">
UserTransaction tx=newInitialContext().lookup("...");
...
tx.commit();
5.Cache
readonly、serialize(全局数据缓存)特性
Type:MEMORY、LRU、FIFO、OSCACHE
SoftReference、WeakReference、PhantomReference
<cacheModel type="MEMORY">
<flushInterval hours="24"/>
<flushOnExecute statement="updateUser"/>
<property value="WEAK" />
</cacheModel>
Ibatis in Spring:
接口:
public interface IUserDAO {
public void insertUser(User user);
}
实现类:
public class UserDao extendsSqlMapClientDaoSupport implements IUserDAO{
public void insertUser(User user){
getSqlMapClientTemplate().update("insertUser",user);
}
}
模型类配置文件:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC"-//iBATIS.com//DTD SQL Map 2.0//EN" "http://toolkit.alibaba-inc.com/dtd/ibatis/sql-map-2.dtd">
<sqlMap namespace="User">
<typeAlias alias="user"type="com.ibatis.ao.User" />
<insert id="insertUser"parameterClass="user">
INSERT INTO users(username,password) VALUES (#username#,#password#)
</insert>
</sqlMap>
拦截器:
public class SqlInterceptor extendsSqlMapClientDaoSupport implements MethodInterceptor{
public Object invoke(MethodInvocationinvocation) throws Throwable {
//可以doSomething
Object returnValue=null;
//可以doSomething
returnValue=invocation.proceed();
return returnValue;
}
}
ibatis配置文件:
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC"-//iBATIS.com//DTD SQL Map Config 2.0//EN""http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<sqlMap resource="com/ibatis/ao/User.xml"/>
</sqlMapConfig>
Spring配置文件:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC"-//SPRING//DTD BEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<description>SpringIbatis</description>
<bean id="dataSource"
class ="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"> //DBCP连接数据库
<property name="driverClassName">
<value>com.p6spy.engine.spy.P6SpyDriver</value> //利用P6Spy来显示执行的SQL语句
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/mysql</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>password</value>
</property>
</bean>
<bean id="sqlMapClient"class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation">
<value>sqlmap-config.xml</value>
</property>
</bean>
<bean id="sqlInterceptor"class="com.taobao.ibatis.dao.SqlInterceptor"> //实现一个拦截器
<property name="sqlMapClient">
<ref local="sqlMapClient"/>
</property>
<property name="dataSource">
<ref local="dataSource"/>
</property>
</bean>
<bean id="myPointcutAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> //设置切点
<property name="advice">
<ref local="sqlInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*insert.*</value>
</list>
</property>
</bean>
<bean id="userDAO"class="com.taobao.ibatis.dao.UserDao">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="sqlMapClient">
<ref local="sqlMapClient"/>
</property>
</bean>
<bean id="userDAOProxy"class="org.springframework.aop.framework.ProxyFactoryBean"> //设置代理类
<property name="proxyInterfaces">
<value>com.ibatis.ao.IUserDAO</value>
</property>
<property name="target">
<ref local="userDAO"/>
</property>
<property name="interceptorNames">
<value>myPointcutAdvisor</value>
</property>
</bean>
</beans>
附:p6spy.properties配置文件
module.log=com.p6spy.engine.logging.P6LogFactory
realdriver=com.mysql.jdbc.Driver
deregisterdrivers=true
executionthreshold=
outagedetection=false
outagedetectioninterval=
filter=false
include =
exclude =
sqlexpression =
autoflush = true
dateformat=
includecategories=
excludecategories=info,debug,result,batch
stringmatcher=
stacktrace=false
stacktraceclass=
reloadproperties=false
reloadpropertiesinterval=60
useprefix=false
appender=com.p6spy.engine.logging.appender.StdoutLogger
append=true
log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.layout=org.apache.log4j.SimpleLayout
log4j.appender.STDOUT.layout.ConversionPattern=p6spy
log4j.logger.p6spy=DEBUG,STDOUT
测试类:
public void testIbatisSqlMap(){
ApplicationContext ctx=newFileSystemXmlApplicationContext("ibatiscontext.xml");
IUserDAO userdao=(IUserDAO)ctx.getBean("userDAOProxy");
User user=new User();
user.setUsername("Samantha");
user.setPassword("miss");
userdao.insertUser(user);
}
对dao配置文件
举例说明:
1.来一个Person类
package com.Jdnis.ibatis.model;
import java.io.Serializable;
import java.sql.Date;
public class Person implements Serializable {
privatestatic final long serialVersionUID = 1L;
private intid ;
privateString firstName ;
privateString lastName ;
private DatebirthDate = new Date(1900,1,1);;
privatedouble weight ;
privatedouble height ;
public intgetId() {
returnid;
}
public voidsetId(int id) {
this.id= id;
}
publicString getFirstName() {
returnfirstName;
}
public voidsetFirstName(String firstName) {
this.firstName= firstName;
}
publicString getLastName() {
returnlastName;
}
public voidsetLastName(String lastName) {
this.lastName= lastName;
}
public DategetBirthDate() {
returnbirthDate;
}
public voidsetBirthDate(Date birthDate) {
this.birthDate= birthDate;
}
publicdouble getWeight() {
returnweight;
}
public voidsetWeight(double weight) {
this.weight= weight;
}
publicdouble getHeight() {
returnheight;
}
public voidsetHeight(double height) {
this.height= height;
}
}
2.oop编程中,面向接口编程是一种很好的编程风格。在这一步骤中,定义Person实例的一个操作接口:
package com.Jdnis.ibatis.interfaces;
import java.util.List;
import com.ibatis.dao.client.Dao;
import com.Jdnis.ibatis.model.Person;
public interface PersonInterface extends Dao{
public voidinsertPerson(Person p);
public voidupdatePerson(Person p);
public ListselectAllPerson( );
}
3.对接口的实现类
package com.Jdnis.ibatis.interfaces;
import java.sql.SQLException;
import java.util.List;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.template.SqlMapDaoTemplate;
import com.Jdnis.ibatis.model.Person;
public class PersonImpl extends SqlMapDaoTemplateimplements PersonInterface {
publicPersonImpl(DaoManager daoManager) {
super(daoManager);
//TODO Auto-generated constructor stub
}
public voidinsertPerson(Person p) {
//TODO Auto-generated method stub
try {
this.getSqlMapExecutor().insert("insertPerson",p);
System.out.println("数据插入成功!");
}catch (SQLException e) {
//TODO Auto-generated catch block
System.out.println("插入出错,主键冲突!");
}
}
public voidupdatePerson(Person p) {
//TODO Auto-generated method stub
try {
this.getSqlMapExecutor().update("updatePerson",p);
}catch (SQLException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
public ListselectAllPerson() {
//TODO Auto-generated method stub
returnqueryForList("selectAllPerson",null);
}
}
4.配置person.xml文件:实现对象与数据库的映射
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQLMap 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap namespace="Person">
<!-- 缓存 -->
<typeAliasalias="person" type="com.Jdnis.ibatis.model.Person" />
<parameterMapid="insert_person" class="person">
<parameterproperty="id" jdbcType="int" />
<parameterproperty="firstName" jdbcType="varchar"/>
<parameterproperty="lastName" jdbcType="varchar"/>
<parameterproperty="birthDate" jdbcType="Date"/>
<parameterproperty="weight" jdbcType="double" />
<parameterproperty="height" jdbcType="double" />
</parameterMap>
<resultMapid="allPersons" class="person">
<result property="id"column="per_id" />
<resultproperty="firstName" column="per_first_name" />
<resultproperty="lastName" column="per_last_name" />
<resultproperty="birthDate" column="per_birth_date" />
<resultproperty="weight" column="weightInKilograms" />
<resultproperty="height" column="heightInMeters" />
</resultMap>
<statementid="insertPerson" parameterMap="insert_person">
INSERT INTOpersons VALUES(?,?,?,?,?,?)
</statement>
<statementid="selectAllPerson" resultMap="allPersons">
<![CDATA[select * from persons]]>
</statement>
<statementid="updatePerson" parameterClass="person">
<![CDATA[update persons setper_first_name=#firstName#,per_last_Name=#lastName#,per_birth_date=#birthDate#,weightInKilograms=#weight#,heightInMeters=#height#where per_id=#id#]]>
</statement>
</sqlMap>
5.SqlMapConfig.xml文件的配置:配置数据源
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTDSQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<!-- 地方i -->
<settingscacheModelsEnabled="true"
enhancementEnabled="true"
lazyLoadingEnabled="true"
errorTracingEnabled="true"
maxRequests="32"
maxSessions="10"
maxTransactions="5"
useStatementNamespaces="false"
/>
<transactionManager type="JDBC">
<dataSource type="SIMPLE">
<property name="JDBC.Driver"value="com.mysql.jdbc.Driver" />
<property name="JDBC.ConnectionURL"value="jdbc:mysql://localhost/person" />
<property name="JDBC.Username" value="root" />
<property name="JDBC.Password" value="root" />
<property name="Pool.MaximumActiveConnections"value="10" />
<property name="Pool.MaximumIdleConnections"value="5" />
<property name="Pool.MaximumCheckoutTime"value="120000" />
<property name="Pool.TimeToWait" value="500"/>
<property name="Pool.PingQuery" value="select 1 fromsample" />
<property name="Pool.PingEnabled" value="false"/>
<property name="Pool.PingConnectionsOlderThan"value="1" />
<property name="Pool.PingConnectionsNotUsedFor"value="1" />
</dataSource>
</transactionManager>
<sqlMapresource="com/Jdnis/ibatis/map/person.xml" />
</sqlMapConfig>
6.ibatis的dao.xml文件的配置:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE daoConfig PUBLIC"-//ibatis.apache.org//DTD DAO Configuration 2.0//EN""http://ibatis.apache.org/dtd/dao-2.dtd">
<daoConfig>
<context>
<transactionManager type="SQLMAP">
<propertyname="SqlMapConfigResource"value="com/neusoft/ibatis/map/SqlMapConfig.xml" />
</transactionManager>
<dao interface="com.neusoft.ibatis.interfaces.PersonInterface"implementation="com.Jdnis.ibatis.interfaces.PersonImpl" />
</context>
</daoConfig>
该文件的<transactionManager>元素将刚才的SqlMapConfig.xml相关联起来,使得三个配置文件都联系到了一起,<dao>元素的配置是将dao接口与其实现类关联起来。
7.dao.xml文件的解析
package com.Jdnis.ibatis.dao;
import java.io.IOException;
import java.io.Reader;
import java.util.Properties;
import com.ibatis.common.resources.Resources;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.DaoManagerBuilder;
public class DAOConfig {
privatestatic final String resource="com/Jdnis/ibatis/map/dao.xml";
privatestatic final DaoManager daoManager;
static{
daoManager= newDaoManager(null);
}
publicstatic DaoManager getDaoManager(){
returndaoManager;
}
public staticDaoManager newDaoManager(Properties props){
try {
Readerreader = Resources.getResourceAsReader(resource);
returnDaoManagerBuilder.buildDaoManager(reader,props);
}catch (Exception e) {
//TODO Auto-generated catch block
newRuntimeException("Could not initialize DaoConfig. Cause: " + e, e);
}
returnnull;
}
}
8.测试类
package com.Jdnis.ibatis.dao;
import java.sql.Date;
import com.ibatis.dao.client.DaoManager;
import com.Jdnis.ibatis.interfaces.PersonInterface;
import com.Jdnis.ibatis.model.Person;
public class TestCase {
DaoManagerdaoManager;
protectedvoid setUp()throws Exception{
daoManager= DAOConfig.getDaoManager();
}
public voidtestInsertPerson(){
PersonInterfacepi = (PersonInterface)daoManager.getDao(PersonInterface.class);
Personp = new Person();
p.setId(2);
p.setFirstName("firstName");
p.setLastName("lastName");
//p.setBirthDate(newDate(21,12,25));
p.setHeight(172);
p.setWeight(125);
pi.insertPerson(p);
}
publicstatic void main(String[] args){
TestCasetc = new TestCase();
try {
tc.setUp();
}catch (Exception e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
tc.testInsertPerson();
}
}
ibatis通过
PersonInterface pi =(PersonInterface)daoManager.getDao(PersonInterface.class);
这种反射的机制,来实例化一个接口的实现类(dao.xml文件中接口与实现类的关联)