以下是iBatis映射文件的一个简单例子:
<?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>
<cacheModelid=”productCache” type=”LRU”>
<flushInterval hours="24"/>
<flushOnExecute statement="insertStudent"/>
<flushOnExecute statement="deleteStudentById"/>
<flushOnExecute statement="updateStudentById"/>
<property name=”size” value=”1000” />
</cacheModel>
<typeAlias alias="Student" type="com.edifier.data.Student"/>
<resultMap id="StudentResult" class="Student">
<resultproperty="sid" column="sid"/>
<resultproperty="sname" column="sname"/>
<resultproperty="major" column="major"/>
<resultproperty="birth" column="birth"/>
<resultproperty="sroce" column="sroce"/>
</resultMap>
<parameterMap id="StudentParameter" class=""Student"">
<parameterproperty="sid" jdbcType="int" javaType="int"/>
<parameterproperty="sname" jdbcType="varchar"javaType="String"/>
</parameterMap>
<select id="selectAllStudents" resultClass="Student" cacheModel=”product-cache”>
select
sid,sname,major,birth,score
from
student;
</select>
<select id="selectStudentById" parameterClass="int"resultClass="Student">
select
sid,sname,major,birth,score
from
student
where
sid= #sid#;
</select>
<insert id="insertStudent" parameterClass="Student">
insert into
student(sid,sname,major,birth,score)
values(#sid#,#sname#,#major#,#birth#,#score#);
</insert>
<delete id="deleteStudentById" parameterClass="int">
delete from
student
where
sid= #sid#;
</delete>
<update id="updateStudentById" parameterClass="student">
update student set
sname= #sname#,
major= #major#,
birth= #birth#,
score= #score#
wheresid = #sid#;
</update>
<!-- 模糊查询这里有两种方式,第一种在sql中这样写 sname like #sname#, 代码中这样写"%e%" 第二种是在sql中sname like '%$sname$%',代码中这样写"e".-->
<select id="selectStudentByName" parameterClass="String"resultClass="Student">
select
sid,sname,major,birth,score
from
student
where
snamelike '%$sname$%';
</select>
<insert id="insertStudentBySequence" parameterClass="Student">
insert into
student(sname,major,birth,score)
values(#sname#,#major#,#birth#,#score#);
<!—Mysql中用到的-->
<selectKey resultClass="int"keyProperty="sid" >
SELECT @@IDENTITY AS SID
</selectKey>
<!--以下在Oracle中用到
<selectKey resultClass="int" keyProperty="sid">
select studentPKSequence.nextVal as sid from dual;
</selectKey>
-->
</insert>
</sqlMap>
在这个例子中,xml的DTD和SqlMapConfig.xml配置文件的不一样要注意,不然会报错。例子中包括了cacheModel、typeAlias、resultMap、parameterMap、以及增删改,查询全部、根据id查询和模糊查询。其中增删改查都属于statement元素,下表总结了statement 类型及其属性:
Statement 类型 | 属性 |
<statement> | id parameterClass resultClass parameterMap resultMap cacheModel xmlResultName |
<insert> | id parameterClass parameterMap |
<update> | id parameterClass parameterMap |
<delete> | id parameterClass parameterMap |
<select> | id parameterClass resultClass parameterMap resultMap cacheModel |
<procedure> | id parameterClass resultClass parameterMap resultMap xmlResultName |
SQL 语句
在statement元素中可以写所有JDBC Driver所支持的sql语句。但是由于sql语句是镶嵌在xml文档中,所以有些特殊符号不能直接使用,例如:<、>。iBatis这里给出了解决办法。
<![CDATA[
select * from student score >#score#
]]>
自动生成的主键
iBatis中唯一使用了自动生成主键的就是<insert>元素,使用子元素<selectKey>来支持自动生成的主键。它同时支持预生成(如Oracle)和后生成(MySQL)。下面是两个例子:
<!—OracleSEQUENCE Example -->
<insertid="insertStudent-ORACLE" parameterClass="com.edifier.Student">
<selectKey resultClass="int"keyProperty="id" >
SELECT STOCKIDSEQUENCE.NEXTVAL ASID FROM DUAL
</selectKey>
insert into Student (SID,SName)
values (#id#,#name#)
</insert>
<!—Microsoft SQL Server IDENTITY Column Example -->
<insert id=" insertStudent-MS-SQL" parameterClass="com. edifier. Student">
insert into Student ( SName)
values (#name #)
<selectKey resultClass="int"keyProperty="id" >
SELECT @@IDENTITY AS ID
</selectKey>
</insert>
存储过程
通过<procedure>元素支持存储过程。下面的例子说明如何使用具有输出参数的存储过程。
<parameterMapid="swapParameters" class="map" >
<parameter property="email1"jdbcType="VARCHAR" javaType="java.lang.String" mode="INOUT"/>
<parameter property="email2"jdbcType="VARCHAR" javaType="java.lang.String" mode="INOUT"/>
</parameterMap>
<procedureid="swapEmailAddresses" parameterMap="swapParameters" >
{call swap_email_address (?, ?)}
</procedure>
调用上面的存储过程将同时互换两个字段(数据库表)和参数对象(Map)中的两个 email地址。如果参数的 mode 属性设为 INOUT 或 OUT,则参数对象的值被修改。否则保持不变。
parameterClass
parameterClass 属性的值是 Java 类的全限定名(即包括类的包名)。parameterClass 属性是可选的,但强烈建议使用。它的目的是限制输入参数的类型为指定的 Java 类,并优化框架的性能。如果您使用 parameterMap,则没有必要使用 parameterClass 属性。例如,如果要只允许 Java 类“com. edifier.Student”作为输入参数,可以这样作:
<statementid=”statementName” parameterClass=” com. edifier.Student”>
insert into PRODUCT values (#id#, #name#, #score#)
</statement>
parameterMap
属性 parameterMap 的值等于一个预先定义的<parameterMap>元素的名称。parameterMap属性很少使用,更多的是使用上面的 parameterClass 和 inline parameter(接下来会讨论)。parameterMap 的基本思想是定义一系列有次序的参数系列,用于匹配 JDBC PreparedStatement的值符号。例如:
<parameterMapid=”insert-student -param” class=”com. edifier. Student”>
<parameter property=”id”/>
<parameter property=” name”/>
</parameterMap>
<statementid=”insertStudent” parameterMap=”insert- student -param”>
insert into Student (SID, SNAME) values(?,?);
</statement>
上面的例子中,parameter map 的两个参数按次序匹配 SQL 语句中的值符号(?)。因此,第一个“?”号将被“id”属性的值替换,而第二个“?”号将被“name”属性的值替换。
Inline Parameter简介
现在简单介绍一下 inline parameter,详细讨论见后面章节。Inline parameter 可以嵌在
mappedstatement 内部使用。例如:
<statementid=”insertStudent” >
insert into Student(SID, SNAME)
values (#id#, #name#);
</statement>
以上例子中,内嵌的参数是#id#和#name#。每个参数代表一个 Java Bean 属性,用于给 SQL 语句中相应的位置赋值。上面例子中,Student 对象的 id 和 description 属性的值将会替换 SQL 语句中相应的符号。因此,对于 id=5,name=‘Steven’的Student 对象,SQL语句变为:
insert into Student (SID, SNAME) values (5, ‘Steven’);
resultClass
resultClass 属性的值是 Java 类的全限定名(即包括类的包名)。resultClass 属性可以让您指定一个 Java 类,根据 ResultSetMetaData 将其自动映射到 JDBC 的 ResultSet。只要是 JavaBean 的属性名称和 ResultSet 的列名匹配,属性自动赋值给列值。这使得查询 mappedstatement变得很短。例如:
<statementid="getPerson" parameterClass=”int” resultClass="com.edifier.Person">
SELECT PER_ID as id,
PER_FIRST_NAME as firstName,
PER_LAST_NAME as lastName,
PER_BIRTH_DATE as birthDate,
PER_WEIGHT_KG as weightInKilograms,
PER_HEIGHT_M as heightInMeters
FROM PERSON
WHERE PER_ID = #value#
</statement>
在上面的例子中,Person 类拥有属性包括 id,firstName,lastName,birthDate,weightInKilograms和 heightInMeters。每一个属性对应 SQL 查询语句一个列的别名(使用“as”关键字-标准的 SQL 语法)。一般情况下,列名和属性名称不匹配,就需要使用“as”关键字。当执行 mapped statement 时,Person 类将被初始化,从结果集中得到的列值将根据属性名和列名映射成 Person 对象的属性值。正如以前所说,使用 resultClass 的自动映射存在一些限制,无法指定输出字段的数据类型(如果需要的话),无法自动装入相关的数据(复杂属性),并且因为需要 ResultSetMetaData的信息,会对性能有轻微的不利影响。但使用 resultMap,这些限制都可以很容易解决。
resultMap
resultMap 是最常用和最重要的属性。ResultMap 属性的值等于预先定义的 resultMap 元素的 name 属性值(参照下面的例子)。使用 resultMap 可以控制数据如何从结果集中取出,以及哪一个属性匹配哪一个字段。不象使用 resultClass 的自动映射方法,resultMap 属性可以允许指定字段的数据类型,NULL 的替代值复杂类型映射(包括其他 Java Bean,集合类型和基本类型包装类)。关于 resultMap 的详细讨论放在以后的章节,这里只给出一个相关 statement 的 resultMap的例子。
<resultMapid=”get-student-result” class=”com.edifier.Student”>
<result property=”id” column=”SID”/>
<result property=”name” column=”SNAME”/>
</resultMap>
<statementid=”getStudent” resultMap=”get- student -result”>
select * from Student
</statement>
上面的例子中,通过 resultMap 的定义,查询语句得到的 ResultSet 被映射成Student对象。resultMap 定义的“id”属性值将赋予“SID”字段值,而“name”属性值将赋予“SNAME”字段值。注意 resultMap 支持“select *”,并不要求定义 ResultSet所有返回字段的映射。
cacheModel
cacheModel 的属性值等于指定的 cacheModel 元素的 name 属性值。属性 cacheModel 定义查询 mapped statement 的缓存。每一个查询 mapped statement 可以使用不同或相同的cacheModel。以下只给出个例子。
<cacheModelid="student-cache" imlementation="LRU">
<flushInterval hours="24"/>
<flushOnExecute statement="insertStudent"/>
<flushOnExecute statement="deleteStudentById"/>
<flushOnExecute statement="updateStudentById"/>
<property name=”size” value=”1000” />
</cacheModel>
<statementid=”selectAllStudent” parameterClass=”int” cacheModel=”product-cache”>
select sid,sname,major,birth,score from student;
</statement>
上面例子中,“selectAllStudent”的缓存使用 WEAK 引用类型,每 24 小时刷新一次,或当更新的操作发生时刷新。
Cache的类型有以下几种:
“MEMORY”(com.ibatis.db.sqlmap.cache.memory.MemoryCacheController)
“LRU”(com.ibatis.db.sqlmap.cache.lru.LruCacheController) --Least Recently Used
“FIFO”(com.ibatis.db.sqlmap.cache.fifo.FifoCacheController) --First In First Out
“OSCACHE”(com.ibatis.db.sqlmap.cache.oscache.OSCacheController)
1.MEMORY 编码结构:
<cacheModel id="student-cache"type="MEMORY">
<flushInterval hours="24"/>
<flushOnExecute statement="insertStudent"/>
<flushOnExecute statement="deleteStudentById"/>
<flushOnExecute statement="updateStudentById"/>
<property name=”reference-type”value=”WEAK” />
</cacheModel>
取不到对象再利用的identifiable pattern或者应用程序的内存不足的时候选用。
reference-type的值可以是下面的3个:
WEAK (default) | 当别的对象要用内存的时候,可以毫无保留的释放自己的内存。 |
SOFT | 当别的对象需要内存的时候,有可能不会释放自己的内存。 |
STRONG | cache时间到达以前,肯定不会释放内存。小的静态的经常被使用的区域可以使用这个选项。缺点是如果内存不足也不会释放内存。 |
2.LRU 编码结构:
<cacheModel id="student-cache"type="LRU">
<flushInterval hours="24"/>
<flushOnExecute statement="insertStudent"/>
<flushOnExecute statement="deleteStudentById"/>
<flushOnExecute statement="updateStudentById"/>
<property name=”size” value=”1000” />
</cacheModel>
应用程序的一部分内容经常被多人多次使用的时候选用。
3.FIFO 编码结构:
<cacheModel id="student-cache"type="FIFO">
<flushInterval hours="24"/>
<flushOnExecute statement="insertStudent"/>
<flushOnExecute statement="deleteStudentById"/>
<flushOnExecute statement="updateStudentById"/>
<property name=”size” value=”1000” />
</cacheModel>
连续的短时间的参照,以后就再不参照的时候选用。
4.OSCACHE 编码结构:
<cacheModel id="student-cache"type="OSCACHE">
<flushInterval hours="24"/>
<flushOnExecute statement="insertStudent"/>
<flushOnExecute statement="deleteStudentById"/>
<flushOnExecute statement="updateStudentById"/>
</cacheModel>
属性名 | 说明 |
cache.memory | cache放在内存中,false的话放在硬盘里 |
cache.key | ServletContext中存放cache的key名 |
cache.capacity | 存放的大小(这个一直不知道单位是什么,配置文件里写的是条数,我怎么感觉设成50都能显示1000个) |
cache.path | cache保存的路径 |
cache.unlimited.disk | 无限cache,默认是false,这时候就会有限制,参照cache.capacity来分配硬盘空间 |