首页 > 代码库 > Hello Mybatis 03 数据关联

Hello Mybatis 03 数据关联

ResultMap

在实际的开发中,数据库不总是我们希望看到的样子。比如我们希望User的主键是id但是数据库偏偏喜欢叫它u_id,这样一来原先的resultType似乎就失效了,不带这么玩的,整个人都不好了。

于是mybatis给出了他的方案——resultMap。把我们从复杂的命名问题中解救出来~~~

在上一篇中已经用mybatis generator生成好了一个BlogMapper.xml。现在让我们分析下这个文件。

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 3 <mapper namespace="pro.app.inter.BlogMapper" >
 4   <resultMap id="BaseResultMap" type="pro.app.model.Blog" >
 5     <id column="b_id" property="bId" jdbcType="INTEGER" />
 6     <result column="b_title" property="bTitle" jdbcType="VARCHAR" />
 7     <result column="b_content" property="bContent" jdbcType="VARCHAR" />
 8     <result column="user_id" property="userId" jdbcType="INTEGER" />
 9   </resultMap>
10   
11   <sql id="Base_Column_List" >
12     b_id, b_title, b_content, user_id
13   </sql>
14   <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
15     select 
16     <include refid="Base_Column_List" />
17     from blog
18     where b_id = #{bId,jdbcType=INTEGER}
19   </select>
20   <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
21     delete from blog
22     where b_id = #{bId,jdbcType=INTEGER}
23   </delete>
24   <insert id="insert" parameterType="pro.app.model.Blog" >
25     <selectKey resultType="java.lang.Integer" keyProperty="bId" order="AFTER" >
26       SELECT LAST_INSERT_ID()
27     </selectKey>
28     insert into blog (b_title, b_content, user_id
29       )
30     values (#{bTitle,jdbcType=VARCHAR}, #{bContent,jdbcType=VARCHAR}, #{userId,jdbcType=INTEGER}
31       )
32   </insert>
33   <insert id="insertSelective" parameterType="pro.app.model.Blog" >
34     <selectKey resultType="java.lang.Integer" keyProperty="bId" order="AFTER" >
35       SELECT LAST_INSERT_ID()
36     </selectKey>
37     insert into blog
38     <trim prefix="(" suffix=")" suffixOverrides="," >
39       <if test="bTitle != null" >
40         b_title,
41       </if>
42       <if test="bContent != null" >
43         b_content,
44       </if>
45       <if test="userId != null" >
46         user_id,
47       </if>
48     </trim>
49     <trim prefix="values (" suffix=")" suffixOverrides="," >
50       <if test="bTitle != null" >
51         #{bTitle,jdbcType=VARCHAR},
52       </if>
53       <if test="bContent != null" >
54         #{bContent,jdbcType=VARCHAR},
55       </if>
56       <if test="userId != null" >
57         #{userId,jdbcType=INTEGER},
58       </if>
59     </trim>
60   </insert>
61   <update id="updateByPrimaryKeySelective" parameterType="pro.app.model.Blog" >
62     update blog
63     <set >
64       <if test="bTitle != null" >
65         b_title = #{bTitle,jdbcType=VARCHAR},
66       </if>
67       <if test="bContent != null" >
68         b_content = #{bContent,jdbcType=VARCHAR},
69       </if>
70       <if test="userId != null" >
71         user_id = #{userId,jdbcType=INTEGER},
72       </if>
73     </set>
74     where b_id = #{bId,jdbcType=INTEGER}
75   </update>
76   <update id="updateByPrimaryKey" parameterType="pro.app.model.Blog" >
77     update blog
78     set b_title = #{bTitle,jdbcType=VARCHAR},
79       b_content = #{bContent,jdbcType=VARCHAR},
80       user_id = #{userId,jdbcType=INTEGER}
81     where b_id = #{bId,jdbcType=INTEGER}
82   </update>
83 </mapper>

在文件的开头位置,就能够发现一个名为BaseResultMapresultMap标签。在这个标签当中我们可以发现几个子标签。这几个子标签对通过columnproperty属性将数据库字段和model对应类型关联起来。而<id/>标签代表这个model类的属性对应的数据库字段为这张表的主键。定义完成这个BaseResultMap之后,我们就可以在后面的标签对中使用它作为返回的结果使用。 这里可以注意到select的属性resultMap="BaseResultMap" 。返回的数据通过resultMap被封装成了相应的对象,如果返回的数据是多条,mybatis也会自动将结果集转换为List集合。

这里还可以关注下resultMap下的sql标签对,在这个标签对中可以写入数据库的字段名称。在CRUDxml文件中使用<include/>标签引用这它,在数据库需要修改的时候,我们就不用去修改这个配置文件下每一个sql语句。

数据关联

有人会说。这样resultMapresultType有什么区别!还要多写这么一堆配置,这不是吃饱了撑着么!!!真的是这个样子?

我们之前设计了两张表,一个用户表和一个博客列表,一个用户可以有多篇博客吧,一篇博客只有一个作者。现在就让resultMap帮助我们把数据关联起来~

先给表Blog添加几条数据

1 INSERT INTO `blog`.`blog` (`b_id`, `b_title`, `b_content`, `user_id`) VALUES (1, 001, mybatis001, 1);
2 INSERT INTO `blog`.`blog` (`b_id`, `b_title`, `b_content`, `user_id`) VALUES (2, 002, mybatis002, 1);
3 INSERT INTO `blog`.`blog` (`b_id`, `b_title`, `b_content`, `user_id`) VALUES (3, 003, mybatis003, 1);
4 INSERT INTO `blog`.`blog` (`b_id`, `b_title`, `b_content`, `user_id`) VALUES (4, 004, mybatis004, 1);
5 INSERT INTO `blog`.`blog` (`b_id`, `b_title`, `b_content`, `user_id`) VALUES (5, 005, mybatis005, 1);

 

在此之前我们需要再定义一个BlogVo类,并继承Blog类,然后添加一个User类型属性user。

 1 package pro.app.model;
 2 
 3 public class BlogVo extends Blog{
 4     private User user;
 5     public User getUser() {
 6         return user;
 7     }
 8     public void setUser(User user) {
 9         this.user = user;
10     }
11 }

接着在BlogMapper.xml中添加一个resultMap。

 1 <resultMap id="BaseResultMapWithUser" type="pro.app.model.BlogVo" >
 2     <id column="b_id" property="bId" jdbcType="INTEGER" />
 3     <result column="b_title" property="bTitle" jdbcType="VARCHAR" />
 4     <result column="b_content" property="bContent" jdbcType="VARCHAR" />
 5     <association property="user"  javaType="pro.app.model.User">
 6         <id column="user_id" property="id" jdbcType="INTEGER" />
 7         <result column="name" property="name" jdbcType="VARCHAR" />
 8         <result column="age" property="age" jdbcType="INTEGER" />
 9     </association>
10   </resultMap>

在resultMap中通过子标签association,我们将外键与对应的model类型对应起来。用association中的property属性对应java属性的用户。association下的子标签id对应blog表中的外键,这也是数据关联的关键!接着再给这个文件添加一个select标签。

1  <select id="selectByPrimaryKeyWithUser" resultMap="BaseResultMapWithUser" parameterType="java.lang.Integer" >
2     select * 
3     from blog b
4     join user u
5     on b.user_id=u.id
6     where b.b_id= #{id,jdbcType=INTEGER}
7  </select>

ok,让我们在BlogMapper.java里添加一个selectByPrimaryKeyWithUser()方法。

 1 package pro.app.inter;
 2 
 3 import org.apache.ibatis.annotations.Param;
 4 
 5 import pro.app.model.Blog;
 6 import pro.app.model.BlogVo;
 7 
 8 public interface BlogMapper {
 9     int deleteByPrimaryKey(Integer bId);
10 
11     int insert(Blog record);
12 
13     int insertSelective(Blog record);
14 
15     Blog selectByPrimaryKey(Integer bId);
16 
17     int updateByPrimaryKeySelective(Blog record);
18 
19     int updateByPrimaryKey(Blog record);
20     
21     BlogVo selectByPrimaryKeyWithUser(@Param("id")Integer id);
22     
23 }

建立一个测试类来看看效果

 1 package pro.test;
 2 
 3 import java.io.Reader;
 4 
 5 import org.apache.ibatis.io.Resources;
 6 import org.apache.ibatis.session.SqlSession;
 7 import org.apache.ibatis.session.SqlSessionFactory;
 8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 9 
10 import pro.app.inter.BlogMapper;
11 import pro.app.model.Blog;
12 import pro.app.model.BlogVo;
13 
14 public class BlogVoTest {
15     private static SqlSessionFactory sqlSessionFactory;
16     private static Reader reader; 
17     static{
18         try{
19             reader= Resources.getResourceAsReader("Configuration.xml");
20             sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
21         }catch(Exception e){
22             e.printStackTrace();
23         }
24     }
25     public static SqlSessionFactory getSession(){
26         return sqlSessionFactory;
27     }
28     public static void main(String[] args) {
29         SqlSession session = sqlSessionFactory.openSession();
30         try {
31             BlogMapper blogs = session.getMapper(BlogMapper.class);
32             BlogVo bv=blogs.selectByPrimaryKeyWithUser(1);
33             System.out.println(bv.getUser().getName());
34         } finally {
35             session.close();
36         }
37     }
38 }

控制台输出了:

Mybatis

ok!mybatis帮我们把博客的作者选出来了。现在我们来通过作者选出他所有的文章。

同样我们在UserMapper.xml里添加一个resultMap

 1   <resultMap id="BaseResultMapWithBlogs" type="pro.app.model.UserVo" >
 2         <id column="id" property="id" jdbcType="INTEGER" />
 3         <result column="name" property="name" jdbcType="VARCHAR" />
 4         <result column="age" property="age" jdbcType="INTEGER" />
 5         <collection property="blogs" ofType="pro.app.model.Blog" column="b_id">
 6             <id column="b_id" property="bId" jdbcType="INTEGER" />
 7             <result column="b_title" property="bTitle" jdbcType="VARCHAR" />
 8             <result column="b_content" property="bContent" jdbcType="VARCHAR" />
 9         </collection>
10     </resultMap>

这里的resultMap还多个了一个collection标签,顾名思义这表示一个集合,collection的column表示结果集对应的table的主键。现在再添加一个select标签。

1     <select id="selectOneWithBlogs" resultMap="BaseResultMapWithBlogs" parameterType="java.lang.Integer">
2         select * 
3         from blog b
4         join user u
5         on b.user_id=u.id
6         where u.id = #{id,jdbcType=INTEGER}
7     </select>

在UserDAO.java里添加一个selectOneWithBlogs()方法。

 1 package pro.app.inter;
 2 import org.apache.ibatis.annotations.Param;
 3 
 4 import pro.app.model.User;
 5 import pro.app.model.UserVo;
 6 
 7 public interface UserDAO {
 8     public User selectOne(@Param("id")Integer id);
 9     
10     public void insertOne(User user);
11     
12     public void deleteOne(@Param("id")Integer id);
13     
14     public void updateOne(User user);
15     
16     UserVo selectOneWithBlogs(@Param("id")Integer id);
17 }

新建一个测试类,观察结果。

 1 package pro.test;
 2 
 3 import java.io.Reader;
 4 
 5 import org.apache.ibatis.io.Resources;
 6 import org.apache.ibatis.session.SqlSession;
 7 import org.apache.ibatis.session.SqlSessionFactory;
 8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 9 
10 import pro.app.inter.UserDAO;
11 import pro.app.model.Blog;
12 import pro.app.model.UserVo;
13 
14 public class UserVoTest {
15     private static SqlSessionFactory sqlSessionFactory;
16     private static Reader reader; 
17     static{
18         try{
19             reader= Resources.getResourceAsReader("Configuration.xml");
20             sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
21         }catch(Exception e){
22             e.printStackTrace();
23         }
24     }
25     public static SqlSessionFactory getSession(){
26         return sqlSessionFactory;
27     }
28     public static void main(String[] args) {
29         SqlSession session = sqlSessionFactory.openSession();
30         try {
31             UserDAO users = session.getMapper(UserDAO.class);
32             UserVo user=users.selectOneWithBlogs(1);
33             for(Blog b:user.getBlogs()){
34                 System.out.println(b.getbTitle());
35                 System.out.println(b.getbContent());
36             }
37         } finally {
38             session.close();
39         }
40     }
41 }

控制台输出

001
mybatis001
002
mybatis002
003
mybatis003
004
mybatis004
005
mybatis005

bingo!!!用户对应的博客都被选出来了~

总结

 通过resultMap 实现数据的关联。