打开IBATIS2之门,将带您走进IBATIS2的美妙世界,陆续让您体会到灵活SQL的对象化映射!
一、IBATIS是什么?
IBATIS是什么?简而言之,IBATIS“半自动化”的ORM实现,采用SQL MAP方式完成SQL与Java Bean间灵活映射。使用SQL Map,能够大大减少访问关系数据库的代码。SQL Map使用简单的XML配置文件将Java Bean映射成SQL语句,对比其他的数据库持续层和ORM框架(如JDO的实现,Hibernate等),SQL Map最大的优点在于它简单易学。要使用SQL Map,只要熟悉Java Bean,XML和SQL,就能使您充分发挥SQL语句的能力。这也是IBATIS最明显的优势所在:简单易学、灵活可控以及SQL细粒度优化!
二、IBATIS带来什么?
简单的说,带来了灵活易控SQL与对象JavaBean间封装映射。从原始Jdbc模式的sql到Appache 的DBUtil,到Spring的JdbcTemplate,到Ibatis,再到Hibernate(OJB、TopLink到),人们不断的实践着sql编程的高复用性,降低代码量(如DBUtil), 不断的追求着sql操作数据形式的对象化,简单化sql数据形式与对象间的转化(如JdbcTemplate),不断找寻着sql语句隔离抛弃硬编码以及sql数据对象化,透明化sql数据对象化(如“半自动化”的Ibatis),不断探索着sql数据面向对象,以面向对象的思想完成JavaBean与Table表间全自动sql映射(如Hibernate)。复用性、面向对象化程度以及抽象层次越来越高,开发效率明显提升,但从某种程度上将,也损失了部分可控性和灵活性,甚至包括性能(仅指对数据库操作,在没有优化手段的情况,因为抽象层次越高,处理相对越耗时)!
谚言“每一枚硬币都有两个面”,优缺点有时候具备太强的相对性,所以,如何选择持久层框架,需要因“情”而定,考虑多方面的因素!对于IBATIS而言,她带给我们的最大好处在于灵活控制sql与Java对象间的映射,过程化与面向对象化需求相结合的中间产物,在对待遗留系统、需自行优化sql提供性能,以及不具备控制数据库表设计权限而要置身度外提供DAO层接口实现时,IBATIS相对来说是您俱佳选择!因为,IBATIS核心的SQL Map框架能应用于设计不好的数据库甚至是设计不好的对象模型(尽管如此,我们依旧应当遵循最佳的设计原则,以便获得更清晰的设计方案和更好的性能)。
三、SQL Map是如何工作的?
SQL Map提供了一个简洁的框架,使用简单的XML描述文件将Java Bean,Map实现和基本数据类型的包装类(String,Integer等)映射成JDBC的PreparedStatement。下图展现了SQL MAP的地位及执行流程:
流程描述了SQL Maps的高层生命周期为: 1)将一个对象作为参数(对象可以是Java Bean,Map实现和基本类型的包装类),参数对象将为SQL修改语句和查询语句设定参数值;2) 执行mapped statement。这是SQL Maps最重要的步骤。SQL Map框架将创建一个PreparedStatement实例,用参数对象为PreparedStatement实例设定参数,执行PreparedStatement并从ResultSet中创建结果对象;3) 执行SQL的更新数据语句时,返回受影响的数据行数。执行查询语句时,将返回一个结果对象或对象的集合。和参数对象一样,结果对象可以是Java Bean,Map实现和基本数据类型的包装类。
四、使用ibatis 提供的ORM机制
使用ibatis 提供的ORM机制,1、对业务逻辑实现人员而言,面对的是纯粹的Java对象,这一层与通过Hibernate 实现ORM 而言基本一致; 2、对于具体的数据操作,Hibernate会自动生成SQL 语句,而ibatis 则要求开发者编写具体的SQL 语句。相对Hibernate等“全自动”ORM机制而言,,“全自动”ORM 实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行,而ibatis 以SQL开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间,作为“全自动”ORM 实现的一种有益补充,ibatis 的出现显得别具有意义。
五、如何配置IBATITS2使其工作?
欲使IBATIS工作,需要完成各类SQL MAP的映射工作,也包括数据库的相关信息。
首先,配置SqlMapConfig.xml,直接拷贝iBATIS-SqlMaps-2-Tutorial中介绍的信息就好,这里我给出一个样例方便大家直观感知:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <!-- 加载数据库连接信息 --> <properties resource="db.properties"/> <!--配置和优化SqlMapClient实例的各选项,是可选的 <settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true" errorTracingEnabled="true" maxRequests="32" maxSessions="10" maxTransactions="5" useStatementNamespaces="false" /> --> <!-- 配置Ibatis事务管理,使用JDBC事务类型,数据源使用Simple类型 --> <transactionManager type="JDBC"> <dataSource type="SIMPLE"> <property name="JDBC.Driver" value="${db_DriverClass}"/> <property name="JDBC.ConnectionURL" value="${db_url}"/> <property name="JDBC.Username" value="${db_user}"/> <property name="JDBC.Password" value="${db_pwd}"/> </dataSource> </transactionManager> <!-- 配置Ibatis要使用的SqlMap 的JavaBean映射文件信息 --> <sqlMap resource="com/eshore/ibatis/example/entity/User.xml"/> </sqlMapConfig>
其次,要给出数据库连接信息db.properties的样例:
db_DriverClass=oracle.jdbc.driver.OracleDriver db_url=jdbc:oracle:thin:@ip:port:sid db_user=test db_pwd=test123
再次,要给出实体类User.java及其映射文件User.xml样例:
package com.eshore.ibatis.example.entity; public class User { private String username; private String password; private String changedate; private String userlevel; // getter/setter methods omitted }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap> <typeAlias alias="User" type="com.eshore.ibatis.example.entity.User"/> <resultMap id="userResult" class="User"> <result property="username" column="USERNAME"/> <result property="password" column="PASSWORD"/> <result property="changedate" column="CHANGEDATE"/> <result property="userlevel" column="USERLEVEL"/> </resultMap> <insert id="insertUser" parameterClass="User"> insert into USER2( USERNAME, PASSWORD, CHANGEDATE, USERLEVEL ) values ( #username#, #password#, #changedate#, #userlevel# ) </insert> <select id="selectUserList" parameterClass="User" resultMap="userResult"> select * from USER2 where userlevel=#userlevel# </select> <select id="selectUserList2" parameterClass="String" resultMap="userResult"> select * from USER2 where userlevel=#userlevel# </select> <delete id="deleteUser" parameterClass="User"> DELETE USER2 WHERE userlevel=#userlevel# </delete> <select id="selectFdual" resultClass="Long"> select 1 from dual </select> </sqlMap>
最后,我们给出简单的测试样例:
package com.eshore.ibatis.example.test; import java.io.Reader; import org.junit.Test; import com.ibatis.common.resources.Resources; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.client.SqlMapClientBuilder; import com.eshore.ibatis.example.entity.User; public class TestUser { @Test public void testInsert(){ String resource = "SqlMapConfig.xml"; try { //读取配置文件 Reader reader = Resources.getResourceAsReader(resource); //得到SqlMapClient SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader); User user= new User(); user.setUsername("test"); user.setPassword("test"); //将所有的属性都set完毕,否则会被IBATITS拦截报空指针异常,即使数据库允许insert null值,稍后将会给此问题解决方案 //开始Ibatis事务 sqlMap.startTransaction(); sqlMap.insert("insertUser", user); //结束IBatis事务 sqlMap.commitTransaction(); } catch (Exception e) { e.printStackTrace(); } finally { sqlMap.endTransaction(); } } }
至此,IBATIS2之门已向您敞开,门内的美妙世界正期待你的体验!
注:允许该测试例唯一可能遇到的麻烦的是加载配置文件时路径信息问题,请确认SqlMapConfig.xml和db.properties在classpath下。若实在解决不了路径可先通过绝对路径途径绕过。