MyBatis学习二

七. 映射关系

7.1 一对一

  1. 通过配置XxxMapper.xml实现一对一

实体类

public class Person {
    private Integer id;
    private String name;
    private IdenCard card;
}
public class IdenCard {
    private Integer id;
    private String card_sn;
}

接口方法

public interface IdenCardMapper {

    //根据id获取身份证
    public IdenCard getIdenCardById(Integer id);

}
public interface PersonMapper {

    //通过person的id获取到person关联的idencard对象
    public Person getPersonById(Integer id);
    
}

mapper.xml文件

<mapper namespace="com.zzti.mybatis.mapper.IdenCardMapper">
    <select id="getIdenCardById" parameterType="Integer" resultType="IdenCard">
        select * from idencard where id =#{id}
    </select>

</mapper>
<mapper namespace="com.zzti.mybatis.mapper.PersonMapper">

    <resultMap id="personResultMap" type="Person">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--一个复杂类型的关联-->
        <association property="card" javaType="com.zzti.mybatis.entity.IdenCard">
            <!--将关联的card对象那些属性放入到这个resultMap-->
            <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>

测试一下

@Test
public void getPersonById(){
    Person personById = personMapper.getPersonById(1);
    System.out.println("getPersonById结果= " + personById);
    if (sqlSession != null) {
        sqlSession.close();
    }
}
===============================================
==>  Preparing: select * from person,idencard where person.id =? and person.card_id = idencard.id
==> Parameters: 1(Integer)
<==    Columns: id, name, card_id, id, card_sn
<==        Row: 1, 张三, 1, 1, 1111111111111
<==      Total: 1
getPersonById结果= Person{id=1, name='张三', card=IdenCard{id=1, card_sn='1111111111111'}}

通过mapper.xml方式2

<!--方式2-->
<resultMap id="personResultMap2" type="person">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <!--当前这个person的card属性,这个数据从getIdenCardById获取;-->
    <!--   card_id: 是从select * from person where id =#{id}查询结果给它的-->
    <!--相当于, 把多表联查分解成单表操作-->
    <association property="card" column="card_id"
                 select="com.zzti.mybatis.mapper.IdenCardMapper.getIdenCardById"/>

</resultMap>

<select id="getPersonById2" parameterType="Integer" resultMap="personResultMap2">
    select * from person where id =#{id}
</select>
@Test
public void getPersonById2(){
    Person personById = personMapper.getPersonById2(1);
    System.out.println("getPersonById2结果= " + personById);
    if (sqlSession != null) {
        sqlSession.close();
    }
}
=================================================
==>  Preparing: select * from person where id =?
==> Parameters: 1(Integer)
<==    Columns: id, name, card_id
<==        Row: 1, 张三, 1
====>  Preparing: select * from idencard where id =?
====> Parameters: 1(Integer)
<====    Columns: id, card_sn
<====        Row: 1, 1111111111111
<====      Total: 1
<==      Total: 1
getPersonById2结果= Person{id=1, name='张三', card=IdenCard{id=1, card_sn='1111111111111'}}
  1. 通过注解的方式实现

相关接口

public interface IdenCardMapperAnnotation {
    //根据id获取身份证
    @Select("select * from idencard where id =#{id}")
    public IdenCard getIdenCardById(Integer id);

}
public interface PersonMapperAnnotation {
    //通过person的id获取到person关联的idencard对象
    @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.zzti.mybatis.mapper.IdenCardMapperAnnotation.getIdenCardById"))
    })
    public Person getPersonById(Integer id);
}

测试一把

 @Test
public void getPersonById3(){
    PersonMapperAnnotation personMapperAnnotation =
            sqlSession.getMapper(PersonMapperAnnotation.class);
    Person personById = personMapperAnnotation.getPersonById(1);
    System.out.println("getPersonById3= " + personById);
    if (sqlSession != null) {
        sqlSession.close();
    }
}
===============================================
==>  Preparing: select * from person where id =?
==> Parameters: 1(Integer)
<==    Columns: id, name, card_id
<==        Row: 1, 张三, 1
====>  Preparing: select * from idencard where id =?
====> Parameters: 1(Integer)
<====    Columns: id, card_sn
<====        Row: 1, 1111111111111
<====      Total: 1
<==      Total: 1
getPersonById3= Person{id=1, name='张三', card=IdenCard{id=1, card_sn='1111111111111'}}

注意细节:
1. 表是否设置外键,对MyBatis进行对象/级联映射没有影响

7.2 多对一

User — Pet: 一个用户可以养多只宠物
Dep — Emp: 一个部门有多个员工
学习双向的多对一的关系,比如通过user可以查询到对应的pet,反过来通过pet也可以级联查询到对应的user信息。

  1. 通过mapper.xml方式
    实体类
public class Pet {
    private Integer id;
    private String nickname;
    private Userr userr;
}
public class Userr {
    private Integer id;
    private String name;
    private List<Pet> pets;
}

接口方法

public interface PetMapper {
    //通过Userr的id来获取pet对象
    public List<Pet> getPetByUserrId(Integer userrId);

    //通过pet的id获取pet对象
    public Pet getPetById(Integer id);

}
public interface UserrMapper {
    //通过id获取Userr对象
    public Userr getUserrById(Integer id);
}

mapper.xml文件
PetMapper

<mapper namespace="com.zzti.mybatis.mapper.PetMapper">
    
    <resultMap id="PetResultMap" type="Pet">
        <id property="id" column="id"/>
        <result property="nickname" column="nickname"/>

        <association property="userr" column="userr_id"
                     select="com.zzti.mybatis.mapper.UserrMapper.getUserrById"/>

    </resultMap>

    <!--userr_id =#{xx} xx就是调用 getPetByUserrId()传入的用户id,可以随意指定-->
    <select id="getPetByUserrId" parameterType="Integer" resultMap="PetResultMap">
        select * from pet where userr_id =#{userrId}
    </select>


    <select id="getPetById" parameterType="Integer" resultMap="PetResultMap">
        select * from pet where id =#{id}
    </select>

</mapper>

UserrMapper

<mapper namespace="com.zzti.mybatis.mapper.UserrMapper">

    <resultMap id="UserrResultMap" type="Userr">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--collection:一对多关联查询,表示一个用户可能对应多个pet对象,-->
        <!--ofType: 集合中元素对象的类型 -->
        <!--id: 当前Userr表的主键,通过这个id去查询对应的pet有哪些-->
        <collection property="pets" ofType="Pet" column="id"
                    select="com.zzti.mybatis.mapper.PetMapper.getPetByUserrId"/>
    </resultMap>

    <select id="getUserrById" parameterType="Integer" resultMap="UserrResultMap">
        select * from userr where id =#{id}
    </select>
</mapper>
  1. 通过注解方式

PetMapper接口

@Select("select * from pet where userr_id =#{userrId}")
@Results({
        @Result(id = true,property = "id",column = "id"),
        @Result(property = "nickname",column = "nickname"),
})
public List<Pet> getPetByUserrId2(Integer userrId);

@Select("select id as tnId,nickname as tnNickname," +
        "userr_id as tnUserr_id from pet where id =#{id}")
@Results({
        @Result(id = true,property = "id",column = "tnId"),
        @Result(property = "nickname",column = "tnNickname"),
        @Result(property = "userr",column = "tnUserr_id",
                one = @One(select = "com.zzti.mybatis.mapper.UserrMapper.getUserrById2"))
})
public Pet getPetById2(Integer id);

UserrMapper接口

@Select("select * from userr where id =#{id}")
@Results({
        @Result(id = true,property = "id",column = "id"),
        @Result(property = "name", column = "name"),
        @Result(property = "pets",column = "id",
        many = @Many(select = "com.zzti.mybatis.mapper.PetMapper.getPetByUserrId2"))
})
public Userr getUserrById2(Integer id);

八. 缓存

一级缓存

1. 默认情况下,mybatis是启用一级缓存的/本地缓存/localCache,它是SqlSession级别的

2. 同一个SqlSession接口对象调用了相同的select语句,会直接从缓存里面获取,而不是再去查询数据库

3. 当执行的SQL查询中间发生了增删改的操作,mybatis会把SqlSession的缓存清空。

4. 一级缓存失效分析:
a) 关闭sqlSession会话后,再次查询,回到数据库查询;
b) 当执行sqlSession.clearCache()会使一级缓存失效,再次查询,会去数据库查询;
c) 当对同一个对象修改,该对象在一级缓存会失效,再次查询,会去数据库查询。

二级缓存

  1. 二级缓存和一级缓存都是为了提高检索效率的技术;
  2. 最大的区别就是作用域的范围不一样,一级缓存的作用域是sqlSession会话级别,在一次会话有效,而二级缓存作用域是全局范围(同一个nameSpace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。),针对不同的会话都有效。一个会话,查询一条数据,这个数据会被放在当前会话的一级缓存中;如果会话被关闭了,若有二级缓存,一级缓存汇总的数据会被保存到二级缓存。新的会话查询信息就会参照二级缓存。
  3. 二级缓存的使用原则:
    3.1 只能在一个命名空间下使用二级缓存。由于二级缓存中的数据是基于nameSpace的,即不同nameSpace中的数据互不干扰。在多个nameSpace中若均存在对同一个表的操作,那么这多个nameSpace中的数据可能就会出现不一致现象。
    3.2 在单表上使用二级缓存。如果一个表与其他表有关联关系,那么就非常有可能存在多个nameSpace对同一数据的操作。而不同nameSpace中的数据互不干扰,所以就有可能出现多个nameSpace中的数据不一致现象。
    3.3 查询多于修改时使用二级缓存。在查询操作远远多于增删改操作的情况下可以使用二级缓存。因为任何增删改操作都将刷新二级缓存,对二级缓存的频繁刷新将降低系统性能。

快速入门

1.开启二级缓存

<settings>
    <!--配置mybatis自带的日志输出,查看原生的SQL-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <!--开启二级缓存,默认是true-->
    <setting name="cacheEnabled" value="true"/>
</settings>
  1. 使用二级缓存entity类实现系列化接口(serializable),因为二级缓存可能使用到序列化技术
  2. 对应的XxxMapper.xml文件设置二级缓存的策略
 <!--eviction="FIFO"==>缓存策略,先进先出-->
 <!--flushInterval="30000"==>每30000毫秒 刷新一次-->
 <!--size="360" ===> 二级缓存设置最大保存360个对象,超过了,就启用FIFO策略处理,默认是1024-->
 <!--readOnly="true" ===> 只读,为了提高效率-->
 <cache eviction="FIFO" flushInterval="30000" size="360" readOnly="true"/>

  1. 四大策略
    LRU-最近最少使用的: 移除最长时间不被使用的对象,它是默认
    FIFO-先进先出: 按对象进入缓存的顺序来移除它们
    SOFT-软引用: 移除基于垃圾回收期状态和软引用规则的对象
    WEAK-弱引用: 更积极地移除基于垃圾收集器状态和弱引用规则的对象

  2. 如何禁用二级缓存
    a) 在mybatis-config.xml文件中二级缓存设置为false
    b) 在XxxMapper.xml文件中关闭cache
    c) 在mapper.xml中的某个配置方法上指定useCache=“false”,useCache默认是true,一般不需要修改,使用默认的就行。

<select id="findMonsterByNameOrId" parameterType="Monster" resultType="Monster" useCache="false">
    select * from monster where id=#{id} or name=#{name}
</select>

d) mybatis刷新二级缓存的设置,flushCache=“true”
insert、update、delete操作数据后需要刷新缓存,若不执行刷新缓存会出现脏读,默认是true,一般不需要修改

<update id="updateMonster" parameterType="Monster" flushCache="true">
    update monster set age=#{age},birthday=#{birthday},email=#{email},
    gender=#{gender},name=#{name},salary=#{salary}
    where id=#{id}
</update>
  1. MyBatis的一级缓存和二级缓存执行顺序: 二级缓存 ==> 一级缓存 ==> 数据库 不会出现一级缓存和二级缓存中都有同一个数据,因为二级缓存是在一级缓存关闭之后才有的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值