让我们重回到车辆管理系统和张三的故事中。
在
iBATIS SQL Maps
的世界里也存在
one-to-many
、
many-to-one
的关系,想必你已经对这些概念驾轻就熟了。好!还是每个
People
对应多条
AutoInfo
信息。
本系列文章第一部分提到过
iBATIS SQL Maps
的映射文件个数可以人为设定,但是,把一组有共性的操作放在一起是首选策略。下面我们看看为张三首次买车所生成的映射文件是怎样的:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "
http://www.ibatis.com/dtd/sql-map-2.dtd
">
<sqlMap namespace="AutoMag">
<insert id="insertPeople" parameterClass="bo.People"> <![CDATA[ insert into people (name, address) values (#name#, #address#) ]]> <selectKey resultClass="java.lang.Integer" keyProperty="id"> <![CDATA[ select last_insert_id(); ]]> </selectKey> </insert> <insert id="insertAutoInfo" parameterClass="bo.AutoInfo"> <![CDATA[ insert into auto_info (license_plate, owner_no) VALUES (#licensePlate#, #ownerNo.id#) ]]> </insert> </sqlMap>
|
sqlMap
sqlMap
元素拥有属性
namespace="…"
,定义了该
XML
文件命名空间。如果你在配置文件
SqlMapConfig.xml
中指定了
settings
元素的属性
useStatementNamespaces="true"
,那么就可以按照命名空间的方式访问
Mapped statement
,比如
namespace="
AutoMag
"
,相应
Java
代码:
sqlMap.insert("AutoMag.insertPeople",people)
。这样做是为了防止不同映射文件中出现同名
Mapped statement
而产生冲突。什么是
Mapped statement
?
Mapped statement
iBATIS SQL Maps
的核心概念就是
Mapped statement
!
Mapped Statement
可以使用任意的
SQL
语句,利用
POJO
、
原始变量
及其
Wrapper Class
作为输入(
parameter class
)和输出(
result class
)。
Mapped Statement
包含以下几种类型:
insert
对应数据库的
insert
操作,该操作返回本次操作插入记录的主键值。
select
对应数据库的
select
操作,该操作返回特定的
POJO
或
对象。
update
对应数据库的
update
操作,该操作返回被更新的记录个数。
delete
对应数据库的
delete
操作,该操作返回被删除的记录个数。
procedure
对应数据库存储过程。
statement
类型最为通用,可以代替以上所有的类型。但由于缺乏操作直观性故不推荐。
insert id="insertPeople" parameterClass="bo.People"
定义了
insert
类型的
Mapped Statement
。属性
id="insertPeople"
定义操作名称,
parameterClass="bo.People"
定义传入参数为
People
对象实例,框架可确保其属性持久化到数据库相应字段中。由于
SQL
语句会包含
“<>”
这样的符号,容易和
XML
产生
冲突,放进
<![CDATA[
……
]]>
区域就可避免。
insert into people (name, address) values (#name#, #address#)
,
是一条普通的
SQL
语句,
“#name#
、
#address#”
利用
Java
反射机制访问
People
对象实例的相应属性。
selectKey resultClass="java.lang.Integer" keyProperty="id"
iBATIS SQL Maps
通过
<insert>
元素的子元素
<selectKey>
来支持主键自动生成。
resultClass="java.lang.Integer"
定义返回对象为
int
的
Wrapper Class
。
keyProperty="id"
定义了主键名称。本例是
MySQL
主键生成方式,参考官方文档,
MySQL
的主键生成无需人为来控制,也就是说可不使用
<selectKey>
而由数据库自动处理。但我测试发现,在执行
insert
操作以后,程序没有返回
本次操作插入记录的主键值。在官方论坛上也有很多用户提出这样的疑惑,作者的答复是:这和
JDBC Driver
有关系。不可能把驱动一一测试吧?一劳永逸的办法是使用
<selectKey>
元素。以下是
Oracle
和
SQL Server
主键生成方法:
< !- Oracle -> <insert id="insertProduct-ORACLE" parameterClass="com.domain.Product"> <selectKey resultClass="int" keyProperty="id" > SELECT STOCKIDSEQUENCE.NEXTVAL AS ID FROM DUAL </selectKey> insert into PRODUCT (PRD_ID,PRD_DESCRIPTION) values (#id#,#description#) </insert>
<!- Microsoft SQL Server -> <insert id="insertProduct-MS-SQL" parameterClass="com.domain.Product"> insert into PRODUCT (PRD_DESCRIPTION) values (#description#) <selectKey resultClass="int" keyProperty="id" > SELECT @@IDENTITY AS ID </selectKey> </insert>
|
insert into auto_info (license_plate, owner_no) VALUES (#licensePlate#, #ownerNo.id#)
在插入了
people
记录后,要为
auto_info
插入记录。基本原则和之前遇到过的一样,只是
”
owner_no”
这个字段值由
AutoInfo
对象属性
”
ownerNo”
获得,该属性类型为
People
。这是由于我沿用了
Hibernate
产生的
POJO
,如果你愿意,完全可以把
”
ownerNo”
替换为
Integer
类型。
编程中几个关键对象
com.ibatis.common.resources.Resources
对象负责从
XML
得到
java.io.Reader
抽象类的实例,供工厂方法调用。
com.ibatis.sqlmap.client.SqlMapClientBuilder
构造
SqlMapClient
实例。
com.ibatis.sqlmap.client.SqlMapClient
是
iBATIS SQL Maps
核心组件,可以说我们的编程工作都是围绕着它展开。
形成的
one-to-many
保存如下:
package test;
import java.io.Reader;
import com.ibatis.sqlmap.client.*; import com.ibatis.common.resources.*;
import bo.*;
public class AutoMag {
private Reader reader; private SqlMapClient sqlMap; private String resource = "SqlMapConfig.xml"; public void insertPeople() throws Exception{ try{ reader = Resources.getResourceAsReader(resource); sqlMap=SqlMapClientBuilder.buildSqlMapClient(reader); sqlMap.startTransaction(); People people=new People(); people.setName("张三"); people.setAddress("中国"); sqlMap.insert("insertPeople",people);
AutoInfo autoInfo=new AutoInfo(); autoInfo.setLicensePlate("A00001"); autoInfo.setOwnerNo(people); sqlMap.insert("insertAutoInfo",autoInfo); sqlMap.commitTransaction(); }finally{ sqlMap.endTransaction(); } } }
|
程序和
Hibernate
写法差不多,我感觉甚至比
Hibernate
更简单。我可以显示的进行
insert
操作,符合传统
JDBC
编程习惯。
iBATIS SQL Maps
支持自动事务处理,可以不用写明
startTransaction
、
commitTransaction
。但如果
People insert
操作成功,而
AutoInfo insert
操作失败,就破坏了两次
insert
操作的原子性。最后
endTransaction
包含异常情况下的回滚事务和关闭连接池连接两种功能。
请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处:http://www.blogjava.net/rosen