MyBatis映射关系详解
海绵hong 人气:0数据库的配置
CREATE TABLE person ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(32) NOT NULL DEFAULT '', card_id INT , FOREIGN KEY (card_id) REFERENCES idencard(id) )CHARSET utf8;
-- 创建 mybatis_idencard 表 CREATE TABLE idencard ( id INT PRIMARY KEY AUTO_INCREMENT, card_sn VARCHAR(32) NOT NULL DEFAULT '' )CHARSET utf8 ; INSERT INTO idencard VALUES(1,'111111111111110'); INSERT INTO person VALUES(1,'张三',1); SELECT * FROM person; SELECT * FROM idencard
一.映射关系一对一
1.映射关系 1 对 1-基本介绍
● 基本介绍
1. 项目中 1 对 1 的关系是一个基本的映射关系,比如 :Person( 人 ) --- IDCard( SFZ )
2. 我们看看再 MyBatis 中如何实现 1 对 1 的处理 .
● 注意细节
1 对 1 , 我们这里就研究一下单向 1 对 1 即可
2.映射关系 1 对 1-映射方式
映射方式
1. 通过配置 XxxMapper.xml 实现 1 对 1 [ 配置方式 ]
2. 通过注解的方式实现 1 对 1 [ 注解方式 ]
3.应用实例
3.1方式一
通过配置 XxxMapper.xml 的方式来实现下面的 1 对 1 的映射关系,实现 级
联查询 , 通过 person 可以获取到对应的 idencard 信息
然后建立各自的javabean--->两个表
然后我们就可以开始重头戏了开始建立IdenCardMapper.java和IdenCardMapper.xml
public interface IdenCardMapper { //根据id获取到SFZ序列号 public IdenCard getIdenCardById(Integer id);
<!-- 1、配置/实现//根据id获取到SFZ序列号 2、public IdenCard getIdenCardById(Integer id); --> <select id="getIdenCardById" parameterType="Integer" resultType="IdenCard"> SELECT * FROM `idencard` WHERE `id` = #{id} </select>
//通过Person的id获取到Person,包括这个Person关联的IdenCard对象[级联查询] public Person getPersonById(Integer id);
<mapper namespace="com.hong.mapper.PersonMapper"> <!-- 1、配置/实现public Person getPersonById(Integer id); 2、完成通过Person的id获取到Person,包括这个Person关联的IdenCard对象[级联查询] 3. 为了让小伙伴们理解的更加深刻一点,先用大家容易想到的方式-分析问题-解决问题 4. 看到如果配置成简单 resultType="Person" 问题就是没有实现级联查询 5. 自定义resultMap 搞定 映射返回的结果 6. 因为 getPersonById 最终返回的是 Person对象[只是有级联的对象属性], type仍然配置"Person" --> <resultMap id="PersonResultMap" type="Person"> <!--<result property="id" column="id"/>--> <!--id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能 1.property="id" 表示person 属性 id ,通常是主键 2.column="id" 表示对应表的字段 --> <id property="id" column="id"/> <result property="name" column="name"/> <!--association – 一个复杂类型的关联 1. property="card" 表示 Person对象的 card 属性 2. javaType="IdenCard" 表示card 属性 的类型 3. column="id" 是从我们的 下面这个语句查询后返回的字段 SELECT * FROM `person`,`idencard` WHERE `person`.id=1 AND `person`.card_id = `idencard`.id --> <association property="card" javaType="IdenCard"> <result property="id" column="id"/> <result property="card_sn" column="card_sn"/> </association> </resultMap> <select id="getPersonById" parameterType="Integer" resultMap="PersonResultMap"> SELECT * FROM `person`,`idencard` WHERE `person`.id = #{id} AND `person`.card_id = `idencard`.id </select> </mapper>
方式二: 通过配置 XxxMapper.xml 的方式来实现下面的 1 对 1 的映射关系,实现级 联查询 , 通过 person 可以获取到对应的 identcard 信息
1. 修改 PersonMapper.java 和 PersonMapper.xml 使用第 2 种映射方式 , 完成 1 对 1 映射 关系
//通过Person的id获取到Person,包括这个Person关联的IdenCard对象,方式2 public Person getPersonById2(Integer id); //编写方法,通过card_id 查询得到person对象/数据 public Person getPersonByCardId(Integer cardId);
<!-- 1、通过Person的id获取到Person,包括这个Person关联的IdenCard对象,方式2 2、public Person getPersonById2(Integer id); 3. 这里的方式和前面不同. 1) 先通过 SELECT * FROM `person` WHERE `id` = #{id} 返回 person信息 2) 再通过 返回的card_id 值,再执行操作,得到IdenCard 数据 --> <resultMap id="PersonResultMap2" type="Person"> <id property="id" column="id"/> <result property="name" column="name"/> <association property="card" column="card_id" select="com.hong.mapper.IdenCardMapper.getIdenCardById" /> </resultMap> <select id="getPersonById2" parameterType="Integer" resultMap="PersonResultMap2"> SELECT * FROM `person` WHERE `id` = #{id} </select> </mapper>
1. mybatis第二种方式核心思想: 将这个多表联查,分解成单表操作 , 这样简洁,而且易于维护 ,推荐
2. 而且可以复用你已经写好的方法 -组合
3. property="card": 表示 Person对象的 card 属性
4. column="card_id" 这个是
SELECT * FROM `person` WHERE `id` = #{id} 返回的 字段 card_id 信息/数据
5. 返回的 字段 card_id 信息/数据 作为getIdenCardById入参, 来执行
重点解析:
先执行下面的select语句,然后将执行的结果中的card_id传参给getIdenCardById,这个时候我们就直接返回的就是确定这个值的IdenCard的值了。
好,现在我们试着来说明一下啥叫将多表级联变成现在的单表操作。
就是我们先来思考一下MySQL中的多表查询,是不是有一个子查询,你要是知道这个就差不多理解了一半了。我们数据库中的子查询是先将一个查询结果返回给另外一个SQL语句进行操作。那么一对一映射其实本质也是一样,我们先将一个结果作为参数然后传入到一个方法中,这个方法就可以运用这个结果去执行他的操作。
注解的方式实现 通过注解的方式来实现下面的 1 对 1 的映射关系,实现级联查询 , 通过 person 可以获取到 对应的 identcard 信息 在实际开发中还是 推荐使用配置方式
public interface PersonMapperAnnotation { //这里注解实现方法 //说明: 注解的形式就是对前面xml配置方式的体现 //这里同学们可以结合前面讲解的xml配置时,加入的注释来理解 @Select("SELECT * FROM `person` WHERE `id` = #{id}") @Results({ @Result(id = true, property = "id", column = "id"), @Result(property = "name", column = "name"), @Result(property = "card", column = "card_id", one = @One(select = "com.hong.mapper.IdenCardMapper.getIdenCardById")) }) public Person getPersonById(Integer id); }
注解的方式也就是xml形式的另外一种体现
public class PersonMapperAnnotationTest { //属性 private SqlSession sqlSession; private PersonMapperAnnotation personMapperAnnotation; //初始化 @Before public void init() { //获取到sqlSession sqlSession = MyBatisUtils.getSqlSession(); personMapperAnnotation = sqlSession.getMapper(PersonMapperAnnotation.class); } @Test public void getPersonById() { Person person = personMapperAnnotation.getPersonById(1); System.out.println("person----" + person); if(sqlSession != null) { sqlSession.close(); } } }
注意事项和细节
1. 表是否设置外键 , 对 MyBatis 进行对象 / 级联映射没有影响
2. 举例 : 去掉 person 表的外键 , 进行测试 , 依然可以获取相应的级联对象
二.映射关系多对一
1.基本介绍
1. 项目中多对 1 的关系是一个基本的映射关系 , 多对 1, 也可以理解成是 1 对多 .
2. User --- Pet : 一个用户可以养多只宠物
3. Dep ---Emp : 一个部门可以有多个员工
2.注意细节
1. 我们直接讲 双向的多对一的关系 ,单向的多对一比双向的多对一简单。
2. 在实际的项目开发中 , 要求会使用双向的多对一的映射关系
3. 说明:什么是 双向的多对一 的关系 : 比如通过 User 可以查询到对应的 Pet, 反过 来,通过 Pet 也可以级联查询到对应的 User 信息 .
4. 多对多的关系,是在多对 1 的基础上扩展即可
3.映射方式
1. 方式 1 :通过配置 XxxMapper.xml 实现多对 1 2.
方式 2 :通过注解的方式实现 多对 1
4.代码实现
4.1数据库表
CREATE TABLE mybatis_user (id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(32) NOT NULL DEFAULT '' )CHARSET=utf8 ; CREATE TABLE mybatis_pet (id INT PRIMARY KEY AUTO_INCREMENT, nickname VARCHAR(32) NOT NULL DEFAULT '', user_id INT , FOREIGN KEY (user_id) REFERENCES mybatis_user(id) )CHARSET=utf8 ; INSERT INTO mybatis_user VALUES(NULL,'宋江'),(NULL,'张飞'); INSERT INTO mybatis_pet VALUES(1,'黑背',1),(2,'小哈',1); INSERT INTO mybatis_pet VALUES(3,'波斯猫',2),(4,'贵妃猫',2); SELECT * FROM mybatis_user; SELECT * FROM mybatis_pet;
4.2UserMapper.xml文件
<mapper namespace="com.hong.mapper.UserMapper"> <!--解读 1、一定要想一想我们前面1-1是如何实现 2、配置/实现 public User getUserById(Integer id); 3、思路(1) 先通过user-id 查询得到user信息 (2) 再根据user-id查询对应的pet信息 并映射到User-List<Pet> pets --> <resultMap id="UserResultMap" type="User"> <id property="id" column="id"/> <result property="name" column="name"/> <!--解读:因为pets属性是集合,因此这里需要是collection标签来处理 1. ofType="Pet" 指定返回的集合中存放的数据类型Pet 2. collection 表示 pets 是一个集合 3. property="pets" 是返回的user对象的属性 pets 4. column="id" SELECT * FROM `mybatis_user` WHERE `id` = #{id} 返回的id字段对应的值 --> <collection property="pets" column="id" ofType="Pet" select="com.hong.mapper.PetMapper.getPetByUserId"/> </resultMap> <select id="getUserById" parameterType="Integer" resultMap="UserResultMap"> SELECT * FROM `mybatis_user` WHERE `id` = #{id} </select> </mapper>
4.3PetMapper.xml文件
<mapper namespace="com.hong.mapper.PetMapper"> <!-- 1、通过User的id来获取pet对象,可能有多个,因此使用List接收 2、public List<Pet> getPetByUserId(Integer userId); 3. 完成的思路和前面大体相同. --> <resultMap id="PetResultMap" type="Pet"> <id property="id" column="id"/> <result property="nickname" column="nickname"/> <association property="user" column="user_id" select="com.hong.mapper.UserMapper.getUserById" /> </resultMap> <select id="getPetByUserId" parameterType="Integer" resultMap="PetResultMap"> SELECT * FROM `mybatis_pet` WHERE `user_id` = #{userId} </select> <!--说明 1. 注意体会resultMap带来好处, 直接复用 2. 实现/配置public Pet getPetById(Integer id); 3. 通过pet的id获取Pet对象 --> <select id="getPetById" parameterType="Integer" resultMap="PetResultMap"> SELECT * FROM `mybatis_pet` WHERE `id` = #{id} </select> </mapper>
注解实现多对 1 映射
需求说明 : 通过注解的方式来实现下面的多对 1 的映射关系,实现级联查询 , 完成前面完成 的任务,通过 User-->Pet 也可 Pet->User , 在实际开发中 推荐使用配置方式来 做
public interface UserMapperAnnotation { //通过id获取User对象 /** * 1. 注解的配置就是对应的Mapper.xml文件配置的,改写 * 2. * 1、一定要想一想我们前面1-1是如何实现 * 2、配置/实现 public User getUserById(Integer id); * 3、思路(1) 先通过user-id 查询得到user信息 (2) 再根据user-id查询对应的pet信息 * 并映射到User-List<Pet> pets * <resultMap id="UserResultMap" type="User"> * <id property="id" column="id"/> * <result property="name" column="name"/> * 1. ofType="Pet" 指定返回的集合中存放的数据类型Pet * 2. collection 表示 pets 是一个集合 * 3. property="pets" 是返回的user对象的属性 pets * 4. column="id" SELECT * FROM `mybatis_user` WHERE `id` = #{id} 返回的id字段对应的值 * --> * <collection property="pets" column="id" ofType="Pet" * select="com.hong.mapper.PetMapper.getPetByUserId"/> * </resultMap> * <select id="getUserById" parameterType="Integer" resultMap="UserResultMap"> * SELECT * FROM `mybatis_user` WHERE `id` = #{id} * </select> */ @Select("SELECT * FROM `mybatis_user` WHERE `id` = #{id}") @Results({ @Result(id = true, property = "id", column = "id"), @Result(property = "name", column = "name"), //这里请小伙伴注意,pets属性对应的是集合 @Result(property = "pets", column = "id", many = @Many(select = "com.hong.mapper.PetMapperAnnotation.getPetByUserId")) }) public User getUserById(Integer id); }
public interface PersonMapperAnnotation { //这里注解实现方法 //说明: 注解的形式就是对前面xml配置方式的体现 //这里同学们可以结合前面老师讲解的xml配置时,加入的注释来理解 @Select("SELECT * FROM `person` WHERE `id` = #{id}") @Results({ @Result(id = true, property = "id", column = "id"), @Result(property = "name", column = "name"), @Result(property = "card", column = "card_id", one = @One(select = "com.hong.mapper.IdenCardMapper.getIdenCardById")) }) public Person getPersonById(Integer id); }
public interface PetMapperAnnotation { //通过User的id来获取pet对象,可能有多个,因此使用List接收 /** * 1、通过User的id来获取pet对象,可能有多个,因此使用List接收 * 2、public List<Pet> getPetByUserId(Integer userId); * 3. 完成的思路和前面大体相同. * <resultMap id="PetResultMap" type="Pet"> * <id property="id" column="id"/> * <result property="nickname" column="nickname"/> * <association property="user" column="user_id" * select="com.hong.mapper.UserMapper.getUserById" /> * </resultMap> * <select id="getPetByUserId" parameterType="Integer" resultMap="PetResultMap"> * SELECT * FROM `mybatis_pet` WHERE `user_id` = #{userId} * </select> */ //id = "PetResultMap" 就是给我们的Results[Result Map] 指定一个名字 //,目的是为了后面复用 @Select("SELECT * FROM `mybatis_pet` WHERE `user_id` = #{userId}") @Results(id = "PetResultMap", value = { @Result(id = true, property = "id", column = "id"), @Result(property = "nickname", column = "nickname"), @Result(property = "user", column = "user_id", one = @One(select = "com.hong.mapper.UserMapperAnnotation.getUserById")) }) public List<Pet> getPetByUserId(Integer userId); //通过pet的id获取Pet对象, 同时会查询到pet对象关联的user对象 /** * <select id="getPetById" * parameterType="Integer" * resultMap="PetResultMap"> * SELECT * FROM `mybatis_pet` WHERE `id` = #{id} * </select> * * @ResultMap("PetResultMap") 使用/引用我们上面定义的 Results[ResultMap] */ @Select("SELECT * FROM `mybatis_pet` WHERE `id` = #{id}") @ResultMap("PetResultMap") public Pet getPetById(Integer id); }
一对多的思路:
1.首先我们通过id="getUserById"的select查询获取到user-id对应的所有数据
2.之后也可以通过user-id获取到pet是的信息
3.之后我们也可以通过User的id来获取pet对象,可能有多个,因此使用List接收
简而言之:
就是我们可以通过主人的id查询到宠物的信息,同时也可以通过宠物的信息查询到主人。
一对一是我先查询一个id,在通过这个id查询到一个信息,而这个信息是可以查询到另外一个表的信息的。而一对多是我通过一个字段查询到这个字段在这个信息里面的所相关的内容(就像一个id可以查询到主人对应的宠物信息),当然是存放在集合之中的。
加载全部内容