mapper mapping document is the core of Mybatis, the operation of the database are in the inside.
In mapper mapping document to <mapper/>
the root node, which can under some child nodes are:
1 |
select, insert, update, delete, cache, cache-ref, resultMap, parameterMap, sql
|
This section will introduce these children.
Let's look insert
insert, update, delete similar attributes and methods of the three labels, described here as an example to insert.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?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" >
<!-- namespace 的值对应一个DAO -->
<mapper namespace="com.wzt.batis.dao.UserMapper">
<!-- 1. id 对应DAO中的一个方法 -->
<insert id="insert"
<!-- 2. parameterType 将要传入语句的参数的完全限定类名或别名
这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数 -->
parameterType="user"
<!-- 3. parameterMap 可以通过额外的标签来对入参进行更复杂的操作 -->
parameterMap="uuu"
<!-- 4. useGeneratedKeys 这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键
5. keyProperty 将获得的主键赋值给指定的Java类中的属性,如此处的id
6. keyColumn 从数据库表的id列取主键值,数据库设定了主键则不需要显式配置 -->
useGeneratedKeys="true" keyProperty="id" keyColumn="id"
<!-- 7. flushCache 任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认为true-->
flushCache="true"
<!-- 8. statementType STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。-->
statementType="PREPARED"
<!-- 9. timeout 这个设置是在抛出异常之前,驱动进程等待数据库返回请求结果的秒数。-->
timeout="20"/>
<parameterMap id="uuu" type="user"/>
</mapper>
|
Pinpointing the code:
Database Table
1 2 3 4 5 6 7 |
CREATE TABLE IF NOT EXISTS `tb_user` (
`id` INT COLLATE utf8_bin NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` VARCHAR (36) COLLATE utf8_bin NOT NULL COMMENT '姓名',
`age` INT NOT NULL COMMENT '年龄',
`gender` CHAR (10) COLLATE utf8_bin NOT NULL COMMENT '性别',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
|
DO Deliverable
Omit getter / setter methods:
1 2 3 4 5 6 |
public class UserDo {
private Integer id;
private String name;
private Integer age;
private String gender;
}
|
Mapper Interface
1 2 3 4 |
@Mapper
public interface UserMapper {
Integer insert(UserDo user);
}
|
Mapper mapping document
1 2 3 4 5 6 7 8 9 |
<?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.wzt.batis.dao.UserMapper">
<insert id="insert" parameterType="user">
INSERT INTO tb_user (id,name,age,gender)VALUES (
#{id},#{name},#{age},#{gender}
)
</insert>
</mapper>
|
Test category
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class TestMain {
public static void main(String[] args) {
SqlSession sqlSession = getSessionFactory().openSession(true);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserDo user = new UserDo(1,"LiLei",12,"male");
Integer res = userMapper.insert(user);
}
/**
* Mybatis 通过SqlSessionFactory获取SqlSession, 然后才能通过SqlSession与数据库进行交互
*/
private static SqlSessionFactory getSessionFactory() {
SqlSessionFactory sessionFactory = null;
String resource = "mybatis-config.xml";
try {
sessionFactory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsReader(resource));
} catch (IOException e) {
e.printStackTrace();
}
return sessionFactory;
}
}
|
After performing tb_user table in the database more than one data.
userMapper.insert(user)
The successful execution returns 1 (failure or 0).
If the insert is not specified id, using the increment primary key database, and want to get the id value recorded, it can be modified:
1 2 3 4 5 |
<insert id="insert" parameterType="user" useGeneratedKeys="true" keyProperty="id">
INSERT INTO tb_user (name,age,gender)VALUES (
#{name},#{age},#{gender}
)
</insert>
|
Or use the <selectKey/>
label:
1 2 3 4 5 6 7 8 |
<insert id="insert1" parameterType="UseR">
<selectKey keyProperty="id" resultType="int" order="AFTER" >
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO tb_user (name,age,gender)VALUES (
#{name},#{age},#{gender}
)
</insert>
|
Thus, in the userMapper.insert(user)
can from the user
get id of the object.
Note: increment id database is assigned to the keyProperty
specified property, insert
the return value of the method is still 1 or 0 .
这里用到了 <selectKey/>
标签,它可以返回记录在数据库中的id,看上去和<insert/>
标签的属性useGeneratedKeys
和keyProperty
功能重复了。 那么除了这个作用外,<selectKey/>
还有什么作用呢?
我们知道,MySQL支持主键自增,但是其它的数据库(如oracle)不支持啊;此外如果主键是UUID的,自增也无能为力了。此时<selectKey/>
就能派上用场了。
先将DO类的id改成String类型,然后mapper映射文档变成这样:
1 2 3 4 5 6 7 8 9 10 |
<insert id="insert" parameterType="user">
<!-- order变成了BEFORE,代表在insert前执行 -->
<selectKey keyProperty="id" resultType="string" order="BEFORE" >
SELECT UUID()
</selectKey>
<!-- 这里也加上了id列 -->
INSERT INTO tb_user (id, name, age, gender)VALUES (
#{id}, #{name}, #{age}, #{gender}
)
</insert>
|
这样就会在insert语句前先执行selectKey,将UUID赋给id,然后再插入数据库。
不过在网上看到这里有个隐患,就是通过mybatis生成的UUID可能存在重复,emmm,所以实际工程中还是用java的UUID,更加方便,还不重复!
重头戏 select
先来看看mapper映射文档中,select 标签可以有哪些属性:
1 2 3 4 5 6 7 8 |
<!-- 大多属性和insert相似,下面列几个多出来的 -->
<select id="select"
<!-- 下面两个二选一,用来指定返回的类型 -->
resultType="user" resultMap="uuu"
<!-- 尝试影响驱动进程每次批量返回的结果行数和这个设置值相等 -->
fetchSize="10"
<!-- 设置本条语句的结果是否被二级缓存,默认为true -->
us 大专栏 Mybatis映射文档介绍eCache="true" />
|
要更全的可以查看相应的官方文档。
现在来看看select的demo。以上面的tb_user表为例,查询某个id的user记录的select为:
1 2 3 |
<select id="findUserById" parameterType="string" resultType="user">
SELECT * FROM tb_user WHERE `id` = #{userId}
</select>
|
DAO层接口为:
1 2 3 4 |
@Mapper
public interface UserMapper {
UserDo findUserById(String userId);
}
|
可以看到select语句中的#{userId}
来自接口方法的入参,返回类型resultType
为user(这是个别名)。
这里有个注意点: 入参只有一个时,可以直接这么取;若是有多个,则需要加注解 @Param()
了,比如要根据性别和年龄来查:
1 2 3 4 5 |
@Mapper
public interface UserMapper {
UserDo findUserByGenderAndAge(@Param("gender") String gender,
@Param("age") String age);
}
|
1 2 3 4 |
<select id="findUserByGenderAndAge" parameterType="string" resultType="user">
SELECT * FROM tb_user
WHERE `gender` = #{gender} AND `age` = #{age}
</select>
|
在上面介绍select的属性时提到,返回类型可以用两个属性来指定,resultType
和 resultMap
,上面的demo用到了resultType
,下面讲讲resultMap
的用法。
什么都能转 resultMap
resultMap 最简单的用法就是字段的映射。 若数据库中字段和用来接收的Javabean的属性一致时,用resultType即可,但若是不一致,resultMap就派上用场了。 比如说数据库中的字段是uuid,Javabean中是id,此时需要这样配置:
1 2 3 |
<resultMap id="userMap" type="user">
<result property="id" column="uuid"/>
</resultMap>
|
这样就完成了一个简单地字段映射。不过resultMap的强大之处远不止此。
在上面的demo中,返回接收的user的属性都是简单的基本类型的包装类型和String,但如果是个自定义的类,resultMap也可以处理得很好:
现在我们给User类中增加一个Role属性
1 2 3 4 |
public class UserDo {
// ...
private RoleDo role;
}
|
在数据库中增加两张表,分别是角色表tb_role,和用户角色关联表tb_user_role_relation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-- 角色表
CREATE TABLE
IF NOT EXISTS tb_role (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` VARCHAR (20) NOT NULL COMMENT '角色名',
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8 COLLATE = utf8_bin;
-- 用户角色关系表
CREATE TABLE
IF NOT EXISTS tb_user_role_relation (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '编号',
`user_id` VARCHAR (20) NOT NULL COMMENT '用户id',
`role_id` VARCHAR (20) NOT NULL COMMENT '角色id',
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8 COLLATE = utf8_bin;
|
在mapper映射文档中,可以用 <association/>
进行关联:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<select id="select" resultMap="userMap" >
SELECT u.*, r.`id` AS role_id, r.`name` AS role_name FROM tb_user u
LEFT JOIN tb_user_role_relation urr ON u.id = urr.user_id
LEFT JOIN tb_role r ON urr.role_id = r.id
</select>
<resultMap id="userMap" type="user">
<id property="id" column="id"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
<result property="name" column="name"/>
<association property="role" javaType="role">
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
</association>
</resultMap>
|
便可将role和user关联起来:
1 2 3 4 5 6 7 8 9 10 |
{
"id": "49",
"name": "ZhangSan",
"age": 25,
"gender": "male",
"role": {
"id": 2,
"name": "manager"
}
}
|
在上面这个例子中,一个user只有一个role,但实际上一个user可能对应着多个role,在Javabean中的表现就是:
1 2 3 4 |
public class UserDo {
// ...
private List<RoleDo> roles;
}
|
此时可以用 <collection/>
进行关联:
1 2 3 4 5 6 7 8 9 10 |
<resultMap id="userMap" type="user">
<id property="id" column="id"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
<result property="name" column="name"/>
<collection property="roles" ofType="role">
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
</collection>
</resultMap>
|
可以得到结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{
"id": "49",
"name": "ZhangSan",
"age": 25,
"gender": "male",
"roles": [
{
"id": 1,
"name": "admin"
},
{
"id": 2,
"name": "manager"
}
]
}
|
到此,mapper映射文档介绍告一段落。