Mybatis的关联映射笔记

Mybatis的概述和入门配置

Mybatis的配置优化和CRUD操作

Mybatis动态SQL语句

Mybatis的关联映射

Mybatis注解式开发

Mybatis缓存

1 1-1关联映射查询实现

需求:查询出某个用户的身份证信息。用户信息和身份证信息是 一 对 一的关系。

实现步骤:

1、必须在实体类中先建立1-1的关系。

​ 定义一个身份证类

public class UserCard {
    private int id;
    private double height;
    private double weight;
    private int married;
    
  	//getter setter toString省略
}

再定义用户类关联身份证类

public class User {
    private int id;
    private String userName;
    private Date birthday;
    private char sex;
    private String address;
    // 一个用户对象 一个身份证对象: 1-1的关系。
    private UserCard userCard;
    
 	//getter setter toString省略
}

2、实现1-1的关联映射查询实现。

获取会话对象,获取用户的数据访问层接口代理对象,创建方法查询用户信息。

public class MybatisDemo {
    @Test
    public void query1_1(){
        // 1、获取与数据库的会话
        SqlSession sqlSession = MybatisSqlSessionFactoryUtils.getSqlSession();
        // 2、获取用户的数据访问层接口的代理对象,会自动找映射文件:UserMapper.xml文件
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 3、查询用户对象信息(目的是可以查询出1-1关联的身份证信息 )
        List<User> users = userMapper.findAll();
        System.out.println(users);
        // 4、关闭会话
        MybatisSqlSessionFactoryUtils.close(sqlSession);
    }
}

因为创建了UserCard的对象类,所以,我们不管需不需要用到,都应该再dao包下创建它的映射文件。

public interface UserCardMapper {
}
public interface UserMapper {
    List<User> findAll();
}
<!--UserCardMapper.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">
<!-- namespace: 必须申明成被服务接口的路径 -->
<mapper namespace="com.itheima.dao.UserCardMapper">
<!--不需要用到,但是必须写上来-->
</mapper>

下面是配置UserMapper.xml,首先先配置好两个实体的结果集,然后在再将两段结果集进行关联,官方规定了1-1关联的字段映射必须使用一个标签:association。最后再配置SQL语句,结果集返回类型是两个实体类关联的结果集。

<mapper namespace="com.itheima.dao.UserMapper">
    <resultMap id="userCardResultMap" type="UserCard">
        <id property="id" column="id"/>
        <result property="height" column="height"/>
        <result property="weight" column="weight"/>
        <result property="married" column="married"/>
    </resultMap>

    <resultMap id="userResultMap" type="User">
        <id property="id" column="id"/>
        <result property="userName" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
    </resultMap>

    <!-- extends:先继承用户基础的结果集映射用户对象本身的信息,里面再关联映射关联字段的信息 -->
    <resultMap id="user1_1ResultMap" type="User" extends="userResultMap">
        <!-- 开始配置1-1关联映射的身份证字段对象信息:userCard
             官方规定了1-1关联的字段映射必须使用一个标签:association
                property:申明关联的1-1字段
                resultMap:关联字段userCard自己的结果集映射
        -->
        <association property="userCard" resultMap="userCardResultMap"/>
    </resultMap>

    <!--  List<User> findAll(); -->
    <select id="findAll" resultMap="user1_1ResultMap">
        SELECT * FROM USER u LEFT JOIN user_card uc ON u.id = uc.id
    </select>

</mapper>

2 1-N

需求: 查询出用户对象的时候,可以查询出它的全部订单信息。用户 与 订单是 1-N的关系!

实现步骤:

1、必须在实体类中先建立1-N的关系。

​ 定义一个订单类:

public class OrderForm {
    private int oid;
    private int userId;
    private String number;
    private Date createTime;
    private String note;
    
	//getter setter toString省略

}

定义一个用户类:

public class User {
    private int id;
    private String userName;
    private Date birthday;
    private char sex;
    private String address;
    // 一个用户对象 一个身份证对象: 1-1的关系。
    private UserCard userCard;
    // 一个用户对象 一批订单对象: 1-N的关系
    private List<OrderForm> orderForms;
 
 	//getter setter toString省略
}
public interface UserMapper {
    List<User> findAll();
}

下面是同样是配置UserMapper.xml,首先先配置好两个实体的结果集,然后在再将两段结果集进行关联,官方规定了1-N关联的字段映射必须使用一个标签:collection。最后再配置SQL语句,结果集返回类型是两个实体类关联的结果集。

<?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: 必须申明成被服务接口的路径 -->
<mapper namespace="com.itheima.dao.UserMapper">

    <resultMap id="userResultMap" type="User">
        <id property="id" column="id"/>
        <result property="userName" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
    </resultMap>

    <resultMap id="orderFormResultMap" type="OrderForm">
        <id property="oid" column="oid"/>
        <result property="userId" column="user_id"/>
        <result property="number" column="number"/>
        <result property="createTime" column="create_time"/>
        <result property="note" column="note"/>
    </resultMap>

    <!-- extends:先继承用户基础的结果集映射用户对象本身的信息,里面再关联映射关联字段的信息 -->
    <resultMap id="user1_NResultMap" type="User" extends="userResultMap">
        <!-- 一个用户包含一批订单,官方规定了1-N的字段必须使用如下标签映射: collection -->
        <!--
         property: 多方的属性名
         javaType:多方的属性类型
         ofType: 集合中每个元素的类型
         resultMap:多方映射
         -->
        <collection property="orderForms" javaType="list" ofType="OrderForm"
                    resultMap="orderFormResultMap"/>
    </resultMap>

    <!-- List<User> findAll(); -->
    <select id="findAll" resultMap="user1_NResultMap">
        <!-- 连表查询 -->
        SELECT * FROM USER u LEFT JOIN order_form of ON u.id = of.user_id
    </select>

</mapper>

3 N-N

需求: 查询出全部用户信息的同时可以查询出用户的全部角色信息。用户与角色是:N-N关系!

实现步骤:

1、必须在实体类中先建立N-N的关系。

​ 同样我们需要建立一个角色类:

public class Role {
    private int roleId;
    private String roleName;
    private String roleDetail;
  
  	//getter setter toString省略
}

然后去用户类去关联:(其他代码参照1-N用户类)

// 一个用户对象 一批角色对象: N-N的关系
private List<Role> roles;

2、实现N-N的关联映射查询实现:实现上与1-N一模一样。单独来看都是1-N的关系。

这里的配置和1-N一样,直接上代码。

public class MybatisDemo {
    @Test
    public void queryN_N(){
        // 1、获取与数据库的会话
        SqlSession sqlSession = MybatisSqlSessionFactoryUtils.getSqlSession();
        // 2、获取用户的数据访问层接口的代理对象,会自动找映射文件:UserMapper.xml文件
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 3、查询用户对象信息(目的是可以查询出1-N关联的订单信息 )
        List<User> users = userMapper.findAll();
        System.out.println(users);
        // 4、关闭会话
        MybatisSqlSessionFactoryUtils.close(sqlSession);
    }
}
public interface UserMapper {
    List<User> findAll();
}
<?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: 必须申明成被服务接口的路径 -->
<mapper namespace="com.itheima.dao.UserMapper">

    <resultMap id="userResultMap" type="User">
        <id property="id" column="id"/>
        <result property="userName" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
    </resultMap>

    <resultMap id="roleFormResultMap" type="Role">
        <id property="roleId" column="role_id"/>
        <result property="roleName" column="role_name"/>
        <result property="roleDetail" column="role_Detail"/>
    </resultMap>

    <!-- extends:先继承用户基础的结果集映射用户对象本身的信息,里面再关联映射关联字段的信息 -->
    <resultMap id="userN_NResultMap" type="User" extends="userResultMap">
        <!-- 一个用户包含一批订单,官方规定了N_N与1-N的字段必须使用如下标签映射: collection -->
        <!--
         property: 多方的属性名
         javaType:多方的属性类型
         ofType: 集合中每个元素的类型
         resultMap:多方映射
         -->
        <collection property="roles" javaType="list" ofType="Role"
                    resultMap="roleFormResultMap"/>
    </resultMap>

    <!-- List<User> findAll(); -->
    <select id="findAll" resultMap="userN_NResultMap">
        <!-- 连表查询 -->
        SELECT * FROM USER u LEFT JOIN user_role ur ON u.id = ur.`user_id`
        LEFT JOIN role r ON ur.`role_id` = r.`role_id`
    </select>

</mapper>

4 延迟加载的配置优化

我们会发现,在之前代码中,在配置结果集的时候我们要根据每一个类去配置它的结果集,这种做法带来的坏处就是代码量过多,如果一个数据很多列,那么我们需要一个个的写,这是不可能的。那么我们就给了一种新的配置优化的做法。我们在前面会根据每个类去创建它的映射文件,比如User类就在dao包下创建UserMapper.java和UserMapper.xml,UserCard类就在dao包下创建UserCardMapper.java和UserCardMapper.xml。

那么我们就可以把之前的这段结果集代码给删除。

<resultMap id="userCardResultMap" type="UserCard">
    <id property="id" column="id"/>
    <result property="height" column="height"/>
    <result property="weight" column="weight"/>
    <result property="married" column="married"/>
</resultMap>

<resultMap id="userResultMap" type="User">
    <id property="id" column="id"/>
    <result property="userName" column="username"/>
    <result property="birthday" column="birthday"/>
    <result property="sex" column="sex"/>
    <result property="address" column="address"/>
</resultMap>

然后在UserCardMapper.java文件下创建一个方法

public interface UserCardMapper {
    UserCard getUserCardById(int userId);
}

再去UserCardMapper.xml文件配置好映射文件。记住namespace: 必须申明成被服务接口的路径。

<?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: 必须申明成被服务接口的路径 -->
<mapper namespace="com.itheima.dao.UserCardMapper">
    <!-- UserCard getUserCardById(int userId); -->
    <select id="getUserCardById" resultType="UserCard">
        select * from user_card where id = #{xxzxz}
    </select>
</mapper>

然后再回到UserMapper.xml文件中进行配置,声明关联的字段、根据当前用户的哪个字段值去查询关联对象、 关联字段的类型、然后用select去提取UserCardMapper.java的相对路径,表示去这个关联对象中去查询信息。

<mapper namespace="com.itheima.dao.UserMapper">

    <resultMap id="user1_1ResultMap" type="User" >
        <id property="id" column="id"/>
        <!-- 开始配置1-1关联映射的身份证字段对象信息:userCard
             官方规定了1-1关联的字段映射必须使用一个标签:association
                property:申明关联的1-1字段
                javaType : 关联字段的类型
                column:根据当前用户的哪个字段值去查询关联对象!
                select:去那当前行的column列值去查询关联的这个字段的对象信息!

                拓展:
                 fetchType="eager" 立即加载
                 fetchType="lazy" 延迟加载
        -->
        <association property="userCard" column="id" javaType="UserCard"
                     select="com.itheima.dao.UserCardMapper.getUserCardById"/>
    </resultMap>

    <!--  List<User> findAll(); -->
    <select id="findAll" resultMap="user1_1ResultMap">
        select * from user
    </select>

</mapper>

通过这样配置,我们会发现代码量少了很多。

5 1-1延迟加载

延迟加载:需要的时候才去查询,不需要的时候不要查询!!提高数据操作的性能!

Mybatis默认是没有开启延迟加载的,本案例是可以支持延迟加载的,需要开启延迟加载才可以。

延迟加载的具体含义:不需要的时候不会加载关联的字段信息查询,需要的时候才会触发查询关联字段信息。

在mybatis-config.xml核心配置文件中配置。

<!--配置mybatis中全局设置-->
<settings>
    <!--开启延迟加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

同样的做法:

需求:查询出某个用户的身份证信息。用户信息和身份证信息是 一 对 一的关系。

实现步骤:
1、必须在实体类中先建立1-1的关系。

​ 忽略。可以翻看上面1-1的代码。

2、实现1-1的关联映射查询实现。

UserMapper.java

public interface UserMapper {
    List<User> findAll();
}

UserMapper.xml

UserMapper.xml文件中进行配置,声明关联的字段、根据当前用户的哪个字段值去查询关联对象、 关联字段的类型、然后用select去提取UserCardMapper.java的相对路径,表示去这个关联对象中去查询信息。

SQL语句直接查询整个user,然后再去UserCardMapper.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">
<!-- namespace: 必须申明成被服务接口的路径 -->
<mapper namespace="com.itheima.dao.UserMapper">

    <resultMap id="user1_1ResultMap" type="User" >
        <id property="id" column="id"/>
        <!-- 开始配置1-1关联映射的身份证字段对象信息:userCard
             官方规定了1-1关联的字段映射必须使用一个标签:association
                property:申明关联的1-1字段
                javaType : 关联字段的类型
                column:根据当前用户的哪个字段值去查询关联对象!
                select:去那当前行的column列值去查询关联的这个字段的对象信息!

                拓展:
                 fetchType="eager" 立即加载
                 fetchType="lazy" 延迟加载
        -->
        <association property="userCard" column="id" javaType="UserCard"
                     select="com.itheima.dao.UserCardMapper.getUserCardById"/>
    </resultMap>

    <!--  List<User> findAll(); -->
    <select id="findAll" resultMap="user1_1ResultMap">
        select * from user
    </select>

</mapper>

UserCardMapper.java

定义方法传入userId(其实就是主键)

public interface UserCardMapper {
    UserCard getUserCardById(int userId);
}

UserCardMapper.xml

namespace: 必须申明成被服务接口的路径

把userId传进来做主键

<?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: 必须申明成被服务接口的路径 -->
<mapper namespace="com.itheima.dao.UserCardMapper">
    <!-- UserCard getUserCardById(int userId); -->
    <select id="getUserCardById" resultType="UserCard">
        select * from user_card where id = #{xxzxz}
    </select>
</mapper>

最后我们来看运行结果:

public class MybatisDemo {
    @Test
    public void query1_1(){
        // 1、获取与数据库的会话
        SqlSession sqlSession = MybatisSqlSessionFactoryUtils.getSqlSession();
        // 2、获取用户的数据访问层接口的代理对象,会自动找映射文件:UserMapper.xml文件
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 3、查询用户对象信息(目的是可以查询出1-1关联的身份证信息 )
        List<User> users = userMapper.findAll();
        for(User u : users){
            System.out.println(u.getUserName());
        }
        System.out.println("------------------------------------");
        for (User u : users){
            System.out.println("身份证:" + u.getUserCard());
        }
        // 4、关闭会话
        MybatisSqlSessionFactoryUtils.close(sqlSession);
    }
}

在这里插入图片描述

这是没有开启延迟加载的,会直接把数据加载出来。

在这里插入图片描述

这是开启延迟加载的,会等到需要取数据的时候再去加载。

6 1-N的延迟加载

其实1-N和N-N是一样的,然后代码的配置也是跟1-1差不多的,所以直接上代码。

需求: 查询出用户对象的时候,可以查询出它的全部订单信息。用户 与 订单是 1-N的关系!

实现步骤:

​ 1、必须在实体类中先建立1-N的关系。

略。

​ 2、实现1-N的关联映射查询实现。

public interface UserMapper {
    List<User> findAll();
}

注意这个UserMapper.xml中的 fetchType=“lazy” : 延迟记载, fetchType=“eager” : 立即加载是就近原则,这里设置了,核心配置设置文件也设置了,优先选择这里,因为比较近。

collection是1-N和N-N的。

<?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: 必须申明成被服务接口的路径 -->
<mapper namespace="com.itheima.dao.UserMapper">



    <resultMap id="user1_NResultMap" type="User">
        <id column="id" property="id"></id>
        <!-- 一个用户包含一批订单,官方规定了1-N的字段必须使用如下标签映射: collection -->
        <!--
         property: 多方的属性名
         javaType:多方的属性类型
         ofType: 集合中每个元素的类型
         column: 根据当前用户的哪个字段的值去查询关联的订单信息对象
         select : 根据用户id查询它的订单信息的方法,
         fetchType="lazy" : 延迟记载
         fetchType="eager" : 立即加载
         -->
        <collection property="orderForms" javaType="list" ofType="OrderForm" fetchType="lazy"
               column="id" select="com.itheima.dao.OrderFormMapper.getOrdersByUserId"     />
    </resultMap>

    <!-- List<User> findAll(); -->
    <select id="findAll" resultMap="user1_NResultMap">
        select * from user
    </select>

</mapper>
public interface OrderFormMapper {
    List<OrderForm> getOrdersByUserId(int userId);
}
<?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: 必须申明成被服务接口的路径 -->
<mapper namespace="com.itheima.dao.OrderFormMapper">
    <!--     List<OrderForm> getOrdersByUserId(int userId);
        -->
    <select id="getOrdersByUserId" resultType="OrderForm">
        select * , user_id userId , create_time createTime from order_form where user_id = #{xDsd}
    </select>
</mapper>
public class MybatisDemo {
    @Test
    public void query1_N(){
        // 1、获取与数据库的会话
        SqlSession sqlSession = MybatisSqlSessionFactoryUtils.getSqlSession();
        // 2、获取用户的数据访问层接口的代理对象,会自动找映射文件:UserMapper.xml文件
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 3、查询用户对象信息(目的是可以查询出1-N关联的订单信息 )
        List<User> users = userMapper.findAll();
        for (User user : users) {
            System.out.println(user.getUserName());
        }
        System.out.println("------------------------------------------------");
        for(User u : users){
            System.out.println(u.getOrderForms());
        }
        // 4、关闭会话
        MybatisSqlSessionFactoryUtils.close(sqlSession);
    }
}

没有延迟加载

在这里插入图片描述

延迟加载
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值