ibatis学习之一二三 ibatis与spring的整合
http://www.blogjava.net/freeman1984/archive/2007/12/07/166112.html
介绍
iBATIS是以SQL为中心的持久化层框架。能支持懒加载、关联查询、继承等特性。
iBATIS不同于一般的OR映射框架(eg:hibernate)。OR映射框架,将数据库表、字段等映射到类、属性,那是一种元数据(meta-data)映射。iBATIS则是将SQL查询的参数和结果集映射到类。因此可以说,iBATIS做的是SQLMapping的工作。它把SQL语句看成输入以及输出,结果集就是输出,而where后面的条件参数则是输入。iBATIS能将输入的普通POJO对象、Map、XML等映射到SQL的条件参数上,同时也可以将查询结果映射到普通POJO对象(集合)、Map、XML等上面。
iBATIS使用xml文件来映射这些输入以及输出。能大大减少数据库存储部分的代码量,而且可以非常方便的利用SQL中的一些小技巧。
简单示例
基于ibatis-2.3.0.677版本。
1、创建新的项目,并引入jar包
a)ibatis-2.3.0.677.jar
b)mysql驱动
2、在类路径中(classes下)提供ibatis的配置文件:sqlMapConfig.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEsqlMapConfig
PUBLIC"-//ibatis.apache.org//DTDSQLMapConfig2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<transactionManagertype="JDBC"commitRequired="false">
<dataSourcetype="SIMPLE">
<propertyname="JDBC.Driver"value="com.mysql.jdbc.Driver"/>
<propertyname="JDBC.ConnectionURL"value="jdbc:mysql://127.0.0.1/ibatis"/>
<propertyname="JDBC.Username"value="root"/>
<propertyname="JDBC.Password"value="mysql"/>
</dataSource>
</transactionManager>
<sqlMapresource="com/ibatis/model/User.xml"/>
</sqlMapConfig>
3、创建实体类:User.java
packagecom.ibatis.model;
publicclassUser{
privateintid;
privateStringusername;
privateStringpassword;
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetPassword(){
returnpassword;
}
publicvoidsetPassword(Stringpassword){
this.password=password;
}
publicStringgetUsername(){
returnusername;
}
publicvoidsetUsername(Stringusername){
this.username=username;
}
}
4、创建针对User对象的CRUD的xml映射配置:User.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEsqlMap
PUBLIC"-//ibatis.apache.org//DTDSQLMap2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMapnamespace="User">
<!--Usetypealiasestoavoidtypingthefullclassnameeverytime.-->
<typeAliasalias="User"type="com.ibatis.model.User"/>
<!--SelectwithnoparametersusingtheresultmapforAccountclass.-->
<selectid="selectAllUsers"resultclass="User">
select*fromt_user
</select>
<selectid="selectUser"resultclass="User"parameterclass="int">
select*fromt_userwhereid=#id#
</select>
<insertid="insertUser"parameterclass="User">
insertintot_uservalues(
null,#username#,#password#
)
</insert>
<updateid="updateUser"parameterclass="User">
updatet_usersetusername=#username#,password=#password#
whereid=#id#
</update>
<deleteid="deleteUser"parameterclass="int">
deletefromt_userwhereid=#id#
</delete>
</sqlMap>
5、创建测试程序测试:
packagecom.crm.model;
importjava.io.Reader;
importjava.util.Iterator;
importjava.util.List;
importcom.ibatis.common.resources.Resources;
importcom.ibatis.sqlmap.client.SqlMapClient;
importcom.ibatis.sqlmap.client.SqlMapClientBuilder;
/**
*最简单的形式!
*@authorq
*
*/
publicclassUserTest{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args)throwsException{
//从配置文件中得到SqlMapClient对象
Readerreader=Resources.getResourceAsReader("sqlMapConfig.xml");
SqlMapClientsqlMapper=SqlMapClientBuilder.buildSqlMapClient(reader);
reader.close();
//创建用户数据
for(inti=0;i<10;i++){
Useruser=newUser();
user.setUsername("用户"+i);
user.setPassword("密码"+i);
sqlMapper.insert("insertUser",user);
}
//查询用户数据
Listusers=sqlMapper.queryForList("selectAllUsers");
for(Iteratoriter=users.iterator();iter.hasNext();){
Useruser=(User)iter.next();
System.out.println(user.getUsername());
}
//查询特定用户的数据
Useruser=(User)sqlMapper.queryForObject("selectUser",1);
System.out.println("用户【id="+1+"】的名称是:"+user.getUsername());
//更新用户的信息
user=newUser();
user.setId(3);
user.setUsername("更改之后的用户名称");
user.setPassword("密码被更改");
sqlMapper.update("updateUser",user);
//删除用户的信息
sqlMapper.delete("deleteUser",6);
}
}
-----------------------------------之二--------------------------
SqlMapClient对象
这个对象是iBatis操作数据库的接口(执行CRUD等操作),它也可以执行事务管理等操作。这个类是我们使用iBATIS的最主要的类。它是线程安全的。通常,将它定义为单例。(与hibernate中sessionFactory的定义类似)。如:
importjava.io.Reader;
importcom.ibatis.common.resources.Resources;
importcom.ibatis.sqlmap.client.SqlMapClient;
importcom.ibatis.sqlmap.client.SqlMapClientBuilder;
publicclassIbatisSQLMapConfig{
privatestaticfinalSqlMapClientsqlMap;
//在静态区块中初试化返回
static{
try{
//声明配置文件的名称(映射文件被定义在其中)
Stringresource="sql_map_config.xml";
//利用工具类Resources来读取到配置文件
Readerreader=Resources.getResourceAsReader(resource);
//创建SqlMapClient接口的变量实例
sqlMap=SqlMapClientBuilder.buildSqlMapClient(reader);
}catch(Exceptione){
e.printStackTrace();
thrownewRuntimeException(
"ErrorinitializingMyAppSqlConfigclass.Cause:"+e);
}
}
publicstaticSqlMapClientgetSqlMapInstance(){
//提供静态方法返回静态区块中得到的SqlMapClient
returnsqlMap;
}
}
主要用法:
如何获得刚插入记录的自增长ID值?
以下所有虚线上面代表User.xml中的内容,虚线下方是测试类中的内容:User类沿用上一篇中的User类
<insertid="insertUser"parameterclass="User">
insertintot_uservalues(
null,#username#,#password#
)
<selectKeyresultclass="int"keyProperty="id">
SELECT@@IDENTITYASID
</selectKey>
</insert>
Useruser=newUser();
user.setUsername("张三");
user.setPassword("张三密码");
//如果主键是自动生成的,则其返回值可以通过<selectKey>标签来设置
//如果不通过<selectKey>标签来设置,则返回值为空!
//<selectKey>中的keyProperty,是指定User中的id属性,当调用结束之后,
//user对象的id值和insert方法的返回值都是这条记录的ID值!
Objectobj=sqlMapper.insert("insertUser",user);
parameterClass的使用
<insertid="insertUser"parameterclass="User">
insertintot_uservalues(
null,#username#,#password#
)
<selectKeyresultclass="int"keyProperty="id">
SELECT@@IDENTITYASID
</selectKey>
</insert>
<insertid="insertUser2">
insertintot_uservalues(
null,#username#,#password#
)
<selectKeyresultclass="int"keyProperty="id">
SELECT@@IDENTITYASID
</selectKey>
</insert>
insertUser使用了parameterClass,所以必需传入User类型的对象
Useruser=newUser();
user.setUsername("张三");
user.setPassword("张三密码");
//传递进去的对象,必须是User类型
Objectobj=sqlMapper.insert("insertUser",user);
insertUser2没有使用parameterClass,所以可以传入任意具有相应属性值的对象
JustAnObjectanobj=newJustAnObject();
anobj.setUsername("用户名");
anobj.setPassword("用户密码");
//如果没有指定parameterClass属性,则任何一个具有相应属性值
//的对象都可以被传递进去
Objectobj=sqlMapper.insert("insertUser2",anobj);
parameterMap的使用
<parameterMapclass="User"id="insertUser-param">
<parameterproperty="username"/>
<parameterproperty="password"/>
</parameterMap>
<insertid="insertUser"parameterMap="insertUser-param">
insertintot_uservalues(
null,?,?
)
<selectKeyresultclass="int"keyProperty="id">
SELECT@@IDENTITYASID
</selectKey>
</insert>
parameterMap用于传入参数,以便匹配SQL语句中的?号
Useruser=newUser();
user.setUsername("张三dd");
user.setPassword("张三密码dd");
Objectobj=sqlMapper.insert("insertUser",user);
利用parameterMap,可以定义参数对象的属性如何映射到SQL查询语句的动态参数上,注意parameterMap中<parameter/>标签的先后顺序不能颠倒!
如何将查询结果映射到不同的对象?(resultClass的使用)
packagecom.ibatis.model;
publicclassOtherObject{
privateintid;
privateStringprop1;
privateStringprop2;
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetProp1(){
returnProp1;
}
publicvoidsetProp1(StringProp1){
this.Prop1=Prop1;
}
publicStringgetProp2(){
returnusername;
}
publicvoidsetProp2(StringProp2){
this.Prop2=Prop2;
}
}
<selectid="selectUserForOtherObject"resultclass="com.ibatis.OtherObject"parameterclass="int">
select
usernameasprop1,
passwordasprop2
fromt_userwhereid=#value#
</select>
//查找t_user表,将其结果映射到一个属性名不同的对象中!
OtherObjectobj=(OtherObject)sqlMapper.queryForObject("selectUserForOtherObject",1);
System.out.println(obj.getProp1()+","+obj.getProp2());
如何将查询结果集映射到不同的对象?(resultMap的基本使用)
<resultMapclass="com.ibatis.model.OtherObject"id="ooResult">
<resultproperty="prop1"column="username"/>
<resultproperty="prop2"column="password"/>
</resultMap>
<!--
如果使用resultMap来定义如何映射,则如下语句不可写成:
selectusernameasprop1,passwordasprop2....
-->
<selectid="selectUserForOtherObject2"parameterclass="int"resultMap="ooResult">
select
username,
password
fromt_userwhereid=#value#
</select>
//查找t_user表,将其结果映射到一个属性名不同的对象中!
OtherObjectobj=(OtherObject)sqlMapper.queryForObject("selectUserForOtherObject2",17);
System.out.println(obj.getProp1()+","+obj.getProp2());
如何将查询结果集映射为xml格式的数据?
<selectid="selectXmlData"resultclass="xml"xmlResultname="User"parameterclass="int">
select*fromt_userwhereid=#value#
</select>
<selectid="selectXmlDatas"resultclass="xml"xmlResultname="User">
select*fromt_user
</select>
//查找t_user表,将其结果映射到xml!
//返回值是xml形式的字符串
Objectobj=(Object)sqlMapper.queryForObject("selectXmlData",1);
System.out.println(obj);
//查找t_user表,将其结果映射到xml!
Listlist=(List)sqlMapper.queryForList("selectXmlDatas");
System.out.println(list);
如何用Map类型的对象作为传入参数?
<!--
这里,可以使用全路径类名,如:
java.util.Map
java.util.HashMap
java.util.TreeMap
或
map
-->
<insertid="insertUser"parameterclass="map">
insertintot_uservalues(
null,#username#,#password#
)
</insert>
Mapuser=newTreeMap();
user.put("username","Map用户");
user.put("password","Map用户密码");
sqlMapper.insert("insertUser",user);
如何将查询结果集的元素转换为Map类型的对象?
<!--
resultClass可以定义为java.util.HashMap类型,
将能自动转换
-->
<selectid="selectMapUsers"resultclass="java.util.HashMap">
select*fromt_user
</select>
Listlist=(List)sqlMapper.queryForList("selectMapUsers");
System.out.println(list);
for(Iteratoriter=list.iterator();iter.hasNext();){
Mapmap=(Map)iter.next();
//可在此输出map的数据
}
事务处理
可以使用sqlMapClient的startTransaction/commitTransaction/endTransaction等方法来控制事务的边界。
如果与spring整合(这是iBatis推荐的方式),则我们需要在spring配置文件中指定其事务特性。
-----------------------------------之三--------------------------
Spring通过DAO模式,提供了对iBATIS的良好支持。SqlMapClient对象是iBATIS中的主要对象,我们可以通过配置让spring来管理SqlMapClient对象的创建。
与hibernate类似,Spring提供了SqlMapClientDaoSupport对象,我们的DAO可以继承这个类,通过它所提供的SqlMapClientTemplate对象来操纵数据库。看起来这些概念都与hibernate类似。
通过SqlMapClientTemplate来操纵数据库的CRUD是没有问题的,这里面关键的问题是事务处理。Spring提供了强大的声明式事务处理的功能,我们已经清楚hibernate中如何配置声明式的事务,那么在iBATIS中如何获得声明式事务的能力呢?
第一,我们需要了解的是spring通过AOP来拦截方法的调用,从而在这些方法上面添加声明式事务处理的能力。典型配置如下:applicationContext-common.xml
<!--配置事务特性-->
<tx:adviceid="txAdvice"transaction-manager="事务管理器名称">
<tx:attributes>
<tx:methodname="add*"propagation="REQUIRED"/>
<tx:methodname="del*"propagation="REQUIRED"/>
<tx:methodname="update*"propagation="REQUIRED"/>
<tx:methodname="*"read-only="true"/>
</tx:attributes>
</tx:advice>
<!--配置哪些类的方法需要进行事务管理-->
<aop:config>
<aop:pointcutid="allManagerMethod"expression="execution(*com.ibatis.manager.*.*(..))"/>
<aop:advisoradvice-ref="txAdvice"pointcut-ref="allManagerMethod"/>
</aop:config>
这些事务都是声明在业务逻辑层的对象上的。
第二,我们需要一个事务管理器,对事务进行管理。
<beanid="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource">
<propertyname="driverClassName"value="com.mysql.jdbc.Driver"/>
<propertyname="url"value="jdbc:mysql://127.0.0.1/ibatis"/>
<propertyname="username"value="root"/>
<propertyname="password"value="mysql"/>
</bean>
此后,我们需要让spring来管理SqlMapClient对象:
<beanid="sqlMapClient"class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<propertyname="configLocation"><value>classpath:sqlMapConfig.xml</value></property>
</bean>
我们的sqlMapConfig.xml就可以简写为:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEsqlMapConfig
PUBLIC"-//ibatis.apache.org//DTDSQLMapConfig2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings
lazyLoadingEnabled="true"
useStatementNamespaces="true"/>
<!--使用spring之后,数据源的配置移植到了spring上,所以iBATIS本身的配置可以取消-->
<sqlMapresource="com/ibatis/dao/impl/ibatis/User.xml"/>
</sqlMapConfig>
User.xml:如下
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEsqlMap
PUBLIC"-//ibatis.apache.org//DTDSQLMap2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMapnamespace="User">
<!--Usetypealiasestoavoidtypingthefullclassnameeverytime.-->
<typeAliasalias="User"type="com.ibatis.User"/>
<!--SelectwithnoparametersusingtheresultmapforAccountclass.-->
<selectid="selectAllUsers"resultclass="User">
select*fromt_user
</select>
<selectid="selectUser"resultclass="User"parameterclass="int">
select*fromt_userwhereid=#id#
</select>
<insertid="insertUser"parameterclass="User">
insertintot_uservalues(
null,#username#,#password#
)
</insert>
<updateid="updateUser"parameterclass="User">
updatet_usersetusername=#username#,password=#password#
whereid=#id#
</update>
<deleteid="deleteUser"parameterclass="int">
deletefromt_userwhereid=#id#
</delete>
</sqlMap>
我们的DAO的编写:
packagecom.iabtis.dao.impl.ibatis;
importjava.util.List;
importorg.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
importcom.ibatis.dao.UserDAO;
importcom.ibatis.crm.model.User;
publicclassUserDAOImplextendsSqlMapClientDaoSupportimplementsUserDAO{
publicvoidselect(Useruser){
getSqlMapClientTemplate().delete("selectUser",user.getId());
}
publicListfindAll(){
returngetSqlMapClientTemplate().queryForList("selectAllUsers");
}
publicvoiddelete(Useruser){
getSqlMapClientTemplate().delete("deleteUser",user.getId());
}
publicvoidsave(Useruser){
getSqlMapClientTemplate().insert("insertUser",user);
}
publicvoidupdate(Useruser){
getSqlMapClientTemplate().update("updateUser",user);
}
}
继承SqlMapClientDaoSupport,要求我们注入SqlMapClient对象,因此,需要有如下的DAO配置:
<beanid="userDAO"class="com.ibatils.dao.impl.ibatis.UserDAOImpl">
<propertyname=”sqlMapClient”ref=”sqlMapClient”/>
</bean>
这就是所有需要注意的问题了,此后就可以在业务逻辑层调用DAO对象了!