Mybatis小结二:映射,存储过程,缓存

Posted 名人堂之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis小结二:映射,存储过程,缓存相关的知识,希望对你有一定的参考价值。

一、一对一:
这个地方与hibernate对比,hibernate 的关联操作应该就是id相等,但是mybatis可以用另外几种方法关联吧,left join or right join。 这些方法有时候可能会得到我们想要的结果,这是hibernate所做不到的吧。

<mapper namespace="ClassesMapper">
<!-- select * from class c RIGHT join  teacher t on c.teacher_id = t.t_id where t.t_id=#{id} -->
    <select id="getClass" parameterType="int" resultMap="ClassResultMap">
        select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
    </select>
    <!-- 使用resultMap映射实体类和字段之间的一一对应关系 -->
    <resultMap type="Classes" id="ClassResultMap">
        <id property="id" column="c_id"/>
        <result property="name" column="c_name"/>
        <association property="teacher" javaType="Teacher">
            <id property="id" column="t_id"/>
            <result property="name" column="t_name"/>
        </association>
    </resultMap>
</mapper>

二、一对多:
是用到了collection,,相当于set集合的效果。这里需要稍微注意的是,association 和 collection 对应实体类Classes中的成员变量,一个是类Teacher,一个是集合students( ).

<select id="getClass3" parameterType="int" resultMap="ClassResultMap3">
    select * from class c, teacher t,student s where c.teacher_id=t.t_id and c.C_id=s.class_id and  c.c_id=#{id}
</select>
<resultMap type="Classes" id="ClassResultMap3">
    <id property="id" column="c_id"/>
    <result property="name" column="c_name"/>
    <association property="teacher" column="teacher_id" javaType="Teacher">
        <id property="id" column="t_id"/>
        <result property="name" column="t_name"/>
    </association>
    <!-- ofType指定students集合中的对象类型 -->
    <collection property="students" ofType="Student">
        <id property="id" column="s_id"/>
        <result property="name" column="s_name"/>
    </collection>
</resultMap>

三、调用存储过程:
需要注意的是in和out,这里传入的是一个map,最后的执行结果会返回到usercount里面,需要再取出来查看结果。

<select id="getUserCount" parameterMap="getUserCountMap" statementType="CALLABLE">
    CALL test.ges_user_count(?,?)
</select>

<parameterMap type="java.util.Map" id="getUserCountMap">
    <parameter property="sexid" mode="IN" jdbcType="INTEGER"/>
    <parameter property="usercount" mode="OUT" jdbcType="INTEGER"/>
</parameterMap>

测试代码

Map<String, Integer> parameterMap = new HashMap<String, Integer>();
parameterMap.put("sexid"1);
parameterMap.put("usercount"-1);
cm.getUserCount(parameterMap);
System.out.println("-----------Midas-----------hm值=" + parameterMap + "," + "当前类=MybatisTest.testOne()");

报错无外乎以下几种问题
1.mysql里面压根没有那个存储过程
2.Mysql里存储过程的名字跟调用的存储过程名字不一样(名字写错了)
3.存储过程代码里面写了注释(中文、英文都删了吧)
4.接收的参数有问题

一级缓存,基于PerpetualCache 的hashmap本地缓存,存储作用域为Session,
session刷新或者关闭操作后,缓存清空
二级缓存,存储作用域为namespace,对应的那个mapper

四、一级缓存测试:

List<Classes> aClass = cm.getClass(3);
for(Classes classes : aClass){
    System.out.println("-----------Midas-----------aclasses值=" + classes + "," + "当前类=MybatisTest.testOne()");
}
List<Classes> bClass = cm.getClass(3);
for(Classes classes : bClass){
    System.out.println("-----------Midas-----------bclasses值=" + classes + "," + "当前类=MybatisTest.testOne()");
}

结果,可以从打印出的sql可以看出,sql语句只执行了一次。

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 841283083.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3224f60b]
==>  Preparing: select * from class c RIGHT join teacher t on c.teacher_id = t.t_id where t.t_id=? 
==> Parameters: 3(Integer)
<==    Columns: c_id, c_name, teacher_id, t_id, t_name
<==        Row: nullnullnull3, teacher3
<==      Total: 1
-----------Midas-----------aclasses值=Classes{id=0, name='null', teacher=Teacher [id=3, name=teacher3], students=null},当前类=MybatisTest.testOne()
-----------Midas-----------bclasses值=Classes{id=0, name='null', teacher=Teacher [id=3, name=teacher3], students=null},当前类=MybatisTest.testOne()

执行不同的查询操作看一下。

List<Classes> aClass = cm.getClass(3);
for(Classes classes : aClass){
    System.out.println("-----------Midas-----------aclasses值=" + classes + "," + "当前类=MybatisTest.testOne()");
}
List<Classes> bClass = cm.getClass(2);
for(Classes classes : bClass){
    System.out.println("-----------Midas-----------bclasses值=" + classes + "," + "当前类=MybatisTest.testOne()");
}

结果,sql出现了两次。

==>  Preparing: select * from class c RIGHT join teacher t on c.teacher_id = t.t_id where t.t_id=? 
==> Parameters: 3(Integer)
<==    Columns: c_id, c_name, teacher_id, t_id, t_name
<==        Row: nullnullnull3, teacher3
<==      Total: 1
-----------Midas-----------aclasses值=Classes{id=0, name='null', teacher=Teacher [id=3, name=teacher3], students=null},当前类=MybatisTest.testOne()
==>  Preparing: select * from class c RIGHT join teacher t on c.teacher_id = t.t_id where t.t_id=? 
==> Parameters: 2(Integer)
<==    Columns: c_id, c_name, teacher_id, t_id, t_name
<==        Row: 2, class_b, 22, teacher2
<==      Total: 1
-----------Midas-----------bclasses值=Classes{id=2, name='class_b', teacher=Teacher [id=2, name=teacher2], students=null},当前类=MybatisTest.testOne()

五、二级缓存:
这里需要注意的是,必须要commit或者close之后,二级缓存才会有效果,毕竟需要刷新到mapper缓存中。对于CUD来说,事务提交后,缓存都会被清空。
而一级缓存,在commit后,查询相同的内容缓存就不会有作用了,这时候commit相当于清空一级缓存session。

SqlSession session = MybatisUtils.getSession();
        SqlSession session2 = MybatisUtils.getSession();
        SqlSession session3 = MybatisUtils.getSession();
        ClassesMapper cm  = session.getMapper(ClassesMapper.class);
        ClassesMapper mapper = session2.getMapper(ClassesMapper.class);
        ClassesMapper mapper3 = session3.getMapper(ClassesMapper.class);
        //List<HashMap<String,String>> list = table.selectAll();
        //for(HashMap hm : list){
        //    System.out.println("-----------Midas-----------string值=" + hm.get("name") + "," + "当前类=MybatisTest.testOne()");
        //}
        List<Classes> aClass = cm.getClass(3);
        for(Classes classes : aClass){
            System.out.println("-----------Midas-----------aclasses值=" + classes + "," + "当前类=MybatisTest.testOne()");
        }
        //session.commit();
        List<Classes> bClass = cm.getClass(3);
        for(Classes classes : bClass){
            System.out.println("-----------Midas-----------bclasses值=" + classes + "," + "当前类=MybatisTest.testOne()");
        }
        session.commit();
        List<Classes> cClass = mapper.getClass(3);
        for(Classes classes : cClass){
            System.out.println("-----------Midas-----------bclasses值=" + classes + "," + "当前类=MybatisTest.testOne()");
        }

        //session.commit();
        List<Classes> dClass = mapper3.getClass(3);
        for(Classes classes : dClass){
            System.out.println("-----------Midas-----------dclasses值=" + classes + "," + "当前类=MybatisTest.testOne()");
        }

结果如下

==>  Preparing: select * from class c RIGHT join teacher t on c.teacher_id = t.t_id where t.t_id=? 
==> Parameters: 3(Integer)
<==    Columns: c_id, c_name, teacher_id, t_id, t_name
<==        Row: nullnullnull3, teacher3
<==      Total: 1
-----------Midas-----------aclasses值=Classes{id=0, name='null', teacher=Teacher [id=3, name=teacher3], students=null},当前类=MybatisTest.testOne()
Cache Hit Ratio [ClassesMapper]: 0.0
-----------Midas-----------bclasses值=Classes{id=0, name='null', teacher=Teacher [id=3, name=teacher3], students=null},当前类=MybatisTest.testOne()
Cache Hit Ratio [ClassesMapper]: 0.3333333333333333
-----------Midas-----------bclasses值=Classes{id=0, name='null', teacher=Teacher [id=3, name=teacher3], students=null},当前类=MybatisTest.testOne()
Cache Hit Ratio [ClassesMapper]: 0.5
-----------Midas-----------dclasses值=Classes{id=0, name='null', teacher=Teacher [id=3, name=teacher3], students=null},当前类=MybatisTest.testOne()

只有一次sql语句被执行。另外需要注意的是cache hit,代表缓存请求命中率。


以上是关于Mybatis小结二:映射,存储过程,缓存的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot进阶系列二

mybatis面试题总结

MyBatis-------添加

Mybatis小结之详解Mapper.xml

mybatis

MyBatis学习SQL语句映射文件增删改查参数缓存