- 浏览: 961686 次
- 性别:
- 来自: 江西上饶
文章分类
- 全部博客 (460)
- p.spring (56)
- p.maven (20)
- p.ant (17)
- p.jee (18)
- p.jse (33)
- p.ofbiz (31)
- p.软件工程 (8)
- p.struts2 (5)
- p.hibernate (5)
- linux (25)
- 设计模式 (2)
- p.javascript (11)
- 硬件 (1)
- p.jsp (2)
- p.windows批处理 (1)
- 操作系统问题 (5)
- 算法 (1)
- p.mysql (7)
- p.sql (5)
- p.c (1)
- google产品 (0)
- 内存 (1)
- p.struts (1)
- p.freemarker (7)
- p.css (4)
- p.log4j (10)
- p.html (3)
- 淘宝产品 (0)
- 其他 (3)
- 编译器 (0)
- svn (4)
- p.spring.security (11)
- 图形 (0)
- p.xml (1)
- p.ssh (0)
- p.jquery (4)
- p.jdbc (3)
- p.flex (0)
- p.c++ (0)
- p.c#Net (0)
- p.assembly (0)
- p.sqlserver (0)
- p.其他 (3)
- p.webwork (21)
- p.wap (12)
- p.cglib (1)
- p.jee服务器 (11)
- windows (2)
- p.iphone (1)
- p.java.分布式与集群 (2)
- p.ibatis (16)
- p.eclipse (5)
- 架构 (2)
- http协议 (5)
- 我的个人标准 (2)
- 多线程 (1)
- 奇怪问题 (5)
- p.jira (13)
- p.httpclient (1)
- 服务器.apache (11)
- 安全防范 (1)
- p.PODAM (1)
- p.junit (16)
- fop (2)
- 硬盘安装 (1)
- powerdesigner (0)
- 单元测试 (1)
- apache commons (4)
- tomcat+apache集群 (10)
- 各类诡辩 (1)
- 安卓 (8)
- qvod (1)
- java编程基础知识考试考点及答案 (0)
- 工作总结 (4)
- oracle (0)
- spring的util工具 (3)
- json (2)
- maven (3)
- jms (19)
- p.bat (3)
- hadoop (2)
- git (3)
- nginx (1)
- p.移动开发 (1)
- shiro (3)
- 游戏破解 (1)
- react-native (7)
- ios开发 (1)
- webmagic (6)
- socks5 (1)
最新评论
-
weituotian:
说的不好,没人看的
公司系统中的菜单功能和权限功能 -
石不易:
非常详细的注解~
绑定端口和IP,Listen 与VirtualHost指令 -
spring_springmvc:
spring mvc demo教程源代码下载,地址:http: ...
spring mvc -
liyixing1:
PandaDONG 写道谢谢你啊,我已经下下来了,只是还有很多 ...
jira war安装 -
liyixing1:
PandaDONG 写道谢谢你啊,我已经下下来了,只是还有很多 ...
jira war安装
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.AccountDao">
</mapper>
包括子元素:
cache - 配置给定命名空间的缓存。
cache-ref – 从其他命名空间引用缓存配置。
resultMap – 最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。
parameterMap – 已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。
sql – 可以重用的SQL块,也可以被其他语句引用。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
select
<select id=”selectPerson” parameterType=”int” resultType=”hashmap”>
SELECT * FROM PERSON WHERE ID = #{id}
</select>
这个语句被定义为selectPerson,使用一个int(或Integer)类型的参数,并返回一个HashMap类型的对象,其中的键是列名,值是列对应的值
#{id}
这就告诉MyBatis使用JDBC创建一个参数,这样的一个参数在SQL中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:
// Similar JDBC code, NOT MyBatis…
String selectPerson = “SELECT * FROM PERSON WHERE ID=?”;
PreparedStatement ps = 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和SQL Server这样的数据库管理系统的自动递增字段)内部生成的主键。默认值:false。
keyProperty
(仅对insert有用)标记一个属性,MyBatis会通过getGeneratedKeys或者通过insert语句的selectKey子元素设置它的值。默认:不设置。
例子:
<insert id="insertAuthor" parameterType="domain.blog.Author">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor" parameterType="domain.blog.Author">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor” parameterType="int">
delete from Author where id = #{id}
</delete>
如果你的数据库支持自动生成主键的字段(比如MySQL和SQL Server),那么你可以设置useGeneratedKeys=”true”,而且设置keyProperty到你已经做好的目标属性上。例如,如果上面的Author表已经对id使用了自动生成的列类型,那么语句可以修改为:
<insert id="insertAuthor" parameterType="domain.blog.Author"
useGeneratedKeys=”true” keyProperty=”id”>
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
MyBatis有另外一种方法来处理数据库不支持自动生成类型,或者可能JDBC驱动不支持自动生成主键时的主键生成问题。
这里有一个简单(甚至很傻)的示例,它可以生成一个随机ID(可能你不会这么做,但是这展示了MyBatis处理问题的灵活性,因为它并不真的关心ID的生成):
<insert id="insertAuthor" parameterType="domain.blog.Author">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
insert into Author
(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代码段,可以包含在其他语句中。比如:
<sql id=”userColumns”> id,username,password </sql>
这个SQL片段可以被包含在其他语句中,例如:
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
select <include refid=”userColumns”/>
from some_table
where id = #{id}
</select>
Parameters
简单的参数传递
<select id=”selectUsers” parameterType=”int” resultType=”User”>
select id, username, password
from users
where id = #{id}
</select>
然而,如果你传递了一个复杂的对象,那么MyBatis的处理方式就会有一点不同。比如:
<insert id=”insertUser” parameterType=”User” >
insert into users (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的作用。
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
或者使用javabean
package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
<select id=”selectUsers” parameterType=”int”
resultType=”com.someapp.model.User”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
因为数据库字段和属性一一对应,所有会自动匹配。如果添加的类型别名定义。那么可以使用别名来设置。
<!-- In Config XML file -->
<typeAlias type=”com.someapp.model.User” alias=”User”/>
<!-- In SQL Mapping XML file -->
<select id=”selectUsers” parameterType=”int”
resultType=”User”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
如果字段名和数据库列名不是一一对应的,可以使用sql语句的as语法,来定义列别名,让它和字段对应
<select id=”selectUsers” parameterType=”int” resultType=”User”>
select
user_id as id,
user_name as userName,
hashed_password as hashedPassword
from some_table
where id = #{id}
</select>
而resultMap则可以更好的解决上面的问题
//实体类
package com.liyixing.ibatis.model;
import java.io.Serializable;
public class Account implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private String userName;
private int age;
public Account() {
super();
}
public Account(int id, String userName, int age) {
super();
this.id = id;
this.userName = userName;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
映射配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liyixing.ibatis.dao.IAccountDao">
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<id property="id" column="ID" />
<result property="userName" column="USER_NAME" />
<result property="age" column="AGE" />
</resultMap>
<select id="getAccount" parameterType="int" resultMap="account">
SELECT
ID, USER_NAME, AGE FROM account
WHERE ID = #{id}
</select>
<!---->
<!-- <select id="getAccount" parameterType="string"-->
<!-- resultType="com.liyixing.ibatis.model.Account">-->
<!-- SELECT ID, USER_NAME, AGE FROM account-->
<!-- WHERE USER_NAME = #{userName}-->
<!-- </select>-->
<insert id="addAccount" parameterType="com.liyixing.ibatis.model.Account">
INSERT INTO account
(USER_NAME, AGE)
VALUES
(#{userName},#{age})
<selectKey resultType="int" keyProperty="id">
select
last_insert_id() as ID from account limit 1
</selectKey>
</insert>
</mapper>
以上映射配置中可以看到一个resultMap元素
而select的配置中,不再使用resultType,而是改为resultMap
表结构
CREATE TABLE `account` (
`ID` int(11) NOT NULL auto_increment,
`USER_NAME` varchar(50) default NULL,
`AGE` int(11) default NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=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
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<id property="id" column="ID" />
<result property="userName" column="USER_NAME" />
<result property="age" column="AGE" />
</resultMap>
constructor构造方法
<constructor>
<idArg column="id" javaType="int"/>
<arg column=”username” javaType=”String”/>
</constructor>
构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。MyBatis也支持私有属性和私有JavaBeans属性来达到这个目的,但是我们可能更青睐构造方法注入。
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ID" javaType="_int" />
<arg column="USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ID" />
<result property="userName" column="USER_NAME" />
<result property="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
CREATE TABLE `address` (
`ID` int(11) NOT NULL auto_increment,
`ADDRESS` varchar(200) default NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
修改account表结构
CREATE TABLE `account` (
`ID` int(11) NOT NULL auto_increment,
`USER_NAME` varchar(50) default NULL,
`AGE` int(11) default NULL,
`ADDRESS_ID` int(11) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
增加了一个ADDRESS_ID字段
添加类Address
package com.liyixing.ibatis.model;
import java.io.Serializable;
public class Address implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private String address;
public Address() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
修改Account实体,添加属性
private Address address;
Account映射中的resultMap
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ACCOUNT_ID" javaType="_int" />
<arg column="ACCOUNT_USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ACCOUNT_ID" />
<result property="userName" column="ACCOUNT_USER_NAME" />
<result property="age" column="ACCOUNT_AGE" />
<association property="address" column="ACCOUNT_ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address">
<id property="id" column="ADDRESS_ID" />
<result property="address" column="ADDRESS" />
</association>
</resultMap>
<association property="address" column="ACCOUNT_ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address">这里的javaType,官方文档说是会自动算出类型,但是我不写javaType发现它获取的Class type是null。抛出了空指针异常。所以我写上了。安全一些。
column="ACCOUNT_ADDRESS_ID"这个属性主要是应用于嵌套查询方式。
select
<select id="getAccount" parameterType="int" resultMap="account">
SELECT
a.ID as ACCOUNT_ID,
a.USER_NAME as ACCOUNT_USER_NAME,
a.AGE as
ACCOUNT_AGE,
a.ADDRESS_ID as ACCOUNT_ADDRESS_ID,
ad.ID as
ADDRESS_ID,
ad.ADDRESS as ADDRESS
FROM account as a
left join address as ad
on ad.ID
= a.ADDRESS_ID
WHERE a.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属性
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ID" javaType="_int" />
<arg column="USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ACCOUNT_ID" />
<result property="userName" column="USER_NAME" />
<result property="age" column="AGE" />
<association property="address" column="ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address" select="getAddress">
</association>
</resultMap>
这里的关联配置中,使用select属性,值是getAddress,batis会调用这个id=getAddress的select,也就是说会执行两个sql语句。
association property="address" column="ADDRESS_ID"的column属性会作为参数传递给参数语句中id为getAddress的参数语句。
<select id="getAddress" parameterType="int"
resultType="com.liyixing.ibatis.model.Address">
select * from address where id = #{id}
</select>
<select id="getAccount" parameterType="int" resultMap="account">
SELECT ID,
USER_NAME,
AGE,
ADDRESS_ID
FROM account
WHERE ID = #{id}
</select>
这种方式会造成sql语句执行过多。
如果我们想在address中,对account进行关联。表结构,模型都不变,添加address的映射文件。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liyixing.ibatis.dao.AddressDao">
<resultMap type="com.liyixing.ibatis.model.Address" id="address">
<id property="id" column="ID" />
<result property="address" column="ADDRESS" />
<association property="account" column="ID"
javaType="com.liyixing.ibatis.model.Account" select="getAccount">
</association>
</resultMap>
<select id="getAddress" parameterType="int" resultMap="address">
select *
from address where id = #{id}
</select>
<select id="getAccount" parameterType="int"
resultType="com.liyixing.ibatis.model.Account">
select * from account where ADDRESS_ID = #{id}
</select>
</mapper>
可以从上面的例子中看出来。<association property="account" column="ID"
javaType="com.liyixing.ibatis.model.Account" select="getAccount">这个元素的column属性会被作为参数传递过去给对应的sql。
collection集合
添加表message,是account用户的发言
CREATE TABLE `message` (
`ID` int(11) NOT NULL auto_increment,
`ACCOUNT_ID` int(11) NOT NULL,
`MESSAGE` varchar(255) default NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ID" javaType="_int" />
<arg column="USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ACCOUNT_ID" />
<result property="userName" column="USER_NAME" />
<result property="age" column="AGE" />
<association property="address" column="ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address" select="getAddress">
</association>
<collection property="messages" javaType="ArrayList"
column="ID" ofType="com.liyixing.ibatis.model.Message"
select="selectMyMessages">
<id property="id" column="ID"/>
<result property="message" column="MESSAGE"/>
</collection>
</resultMap>
<select id="selectMyMessages" parameterType="int"
resultType="com.liyixing.ibatis.model.Message">
select * from message where ACCOUNT_ID = #{accountId}
</select>
以上的配置<collection property="messages" javaType="ArrayList"
column="ID" ofType="com.liyixing.ibatis.model.Message"
select="selectMyMessages">中依然可以看到column会被做为参数传递过去。
一个嵌套结果的方式
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ACOUNT_ID" javaType="_int" />
<arg column="ACOUNT_USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ACCOUNT_ID" />
<result property="userName" column="ACOUNT_USER_NAME" />
<result property="age" column="ACOUNT_AGE" />
<collection property="messages" javaType="ArrayList"
ofType="com.liyixing.ibatis.model.Message">
<id property="id" column="MESSAGE_ID" />
<result property="message" column="MESSAGE" />
</collection>
</resultMap>
这里的column可以省略。
ofType属性:
这个属性用来区分JavaBean(或字段)属性类型,是用来指定集合中的包含(泛型)类型的。
discriminator鉴别器
类似于java的switch可以根据结果制定实际的映射器
有一个Message类
package com.liyixing.ibatis.model;
import java.io.Serializable;
public class Message implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private Account account;
private String message;
private short messageType = (short) -1;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public short getMessageType() {
return messageType;
}
public void setMessageType(short messageType) {
this.messageType = messageType;
}
}
这里的messageType = -1,是因为数据库中我的测试数据,是一条message记录的messageType=0,另一条messageType=1;而java的short自动初始化的时候,值也是0.改成-1就能更清楚的看到结果。
message.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liyixing.ibatis.dao.IMessageDao">
<resultMap type="com.liyixing.ibatis.model.Message" id="message">
<id property="id" column="ID" />
<discriminator javaType="_int" column="MESSAGE_TYPE">
<case value="1" resultMap="messageType"></case>
</discriminator>
</resultMap>
<resultMap type="com.liyixing.ibatis.model.Message" id="messageType">
<result property="messageType" column="MESSAGE_TYPE" />
</resultMap>
</mapper>
这里有<discriminator javaType="_int" column="MESSAGE_TYPE">
<case value="1" resultMap="messageType"></case>
</discriminator>
当值为1才会映射MESSAGE_TYPE
Account.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liyixing.ibatis.dao.IAccountDao">
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<id property="id" column="ID" />
<result property="userName" column="USER_NAME" />
<collection property="messages" javaType="ArrayList"
column="ID" ofType="com.liyixing.ibatis.model.Message" select="getMyMessage">
</collection>
</resultMap>
<select id="getMyMessage" parameterType="_int"
resultMap="message">
SELECT ID,
USER_ID,
MESSAGE,
MESSAGE_TYPE
FROM message
WHERE USER_ID = #{id}
</select>
<select id="getAccount" parameterType="_int" resultMap="account">
SELECT *
FROM account WHERE ID = #{id}
</select>
</mapper>
这里我同时测试了collection和跨文件访问resultMap,发现跨文件访问resultMap是允许的。
调用getAccount的select,发现当message_type字段值为1,才会调用id=messageType的resultMap
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.AccountDao">
</mapper>
包括子元素:
cache - 配置给定命名空间的缓存。
cache-ref – 从其他命名空间引用缓存配置。
resultMap – 最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。
parameterMap – 已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。
sql – 可以重用的SQL块,也可以被其他语句引用。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
select
<select id=”selectPerson” parameterType=”int” resultType=”hashmap”>
SELECT * FROM PERSON WHERE ID = #{id}
</select>
这个语句被定义为selectPerson,使用一个int(或Integer)类型的参数,并返回一个HashMap类型的对象,其中的键是列名,值是列对应的值
#{id}
这就告诉MyBatis使用JDBC创建一个参数,这样的一个参数在SQL中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:
// Similar JDBC code, NOT MyBatis…
String selectPerson = “SELECT * FROM PERSON WHERE ID=?”;
PreparedStatement ps = 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和SQL Server这样的数据库管理系统的自动递增字段)内部生成的主键。默认值:false。
keyProperty
(仅对insert有用)标记一个属性,MyBatis会通过getGeneratedKeys或者通过insert语句的selectKey子元素设置它的值。默认:不设置。
例子:
<insert id="insertAuthor" parameterType="domain.blog.Author">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor" parameterType="domain.blog.Author">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor” parameterType="int">
delete from Author where id = #{id}
</delete>
如果你的数据库支持自动生成主键的字段(比如MySQL和SQL Server),那么你可以设置useGeneratedKeys=”true”,而且设置keyProperty到你已经做好的目标属性上。例如,如果上面的Author表已经对id使用了自动生成的列类型,那么语句可以修改为:
<insert id="insertAuthor" parameterType="domain.blog.Author"
useGeneratedKeys=”true” keyProperty=”id”>
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
MyBatis有另外一种方法来处理数据库不支持自动生成类型,或者可能JDBC驱动不支持自动生成主键时的主键生成问题。
这里有一个简单(甚至很傻)的示例,它可以生成一个随机ID(可能你不会这么做,但是这展示了MyBatis处理问题的灵活性,因为它并不真的关心ID的生成):
<insert id="insertAuthor" parameterType="domain.blog.Author">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
insert into Author
(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代码段,可以包含在其他语句中。比如:
<sql id=”userColumns”> id,username,password </sql>
这个SQL片段可以被包含在其他语句中,例如:
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
select <include refid=”userColumns”/>
from some_table
where id = #{id}
</select>
Parameters
简单的参数传递
<select id=”selectUsers” parameterType=”int” resultType=”User”>
select id, username, password
from users
where id = #{id}
</select>
然而,如果你传递了一个复杂的对象,那么MyBatis的处理方式就会有一点不同。比如:
<insert id=”insertUser” parameterType=”User” >
insert into users (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的作用。
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
或者使用javabean
package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
<select id=”selectUsers” parameterType=”int”
resultType=”com.someapp.model.User”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
因为数据库字段和属性一一对应,所有会自动匹配。如果添加的类型别名定义。那么可以使用别名来设置。
<!-- In Config XML file -->
<typeAlias type=”com.someapp.model.User” alias=”User”/>
<!-- In SQL Mapping XML file -->
<select id=”selectUsers” parameterType=”int”
resultType=”User”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
如果字段名和数据库列名不是一一对应的,可以使用sql语句的as语法,来定义列别名,让它和字段对应
<select id=”selectUsers” parameterType=”int” resultType=”User”>
select
user_id as id,
user_name as userName,
hashed_password as hashedPassword
from some_table
where id = #{id}
</select>
而resultMap则可以更好的解决上面的问题
//实体类
package com.liyixing.ibatis.model;
import java.io.Serializable;
public class Account implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private String userName;
private int age;
public Account() {
super();
}
public Account(int id, String userName, int age) {
super();
this.id = id;
this.userName = userName;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
映射配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liyixing.ibatis.dao.IAccountDao">
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<id property="id" column="ID" />
<result property="userName" column="USER_NAME" />
<result property="age" column="AGE" />
</resultMap>
<select id="getAccount" parameterType="int" resultMap="account">
SELECT
ID, USER_NAME, AGE FROM account
WHERE ID = #{id}
</select>
<!---->
<!-- <select id="getAccount" parameterType="string"-->
<!-- resultType="com.liyixing.ibatis.model.Account">-->
<!-- SELECT ID, USER_NAME, AGE FROM account-->
<!-- WHERE USER_NAME = #{userName}-->
<!-- </select>-->
<insert id="addAccount" parameterType="com.liyixing.ibatis.model.Account">
INSERT INTO account
(USER_NAME, AGE)
VALUES
(#{userName},#{age})
<selectKey resultType="int" keyProperty="id">
select
last_insert_id() as ID from account limit 1
</selectKey>
</insert>
</mapper>
以上映射配置中可以看到一个resultMap元素
而select的配置中,不再使用resultType,而是改为resultMap
表结构
CREATE TABLE `account` (
`ID` int(11) NOT NULL auto_increment,
`USER_NAME` varchar(50) default NULL,
`AGE` int(11) default NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=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
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<id property="id" column="ID" />
<result property="userName" column="USER_NAME" />
<result property="age" column="AGE" />
</resultMap>
constructor构造方法
<constructor>
<idArg column="id" javaType="int"/>
<arg column=”username” javaType=”String”/>
</constructor>
构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。MyBatis也支持私有属性和私有JavaBeans属性来达到这个目的,但是我们可能更青睐构造方法注入。
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ID" javaType="_int" />
<arg column="USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ID" />
<result property="userName" column="USER_NAME" />
<result property="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
CREATE TABLE `address` (
`ID` int(11) NOT NULL auto_increment,
`ADDRESS` varchar(200) default NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
修改account表结构
CREATE TABLE `account` (
`ID` int(11) NOT NULL auto_increment,
`USER_NAME` varchar(50) default NULL,
`AGE` int(11) default NULL,
`ADDRESS_ID` int(11) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
增加了一个ADDRESS_ID字段
添加类Address
package com.liyixing.ibatis.model;
import java.io.Serializable;
public class Address implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private String address;
public Address() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
修改Account实体,添加属性
private Address address;
Account映射中的resultMap
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ACCOUNT_ID" javaType="_int" />
<arg column="ACCOUNT_USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ACCOUNT_ID" />
<result property="userName" column="ACCOUNT_USER_NAME" />
<result property="age" column="ACCOUNT_AGE" />
<association property="address" column="ACCOUNT_ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address">
<id property="id" column="ADDRESS_ID" />
<result property="address" column="ADDRESS" />
</association>
</resultMap>
<association property="address" column="ACCOUNT_ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address">这里的javaType,官方文档说是会自动算出类型,但是我不写javaType发现它获取的Class type是null。抛出了空指针异常。所以我写上了。安全一些。
column="ACCOUNT_ADDRESS_ID"这个属性主要是应用于嵌套查询方式。
select
<select id="getAccount" parameterType="int" resultMap="account">
SELECT
a.ID as ACCOUNT_ID,
a.USER_NAME as ACCOUNT_USER_NAME,
a.AGE as
ACCOUNT_AGE,
a.ADDRESS_ID as ACCOUNT_ADDRESS_ID,
ad.ID as
ADDRESS_ID,
ad.ADDRESS as ADDRESS
FROM account as a
left join address as ad
on ad.ID
= a.ADDRESS_ID
WHERE a.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属性
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ID" javaType="_int" />
<arg column="USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ACCOUNT_ID" />
<result property="userName" column="USER_NAME" />
<result property="age" column="AGE" />
<association property="address" column="ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address" select="getAddress">
</association>
</resultMap>
这里的关联配置中,使用select属性,值是getAddress,batis会调用这个id=getAddress的select,也就是说会执行两个sql语句。
association property="address" column="ADDRESS_ID"的column属性会作为参数传递给参数语句中id为getAddress的参数语句。
<select id="getAddress" parameterType="int"
resultType="com.liyixing.ibatis.model.Address">
select * from address where id = #{id}
</select>
<select id="getAccount" parameterType="int" resultMap="account">
SELECT ID,
USER_NAME,
AGE,
ADDRESS_ID
FROM account
WHERE ID = #{id}
</select>
这种方式会造成sql语句执行过多。
如果我们想在address中,对account进行关联。表结构,模型都不变,添加address的映射文件。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liyixing.ibatis.dao.AddressDao">
<resultMap type="com.liyixing.ibatis.model.Address" id="address">
<id property="id" column="ID" />
<result property="address" column="ADDRESS" />
<association property="account" column="ID"
javaType="com.liyixing.ibatis.model.Account" select="getAccount">
</association>
</resultMap>
<select id="getAddress" parameterType="int" resultMap="address">
select *
from address where id = #{id}
</select>
<select id="getAccount" parameterType="int"
resultType="com.liyixing.ibatis.model.Account">
select * from account where ADDRESS_ID = #{id}
</select>
</mapper>
可以从上面的例子中看出来。<association property="account" column="ID"
javaType="com.liyixing.ibatis.model.Account" select="getAccount">这个元素的column属性会被作为参数传递过去给对应的sql。
collection集合
添加表message,是account用户的发言
CREATE TABLE `message` (
`ID` int(11) NOT NULL auto_increment,
`ACCOUNT_ID` int(11) NOT NULL,
`MESSAGE` varchar(255) default NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ID" javaType="_int" />
<arg column="USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ACCOUNT_ID" />
<result property="userName" column="USER_NAME" />
<result property="age" column="AGE" />
<association property="address" column="ADDRESS_ID"
javaType="com.liyixing.ibatis.model.Address" select="getAddress">
</association>
<collection property="messages" javaType="ArrayList"
column="ID" ofType="com.liyixing.ibatis.model.Message"
select="selectMyMessages">
<id property="id" column="ID"/>
<result property="message" column="MESSAGE"/>
</collection>
</resultMap>
<select id="selectMyMessages" parameterType="int"
resultType="com.liyixing.ibatis.model.Message">
select * from message where ACCOUNT_ID = #{accountId}
</select>
以上的配置<collection property="messages" javaType="ArrayList"
column="ID" ofType="com.liyixing.ibatis.model.Message"
select="selectMyMessages">中依然可以看到column会被做为参数传递过去。
一个嵌套结果的方式
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<constructor>
<idArg column="ACOUNT_ID" javaType="_int" />
<arg column="ACOUNT_USER_NAME" javaType="string" />
</constructor>
<id property="id" column="ACCOUNT_ID" />
<result property="userName" column="ACOUNT_USER_NAME" />
<result property="age" column="ACOUNT_AGE" />
<collection property="messages" javaType="ArrayList"
ofType="com.liyixing.ibatis.model.Message">
<id property="id" column="MESSAGE_ID" />
<result property="message" column="MESSAGE" />
</collection>
</resultMap>
这里的column可以省略。
ofType属性:
这个属性用来区分JavaBean(或字段)属性类型,是用来指定集合中的包含(泛型)类型的。
discriminator鉴别器
类似于java的switch可以根据结果制定实际的映射器
有一个Message类
package com.liyixing.ibatis.model;
import java.io.Serializable;
public class Message implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private Account account;
private String message;
private short messageType = (short) -1;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public short getMessageType() {
return messageType;
}
public void setMessageType(short messageType) {
this.messageType = messageType;
}
}
这里的messageType = -1,是因为数据库中我的测试数据,是一条message记录的messageType=0,另一条messageType=1;而java的short自动初始化的时候,值也是0.改成-1就能更清楚的看到结果。
message.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liyixing.ibatis.dao.IMessageDao">
<resultMap type="com.liyixing.ibatis.model.Message" id="message">
<id property="id" column="ID" />
<discriminator javaType="_int" column="MESSAGE_TYPE">
<case value="1" resultMap="messageType"></case>
</discriminator>
</resultMap>
<resultMap type="com.liyixing.ibatis.model.Message" id="messageType">
<result property="messageType" column="MESSAGE_TYPE" />
</resultMap>
</mapper>
这里有<discriminator javaType="_int" column="MESSAGE_TYPE">
<case value="1" resultMap="messageType"></case>
</discriminator>
当值为1才会映射MESSAGE_TYPE
Account.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liyixing.ibatis.dao.IAccountDao">
<resultMap type="com.liyixing.ibatis.model.Account" id="account">
<id property="id" column="ID" />
<result property="userName" column="USER_NAME" />
<collection property="messages" javaType="ArrayList"
column="ID" ofType="com.liyixing.ibatis.model.Message" select="getMyMessage">
</collection>
</resultMap>
<select id="getMyMessage" parameterType="_int"
resultMap="message">
SELECT ID,
USER_ID,
MESSAGE,
MESSAGE_TYPE
FROM message
WHERE USER_ID = #{id}
</select>
<select id="getAccount" parameterType="_int" resultMap="account">
SELECT *
FROM account WHERE ID = #{id}
</select>
</mapper>
这里我同时测试了collection和跨文件访问resultMap,发现跨文件访问resultMap是允许的。
调用getAccount的select,发现当message_type字段值为1,才会调用id=messageType的resultMap
发表评论
-
深入了解MyBatis参数
2017-05-04 21:12 394深入了解MyBatis参数 http://blog.csdn ... -
MyBatis Generator 详解
2015-08-03 14:00 767http://blog.csdn.net/isea533/ar ... -
ibatis的动态sql
2014-10-23 13:33 942位于包 com.ibatis.sqlmap.engine.ma ... -
枚举 enum
2013-12-13 17:28 2597当使用枚举时,需要使用EnumTypeHandler或者Enu ... -
mybatis generator tools配置文件解析
2012-12-20 23:28 25416这是mybatis3 generator 配 ... -
问题解决方案
2011-08-22 00:25 24261.Mapped Statements collection ... -
mybatis的参数
2011-06-16 12:36 6436在类DynamicSqlSource 方法 public Bo ... -
与spring结合
2011-05-20 21:58 1244实体省略 maping文件省略 dao接口省略 mybatis ... -
动态sql
2011-05-05 17:54 1268ibatis支持动态的组合sql。 包括动态元素 if ... -
ibatis缓存
2011-05-05 16:38 4515ibatis的session缓存。做了一个测试 <?xm ... -
ibatis官方推荐目录结构
2011-05-05 13:24 1065src/com.liyixing.application.da ... -
配置文件
2011-04-30 20:17 1809mybatis的配置文件结构 顶级是configuration ... -
session的getMapper方法解析
2011-04-30 17:22 9647跟踪: DefaultSqlSession类 public & ... -
一个简单例子,以及基于接口,class对象调用
2011-04-30 16:59 1331应用结构: IbatisConfiguration.xm ... -
范围和声明周期(对象声明周期)
2011-04-29 23:19 1353先看mybatis用户手册中的一段代码 DataSource ...
相关推荐
在MyBatis中,SQL映射文件起着至关重要的作用,它是连接数据库和Java代码的桥梁,允许开发者灵活地控制SQL语句的编写。本文将深入探讨MyBatis框架中的SQL映射文件配置,主要包括以下几个方面: 1. **基本结构** ...
SQL映射文件是MyBatis框架的核心组件之一,主要用于存放数据库操作的SQL语句。它不仅简化了开发过程中的SQL编写工作,还提供了灵活的数据访问层实现方式。通过将SQL语句与Java接口方法进行映射,可以有效地分离业务...
Ibatis 是一款轻量级的Java持久层框架,它提供了SQL映射文件和基于XML或注解的SQL语句配置,使得开发者可以更加灵活地控制SQL的编写,从而避免了传统的JDBC代码中的大量模板式代码。这个"ibatis SQL映射文件、DAO、...
SqlMap.xml文件则是具体的SQL映射文件,它是iBATIS的核心,定义了SQL语句、结果映射、参数映射等。映射文件中的每个元素都代表了一个数据库操作,如查询、插入、更新或删除。例如,元素用于定义一个查询,它可以包含...
总结来说,MyBatis通过SQL映射文件或注解实现了数据库的CRUD操作,它的优势在于将SQL语句与业务逻辑分离,提高了代码的可维护性和灵活性。在实际开发中,结合Spring框架的MyBatis-Spring模块,可以进一步简化事务...
Mybatis核心组成部分之SQL映射文件揭秘详解 Mybatis是一个基于Java的持久层框架,它的核心组成部分之一是SQL映射文件。SQL映射文件是Mybatis的真正力量所在,通过它可以实现数据库操作的自动化。下面我们将详细介绍...
首先,MyBatis的核心是SQL映射文件,这些文件是XML格式的,定义了SQL语句及其相关的参数映射和结果映射。在`mybatis-3_master.zip`中可能包含了MyBatis的源码,这有助于理解其内部工作原理。通过XML配置,我们可以...
这个框架允许我们通过XML或注解方式定义SQL映射文件,以便于实现数据访问操作。标题和描述中提到的“ibatis映射文件信息,接口对应”是指Ibatis如何通过映射文件与Java接口进行关联,实现数据操作的封装和调用。 ...
标题 "根据mybatis/ibatis sqlmapper文件解析生成数据库表" 暗示了我们将会探讨一个关于MyBatis或iBatis框架的工具,它能够解析SQL映射文件并根据这些文件自动生成数据库表。这个过程对于快速构建数据库模型,尤其是...
- **SQL映射文件**:这是MyBatis的核心配置文件之一,它定义了SQL语句与Java方法之间的映射关系。通过XML文件或注解的方式,开发者可以明确指定如何将Java对象的属性映射到数据库表的列上,以及如何执行各种数据库...
4. 编写映射文件UserMapper.xml和UserMapper接口,声明需要的方法。 5. 配置mybatis-config.xml。 6. 编写工具类,如MyBatisUtil,用于创建SqlSessionFactory和SqlSession。 7. 编写测试类,使用SqlSession和Mapper...
通常情况下,当我们修改了iBatis的SQL映射文件(sqlmap)后,需要重启应用服务器来使改动生效。这无疑降低了开发效率。然而,通过手动控制加载sqlmap文件,我们可以实现在不重启应用的情况下更新SQL映射,从而提高...
其次,`mybatis-3.0.2.jar`是MyBatis的核心库,包含了MyBatis框架的主要功能,如SQL映射文件解析、SQL执行等。这个版本的MyBatis支持动态SQL,使得SQL编写更加灵活。 `mybatis-generator-core-1.3.0.jar`是MyBatis ...
它支持 XML 配置和 SQL 映射文件配置,提供了灵活的持久层框架。 XML 配置 Mybatis 的 XML 配置文件用于定义数据库操作。配置文件中可以定义多个 SQL 语句标签,每个标签对应一个数据库操作。标签的 id 必须与接口...
4. **Mappers**:配置Mybatis的映射文件路径,每个Mapper对应一个SQL映射文件,用于定义SQL语句和结果映射。 **二、附配置文件(Mapper XML文件)** Mapper XML文件是Mybatis的SQL映射文件,它包含了SQL语句和结果...
mybatis动态sql:SQL 映射 XML 文件是所有 sql 语句放置的地方。需要定义一个 workspace,一般定义为对应的接口类的路径。写好 SQL 语句映射文件后需要在 MyBAtis 配置文件 mappers 标签中引用。
XDoclet是早期的一个工具,用于自动生成Hibernate的映射文件(.hbm.xml)和SQL语句,这样开发者无需手动编写这些文件,提高了开发效率。这篇博客文章“Hibernate使用xdoclet生成映射文件和sql语句”可能详细介绍了...
本文将深入探讨使用C#语言创建一个能够为Oracle和SQL Server数据库自动生成NHibernate映射文件的程序。 NHibernate是一个流行的.NET ORM框架,它允许开发人员将.NET对象模型与数据库中的表进行映射,从而简化了...