sql映射文件
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="dao.AccountDao">
</mapper>
包括子元素:
cache-配置给定命名空间的缓存。
cache-ref–从其他命名空间引用缓存配置。
resultMap–最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。
parameterMap–已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。
sql–可以重用的SQL块,也可以被其他语句引用。
insert–映射插入语句
update–映射更新语句
delete–映射删除语句
select–映射查询语句
select
<selectid=”selectPerson”parameterType=”int”resultType=”hashmap”>
SELECT*FROMPERSONWHEREID=#{id}
</select>
这个语句被定义为selectPerson,使用一个int(或Integer)类型的参数,并返回一个HashMap类型的对象,其中的键是列名,值是列对应的值
#{id}
这就告诉MyBatis使用JDBC创建一个参数,这样的一个参数在SQL中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:
//SimilarJDBCcode,NOTMyBatis…
StringselectPerson=“SELECT*FROMPERSONWHEREID=?”;
PreparedStatementps=conn.prepareStatement(selectPerson);
ps.setInt(1,id);
select有很多参数
id
在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType
将会传入这条语句的参数类的完全限定名或别名。
parameterMap
这是引用外部parameterMap的已经被废弃的方法。使用内联参数映射和parameterType属性。
resultType
从这条语句中返回的期望类型的类的完全限定名或别名。注意集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用resultType或resultMap,但不能同时使用。
resultMap
命名引用外部的resultMap。返回map是MyBatis最具力量的特性,对其有一个很好的理解的话,许多复杂映射的情形就能被解决了。使用resultMap或resultType,但不能同时使用。
flushCache
将其设置为true,不论语句什么时候被带哦用,都会导致缓存被清空。默认值:false。
useCache
将其设置为true,将会导致本条语句的结果被缓存。默认值:true。
timeout
这个设置驱动程序等待数据库返回请求结果,并抛出异常时间的最大等待值。默认不设置(驱动自行处理)。
fetchSize
这是暗示驱动程序每次批量返回的结果行数。默认不设置(驱动自行处理)。
statementType
STATEMENT,PREPARED或CALLABLE的一种。这会让MyBatis使用选择使用Statement,PreparedStatement或CallableStatement。默认值:PREPARED。
resultSetType
FORWARD_ONLY|SCROLL_SENSITIVE|SCROLL_INSENSITIVE中的一种。默认是不设置(驱动自行处理)。
insert,update,delete
属性
id
在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType
将会传入这条语句的参数类的完全限定名或别名。
parameterMap
这是引用外部parameterMap的已经被废弃的方法。使用内联参数映射和parameterType属性。
flushCache
将其设置为true,不论语句什么时候被带哦用,都会导致缓存被清空。默认值:false。
timeout
这个设置驱动程序等待数据库返回请求结果,并抛出异常时间的最大等待值。默认不设置(驱动自行处理)。
statementType
STATEMENT,PREPARED或CALLABLE的一种。这会让MyBatis使用选择使用Statement,PreparedStatement或CallableStatement。默认值:PREPARED。
useGeneratedKeys
(仅对insert有用)这会告诉MyBatis使用JDBC的getGeneratedKeys方法来取出由数据(比如:像MySQL和SQLServer这样的数据库管理系统的自动递增字段)内部生成的主键。默认值:false。
keyProperty
(仅对insert有用)标记一个属性,MyBatis会通过getGeneratedKeys或者通过insert语句的selectKey子元素设置它的值。默认:不设置。
例子:
<insertid="insertAuthor"parameterType="domain.blog.Author">
insertintoAuthor(id,username,password,email,bio)
values(#{id},#{username},#{password},#{email},#{bio})
</insert>
<updateid="updateAuthor"parameterType="domain.blog.Author">
updateAuthorset
username=#{username},
password=#{password},
email=#{email},
bio=#{bio}
whereid=#{id}
</update>
<deleteid="deleteAuthor”parameterType="int">
deletefromAuthorwhereid=#{id}
</delete>
如果你的数据库支持自动生成主键的字段(比如MySQL和SQLServer),那么你可以设置useGeneratedKeys=”true”,而且设置keyProperty到你已经做好的目标属性上。例如,如果上面的Author表已经对id使用了自动生成的列类型,那么语句可以修改为:
<insertid="insertAuthor"parameterType="domain.blog.Author"
useGeneratedKeys=”true”keyProperty=”id”>
insertintoAuthor(username,password,email,bio)
values(#{username},#{password},#{email},#{bio})
</insert>
MyBatis有另外一种方法来处理数据库不支持自动生成类型,或者可能JDBC驱动不支持自动生成主键时的主键生成问题。
这里有一个简单(甚至很傻)的示例,它可以生成一个随机ID(可能你不会这么做,但是这展示了MyBatis处理问题的灵活性,因为它并不真的关心ID的生成):
<insertid="insertAuthor"parameterType="domain.blog.Author">
<selectKeykeyProperty="id"resultType="int"order="BEFORE">
selectCAST(RANDOM()*1000000asINTEGER)afromSYSIBM.SYSDUMMY1
</selectKey>
insertintoAuthor
(id,username,password,email,bio,favourite_section)
values
(#{id},#{username},#{password},#{email},#{bio},
#{favouriteSection,jdbcType=VARCHAR}
)
</insert>
在上面的示例中,selectKey元素将会首先运行,Author的id会被设置,然后插入语句会被调用。这给你了一个简单的行为在你的数据库中来处理自动生成的主键,而不需要使你的Java代码变得复杂。
selectKey元素描述如下:
keyProperty
selectKey语句结果应该被设置的目标属性。
resultType
结果的类型。MyBatis通常可以算出来,但是写上也没有问题。MyBatis允许任何简单类型用作主键的类型,包括字符串。
order
这可以被设置为BEFORE或AFTER。如果设置为BEFORE,那么它会首先选择主键,设置keyProperty然后执行插入语句。如果设置为AFTER,那么先执行插入语句,然后是selectKey元素-这和如Oracle数据库相似,可以在插入语句中嵌入序列调用。
statementType
和前面的相同,MyBatis支持STATEMENT,PREPARED和CALLABLE语句的映射类型,分别代表PreparedStatement和CallableStatement类型。
sql
这个元素可以被用来定义可重用的SQL代码段,可以包含在其他语句中。比如:
<sqlid=”userColumns”>id,username,password</sql>
这个SQL片段可以被包含在其他语句中,例如:
<selectid=”selectUsers”parameterType=”int”resultType=”hashmap”>
select<includerefid=”userColumns”/>
fromsome_table
whereid=#{id}
</select>
Parameters
简单的参数传递
<selectid=”selectUsers”parameterType=”int”resultType=”User”>
selectid,username,password
fromusers
whereid=#{id}
</select>
然而,如果你传递了一个复杂的对象,那么MyBatis的处理方式就会有一点不同。比如:
<insertid=”insertUser”parameterType=”User”>
insertintousers(id,username,password)
values(#{id},#{username},#{password})
</insert>
如果User类型的参数对象传递到了语句中,它的id、username和password属性将会被查找,然后它们的值就被传递到参数中。
这点对于传递参数到语句中非常好。但是对于参数映射也有一些其他的特性。
首先,像MyBatis的其他功能,参数可以指定一个确定的数据类型。
#{propertyName,javaType=int,jdbcType=NUMERIC}
如果参数对象是一个hashMap,javaType应该被保证使用正确类型处理器。
如果查询某个值为空的列null,JDBCType就需要写了。
如果使用自定义类型处理器,你需要指定一个类型处理器的类名或者缩写别名,如
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
最后,mode属性允许你指定IN,OUT或INOUT参数。如果参数为OUT或INOUT,参数对象属性的值将会被改变,否则保持不变。注意!要确保始终只使用JDBC标准的存储过程语法。参考JDBC的CallableStatement文档以获得更详细的信息。
字符串替换
#{}格式的语法会创建参数华。如果不想创建参数化,使用
${columnName}
方式,将直接用参数值替换sql中的该部分内容。
resultMap
首先需要了解resultType的作用。
<selectid=”selectUsers”parameterType=”int”resultType=”hashmap”>
selectid,username,hashedPassword
fromsome_table
whereid=#{id}
</select>
或者使用javabean
packagecom.someapp.model;
publicclassUser{
privateintid;
privateStringusername;
privateStringhashedPassword;
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetUsername(){
returnusername;
}
publicvoidsetUsername(Stringusername){
this.username=username;
}
publicStringgetHashedPassword(){
returnhashedPassword;
}
publicvoidsetHashedPassword(StringhashedPassword){
this.hashedPassword=hashedPassword;
}
}
<selectid=”selectUsers”parameterType=”int”
resultType=”com.someapp.model.User”>
selectid,username,hashedPassword
fromsome_table
whereid=#{id}
</select>
因为数据库字段和属性一一对应,所有会自动匹配。如果添加的类型别名定义。那么可以使用别名来设置。
<!--InConfigXMLfile-->
<typeAliastype=”com.someapp.model.User”alias=”User”/>
<!--InSQLMappingXMLfile-->
<selectid=”selectUsers”parameterType=”int”
resultType=”User”>
selectid,username,hashedPassword
fromsome_table
whereid=#{id}
</select>
如果字段名和数据库列名不是一一对应的,可以使用sql语句的as语法,来定义列别名,让它和字段对应
<selectid=”selectUsers”parameterType=”int”resultType=”User”>
select
user_idasid,
user_nameasuserName,
hashed_passwordashashedPassword
fromsome_table
whereid=#{id}
</select>
而resultMap则可以更好的解决上面的问题
//实体类
packagecom.liyixing.ibatis.model;
importjava.io.Serializable;
publicclassAccountimplementsSerializable{
/**
*
*/
privatestaticfinallongserialVersionUID=1L;
privateintid;
privateStringuserName;
privateintage;
publicAccount(){
super();
}
publicAccount(intid,StringuserName,intage){
super();
this.id=id;
this.userName=userName;
this.age=age;
}
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetUserName(){
returnuserName;
}
publicvoidsetUserName(StringuserName){
this.userName=userName;
}
publicintgetAge(){
returnage;
}
publicvoidsetAge(intage){
this.age=age;
}
}
映射配置
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="com.liyixing.ibatis.dao.IAccountDao">
<resultMaptype="com.liyixing.ibatis.model.Account"id="account">
<idproperty="id"column="ID"/>
<resultproperty="userName"column="USER_NAME"/>
<resultproperty="age"column="AGE"/>
</resultMap>
<selectid="getAccount"parameterType="int"resultMap="account">
SELECT
ID,USER_NAME,AGEFROMaccount
WHEREID=#{id}
</select>
<!---->
<!--<selectid="getAccount"parameterType="string"-->
<!--resultType="com.liyixing.ibatis.model.Account">-->
<!--SELECTID,USER_NAME,AGEFROMaccount-->
<!--WHEREUSER_NAME=#{userName}-->
<!--</select>-->
<insertid="addAccount"parameterType="com.liyixing.ibatis.model.Account">
INSERTINTOaccount
(USER_NAME,AGE)
VALUES
(#{userName},#{age})
<selectKeyresultType="int"keyProperty="id">
select
last_insert_id()asIDfromaccountlimit1
</selectKey>
</insert>
</mapper>
以上映射配置中可以看到一个resultMap元素
而select的配置中,不再使用resultType,而是改为resultMap
表结构
CREATETABLE`account`(
`ID`int(11)NOTNULLauto_increment,
`USER_NAME`varchar(50)defaultNULL,
`AGE`int(11)defaultNULL,
PRIMARYKEY(`ID`)
)ENGINE=MyISAMDEFAULTCHARSET=utf8;
这里不再使用resultType,而是使用了resultMap。
resultMap也用来做关联关系等操作。
resultMap元素子元素
constructor–类在实例化时,用来注入结果到构造方法中
idArg–ID参数;标记结果作为ID可以帮助提高整体效能
arg–注入到构造方法的一个普通结果
id–一个ID结果;标记结果作为ID可以帮助提高整体效能
result–注入到字段或JavaBean属性的普通结果
association–一个复杂的类型关联;许多结果将包成这种类型
嵌入结果映射–结果映射自身的关联,或者参考一个
collection–复杂类型的集
嵌入结果映射–结果映射自身的集,或者参考一个
discriminator–使用结果值来决定使用哪个结果映射
case–基于某些值的结果映射
嵌入结果映射–这种情形结果也映射它本身,因此可以包含很多相同的元素,或者它可以参照一个外部的结果映射。
id,result
这些是结果映射最基本内容。id和result都映射一个单独列的值到简单数据类型(字符串,整型,双精度浮点数,日期等)的单独属性或字段。
这两者之间的唯一不同是id表示的结果将是当比较对象实例时用到的标识属性。这帮助来改进整体表现,特别是缓存和关联关系映射。
他们的属性:
property
映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同的JavaBeans的属性,那么就会使用。否则MyBatis将会寻找给定名称的字段。这两种情形你可以使用通常点式的复杂属性导航。比如,你可以这样映射一些东西:“username”,或者映射到一些复杂的东西:“address.street.number”。
column
从数据库中得到的列名,或者是列名的重命名标签。这也是通常和会传递给resultSet.getString(columnName)方法参数中相同的字符串。
javaType
一个Java类的完全限定名,或一个类型别名(参加上面内建类型别名的列表)。如果你映射到一个JavaBean,MyBatis通常可以断定类型。然而,如果你映射到的是HashMap,那么你应该明确地指定javaType来保证所需的行为。
jdbcType
在这个表格之后的所支持的JDBC类型列表中的类型。JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。这是JDBC的需要,而不是MyBatis的。如果你直接使用JDBC编程,你需要指定这个类型-但仅仅对可能为空的值。
typeHandler
我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。
支持的JDBC类型
BIT
FLOAT
CHAR
TIMESTAMP
OTHER
UNDEFINED
TINYINT
REAL
VARCHAR
BINARY
BLOB
NVARCHAR
SMALLINT
DOUBLE
LONGVARCHAR
VARBINARY
CLOB
NCHAR
INTEGER
NUMERIC
DATE
LONGVARBINARY
BOOLEAN
NCLOB
BIGINT
DECIMAL
TIME
NULL
CURSOR
<resultMaptype="com.liyixing.ibatis.model.Account"id="account">
<idproperty="id"column="ID"/>
<resultproperty="userName"column="USER_NAME"/>
<resultproperty="age"column="AGE"/>
</resultMap>
constructor构造方法
<constructor>
<idArgcolumn="id"javaType="int"/>
<argcolumn=”username”javaType=”String”/>
</constructor>
构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。MyBatis也支持私有属性和私有JavaBeans属性来达到这个目的,但是我们可能更青睐构造方法注入。
<resultMaptype="com.liyixing.ibatis.model.Account"id="account">
<constructor>
<idArgcolumn="ID"javaType="_int"/>
<argcolumn="USER_NAME"javaType="string"/>
</constructor>
<idproperty="id"column="ID"/>
<resultproperty="userName"column="USER_NAME"/>
<resultproperty="age"column="AGE"/>
</resultMap>
注意上面的情况,我们不仅仅在构造定义了构造,而且定义了属性id,和username,这个时候ibatis会在构造的时候把id和userName两个参数传递进去,因为后面还定义了id属性值id,和result属性值userName,那么它还会再构造完毕后,再次把id和userName传递进去。
还有一点就是参数定义的顺序要和我们在constructor中定义的顺序一样,因为java反射机制无法获取参数的名字的。
他们的属性:
column
来自数据库的类名,或重命名的列标签。这和通常传递给resultSet.getString(columnName)方法的字符串是相同的。
javaType
一个Java类的完全限定名,或一个类型别名(参加上面内建类型别名的列表)。如果你映射到一个JavaBean,MyBatis通常可以断定类型。然而,如果你映射到的是HashMap,那么你应该明确地指定javaType来保证所需的行为。
jdbcType
在这个表格之前的所支持的JDBC类型列表中的类型。JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。这是JDBC的需要,而不是MyBatis的。如果你直接使用JDBC编程,你需要指定这个类型-但仅仅对可能为空的值。
typeHandler
我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。
association一对一关联。
添加表address
CREATETABLE`address`(
`ID`int(11)NOTNULLauto_increment,
`ADDRESS`varchar(200)defaultNULL,
PRIMARYKEY(`ID`)
)ENGINE=MyISAMDEFAULTCHARSET=utf8;
修改account表结构
CREATETABLE`account`(
`ID`int(11)NOTNULLauto_increment,
`USER_NAME`varchar(50)defaultNULL,
`AGE`int(11)defaultNULL,
`ADDRESS_ID`int(11)NOTNULL,
PRIMARYKEY(`ID`)
)ENGINE=MyISAMDEFAULTCHARSET=utf8;
增加了一个ADDRESS_ID字段
添加类Address
packagecom.liyixing.ibatis.model;
importjava.io.Serializable;
publicclassAddressimplementsSerializable{
/**
*
*/
privatestaticfinallongserialVersionUID=1L;
privateintid;
privateStringaddress;
publicAddress(){
super();
}
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetAddress(){
returnaddress;
}
publicvoidsetAddress(Stringaddress){
this.address=address;
}
}
修改Account实体,添加属性
privateAddressaddress;
Account映射中的resultMap
<resultMaptype="com.liyixing.ibatis.model.Account"id="account">
<constructor>
<idArgcolumn="ACCOUNT_ID"javaType="_int"/>
<argcolumn="ACCOUNT_USER_NAME"javaType="string"/>
</constructor>
<idproperty="id"column="ACCOUNT_ID"/>
<resultproperty="userName"column="ACCOUNT_USER_NAME"/>
<resultproperty="age"column="ACCOUNT_AGE"/>
<associationproperty="address"column="ACCOUNT_ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address">
<idproperty="id"column="ADDRESS_ID"/>
<resultproperty="address"column="ADDRESS"/>
</association>
</resultMap>
<associationproperty="address"column="ACCOUNT_ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address">这里的javaType,官方文档说是会自动算出类型,但是我不写javaType发现它获取的Classtype是null。抛出了空指针异常。所以我写上了。安全一些。
column="ACCOUNT_ADDRESS_ID"这个属性主要是应用于嵌套查询方式。
select
<selectid="getAccount"parameterType="int"resultMap="account">
SELECT
a.IDasACCOUNT_ID,
a.USER_NAMEasACCOUNT_USER_NAME,
a.AGEas
ACCOUNT_AGE,
a.ADDRESS_IDasACCOUNT_ADDRESS_ID,
ad.IDas
ADDRESS_ID,
ad.ADDRESSasADDRESS
FROMaccountasa
leftjoinaddressasad
onad.ID
=a.ADDRESS_ID
WHEREa.ID=#{id}
</select>
我们需要告诉batis如何加载关联。有两种方式。
嵌套查询,通过执行另一个sql映射语句来返回。
嵌套结果,使用嵌套结果映射来同时返回本对象和关联的对象。我上面使用的就是这一种。
association属性:
property
映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同的JavaBeans的属性,那么就会使用。否则MyBatis将会寻找给定名称的字段。这两种情形你可以使用通常点式的复杂属性导航。比如,你可以这样映射一些东西:“username”,或者映射到一些复杂的东西:“address.street.number”。
column
应用于嵌套查询语句方式。来自数据库的类名,或重命名的列标签。这和通常传递给resultSet.getString(columnName)方法的字符串是相同的。
注意:要处理复合主键,你可以指定多个列名通过column=”{prop1=col1,prop2=col2}”这种语法来传递给嵌套查询语句。这会引起prop1和prop2以参数对象形式来设置给目标嵌套查询语句。
javaType
一个Java类的完全限定名,或一个类型别名(参加上面内建类型别名的列表)。如果你映射到一个JavaBean,MyBatis通常可以断定类型。然而,如果你映射到的是HashMap,那么你应该明确地指定javaType来保证所需的行为。
jdbcType
在这个表格之前的所支持的JDBC类型列表中的类型。JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。这是JDBC的需要,而不是MyBatis的。如果你直接使用JDBC编程,你需要指定这个类型-但仅仅对可能为空的值。
typeHandler
我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。
嵌套查询方式:
select属性
<resultMaptype="com.liyixing.ibatis.model.Account"id="account">
<constructor>
<idArgcolumn="ID"javaType="_int"/>
<argcolumn="USER_NAME"javaType="string"/>
</constructor>
<idproperty="id"column="ACCOUNT_ID"/>
<resultproperty="userName"column="USER_NAME"/>
<resultproperty="age"column="AGE"/>
<associationproperty="address"column="ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address"select="getAddress">
</association>
</resultMap>
这里的关联配置中,使用select属性,值是getAddress,batis会调用这个id=getAddress的select,也就是说会执行两个sql语句。
associationproperty="address"column="ADDRESS_ID"的column属性会作为参数传递给参数语句中id为getAddress的参数语句。
<selectid="getAddress"parameterType="int"
resultType="com.liyixing.ibatis.model.Address">
select*fromaddresswhereid=#{id}
</select>
<selectid="getAccount"parameterType="int"resultMap="account">
SELECTID,
USER_NAME,
AGE,
ADDRESS_ID
FROMaccount
WHEREID=#{id}
</select>
这种方式会造成sql语句执行过多。
如果我们想在address中,对account进行关联。表结构,模型都不变,添加address的映射文件。
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="com.liyixing.ibatis.dao.AddressDao">
<resultMaptype="com.liyixing.ibatis.model.Address"id="address">
<idproperty="id"column="ID"/>
<resultproperty="address"column="ADDRESS"/>
<associationproperty="account"column="ID"
javaType="com.liyixing.ibatis.model.Account"select="getAccount">
</association>
</resultMap>
<selectid="getAddress"parameterType="int"resultMap="address">
select*
fromaddresswhereid=#{id}
</select>
<selectid="getAccount"parameterType="int"
resultType="com.liyixing.ibatis.model.Account">
select*fromaccountwhereADDRESS_ID=#{id}
</select>
</mapper>
可以从上面的例子中看出来。<associationproperty="account"column="ID"
javaType="com.liyixing.ibatis.model.Account"select="getAccount">这个元素的column属性会被作为参数传递过去给对应的sql。
collection集合
添加表message,是account用户的发言
CREATETABLE`message`(
`ID`int(11)NOTNULLauto_increment,
`ACCOUNT_ID`int(11)NOTNULL,
`MESSAGE`varchar(255)defaultNULL,
PRIMARYKEY(`ID`)
)ENGINE=MyISAMDEFAULTCHARSET=utf8;
<resultMaptype="com.liyixing.ibatis.model.Account"id="account">
<constructor>
<idArgcolumn="ID"javaType="_int"/>
<argcolumn="USER_NAME"javaType="string"/>
</constructor>
<idproperty="id"column="ACCOUNT_ID"/>
<resultproperty="userName"column="USER_NAME"/>
<resultproperty="age"column="AGE"/>
<associationproperty="address"column="ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address"select="getAddress">
</association>
<collectionproperty="messages"javaType="ArrayList"
column="ID"ofType="com.liyixing.ibatis.model.Message"
select="selectMyMessages">
<idproperty="id"column="ID"/>
<resultproperty="message"column="MESSAGE"/>
</collection>
</resultMap>
<selectid="selectMyMessages"parameterType="int"
resultType="com.liyixing.ibatis.model.Message">
select*frommessagewhereACCOUNT_ID=#{accountId}
</select>
以上的配置<collectionproperty="messages"javaType="ArrayList"
column="ID"ofType="com.liyixing.ibatis.model.Message"
select="selectMyMessages">中依然可以看到column会被做为参数传递过去。
一个嵌套结果的方式
<resultMaptype="com.liyixing.ibatis.model.Account"id="account">
<constructor>
<idArgcolumn="ACOUNT_ID"javaType="_int"/>
<argcolumn="ACOUNT_USER_NAME"javaType="string"/>
</constructor>
<idproperty="id"column="ACCOUNT_ID"/>
<resultproperty="userName"column="ACOUNT_USER_NAME"/>
<resultproperty="age"column="ACOUNT_AGE"/>
<collectionproperty="messages"javaType="ArrayList"
ofType="com.liyixing.ibatis.model.Message">
<idproperty="id"column="MESSAGE_ID"/>
<resultproperty="message"column="MESSAGE"/>
</collection>
</resultMap>
这里的column可以省略。
ofType属性:
这个属性用来区分JavaBean(或字段)属性类型,是用来指定集合中的包含(泛型)类型的。
discriminator鉴别器
类似于java的switch可以根据结果制定实际的映射器
有一个Message类
packagecom.liyixing.ibatis.model;
importjava.io.Serializable;
publicclassMessageimplementsSerializable{
/**
*
*/
privatestaticfinallongserialVersionUID=1L;
privateintid;
privateAccountaccount;
privateStringmessage;
privateshortmessageType=(short)-1;
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicAccountgetAccount(){
returnaccount;
}
publicvoidsetAccount(Accountaccount){
this.account=account;
}
publicStringgetMessage(){
returnmessage;
}
publicvoidsetMessage(Stringmessage){
this.message=message;
}
publicshortgetMessageType(){
returnmessageType;
}
publicvoidsetMessageType(shortmessageType){
this.messageType=messageType;
}
}
这里的messageType=-1,是因为数据库中我的测试数据,是一条message记录的messageType=0,另一条messageType=1;而java的short自动初始化的时候,值也是0.改成-1就能更清楚的看到结果。
message.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="com.liyixing.ibatis.dao.IMessageDao">
<resultMaptype="com.liyixing.ibatis.model.Message"id="message">
<idproperty="id"column="ID"/>
<discriminatorjavaType="_int"column="MESSAGE_TYPE">
<casevalue="1"resultMap="messageType"></case>
</discriminator>
</resultMap>
<resultMaptype="com.liyixing.ibatis.model.Message"id="messageType">
<resultproperty="messageType"column="MESSAGE_TYPE"/>
</resultMap>
</mapper>
这里有<discriminatorjavaType="_int"column="MESSAGE_TYPE">
<casevalue="1"resultMap="messageType"></case>
</discriminator>
当值为1才会映射MESSAGE_TYPE
Account.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="com.liyixing.ibatis.dao.IAccountDao">
<resultMaptype="com.liyixing.ibatis.model.Account"id="account">
<idproperty="id"column="ID"/>
<resultproperty="userName"column="USER_NAME"/>
<collectionproperty="messages"javaType="ArrayList"
column="ID"ofType="com.liyixing.ibatis.model.Message"select="getMyMessage">
</collection>
</resultMap>
<selectid="getMyMessage"parameterType="_int"
resultMap="message">
SELECTID,
USER_ID,
MESSAGE,
MESSAGE_TYPE
FROMmessage
WHEREUSER_ID=#{id}
</select>
<selectid="getAccount"parameterType="_int"resultMap="account">
SELECT*
FROMaccountWHEREID=#{id}
</select>
</mapper>
这里我同时测试了collection和跨文件访问resultMap,发现跨文件访问resultMap是允许的。
调用getAccount的select,发现当message_type字段值为1,才会调用id=messageType的resultMap