mybatis使用总结

公司目前使用springmvc+maven+mybatis开发项目,用到了数据库中一对多的关系,所以做此总结。

mapper代理开发dao

使用mapper代理开发dao时,需要编写mapper.xml映射文件以及mapper接口。

<mapper namespace="com.zyuc.fw.basic.service.repository.mapper.IFwAclPolicyMapper">

    <insert id="insert" parameterType="AclPolicy" useGeneratedKeys="true" keyProperty="aclId">
        insert into fw_acl_policy (vfw_id, acl_number) values (#{vfwId},#{aclNumber})
    </insert>

    <delete id="delete" parameterType="AclPolicy">
        delete from fw_acl_policy
        <where>
            <if test="aclNumber != null and aclNumber != ''">
            fw_acl_policy.acl_number=#{aclNumber}
            </if>
        </where>
    </delete>

定义好了mapper.xml映射文件后,接下来就要编写mapper接口了,编写mapper接口要遵循以下四个开发规范:

  1. 在mapper.xml中,使namespace等于mapper接口的地址(完全限定名)
  2. mapper.java接口中的方法名和mapper.xml中statement的id一致
  3. mapper.java接口中方法的输入参数类型和mapper.xml中statement的parameterType指定的类型一致
  4. mapper.java接口中方法返回值类型和mapper.xml中statement的resultType指定的类型一致

根据这四条开发规范,我们来完成mapper接口

public interface IRepository<T> {
    int insert(T var1);

    int update(T var1);

    int delete(T var1);

    T get(T var1);

    PageWrapper<T> page(PageParam var1, T var2);
}

public interface IFwAclPolicyMapper extends IRepository<AclPolicy> {
}

mybatis全局配置文件

配置内容 作用
< properties> 用来加载属性文件
< settings> 用来设置全局参数
< typeAliases> 用来设置类型的别名
< typeHandlers> 用来设置类型处理器
< objectFactory> 用来设置对象工厂
< plugins> 用来设置插件
< environments> 用来设置mybatis的环境
< mappers> 用来配置映射文件

需要注意的是,配置项需要严格按照顺序来配置。

mapper.xml中定义了许多参数类型。类型全路径,有时候会很长,不方便进行开发,那么我们就可以可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名来定义,方便开发。

<!-- 别名的定义 -->
<typeAliases>
    <!-- 针对单个别名的定义。type:类型的路径; alias:别名 -->     
    <typeAlias type="mybatis.po.User" alias="user"/>
</typeAliases>

然后输入参数或者输出结果为mybatis.po.User时,就可以用user来代替了。

数据库一对多关系

这里aclPolicy对应多条aclRule。aclRule的查找实现如下:

<resultMap type="AclRule" id="AclRuleResultMap">
        <!-- 配置acl规则的明细信息 -->
        <id column="acl_id" property="aclId"/>
        <result column="global_rule_id" property="globalRuleId"/>
        <result column="protocol" property="protocol"/>
        <result column="source_ip" property="sourceIp"/>
        <result column="dest_ip" property="destIp"/>
        <result column="action" property="action"/>
    </resultMap>
<select id="getAclRule" parameterType="String" resultMap="AclRuleResultMap">
        select * from fw_acl_rule where global_acl_id=#{global_acl_id}
</select>

//此处定义aclPolicy的resultmap,collection可以包含一个list
<resultMap type="AclPolicy" id="AclPolicyResultMap">
<!--定义aclpolicy公共参数-->
<id column="acl_id" property="aclId"/>
<result column="vfw_id" property="vfwId"/>
<result column="acl_number" property="aclNumber"/>
<!-- 配置acl规则的明细信息 -->
<collection property="aclRules" column="global_acl_id" javaType="ArrayList" ofType="AclRule" select="getAclRule"/>
</resultMap>

<sql id="Acl_Policy_Column">
select
fw_acl_policy.*,
fw_acl_rule.global_rule_id,
fw_acl_rule.global_acl_id,
fw_acl_rule.protocol,
fw_acl_rule.source_ip,
fw_acl_rule.dest_ip,
fw_acl_rule.action
from
fw_acl_policy LEFT JOIN fw_acl_rule ON fw_acl_policy.global_acl_id = fw_acl_rule.global_acl_id
</sql>

<select id="get" parameterType="AclPolicy" resultMap="AclPolicyResultMap">
<include refid="Acl_Policy_Column" />
<where>
<if test="vfwId != null and vfwId != ''">
fw_acl_policy.vfw_id=#{vfwId}
</if>
<if test="aclNumber != null and aclNumber != ''">
AND fw_acl_policy.acl_number=#{aclNumber}
</if>
</where>
</select>

这样进行查询aclPolicy时,就会查出aclRule的list。

结果如下:

{"body":{"acl_number":"10","acl_rules":
[{"action":true,"dest_ip":"2.2.2.2","global_acl_id":"1","global_rule_id":"1","protocol":"17","rule_id":"1","source_ip":"1.1.1.1"},
{"action":true,"dest_ip":"4.4.4.4","global_acl_id":"1","global_rule_id":"2","protocol":"16","rule_id":"2","source_ip":"3.3.3.3"}],
"global_acl_id":"1","vfw_id":"1"},
"success":true}

缓存

序列化缓存

  • 用途是先将对象序列化成2进制,再缓存,好处是将对象压缩了,省内存
  • 坏处是速度慢了

mybatis一级缓存

mybatis默认支持一级缓存,不需要另外配置
在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。
为了解决这一问题,减少资源的浪费,MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候,如果判断先前有个完全一样的查询,会直接从缓存中直接将结果取出,返回给用户,不需要再进行一次数据库查询了

一级缓存被清除时机

a. MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
b. 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
c. 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
d.SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;

mybatis二级缓存

MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。如果开启了二级缓存,那么在关闭sqlsession后,会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。

MyBatis查询数据的顺序是:
二级缓存 ———> 一级缓存——> 数据库

要开启二级缓存步骤:

1.打开二级缓存总开关
打开总开关,只需要在mybatis总配置文件中加入一行设置

<settings>
   <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>

2.打开需要使用二级缓存的mapper的开关

在需要开启二级缓存的mapper.xml中加入caceh标签

<cache/>

3.POJO序列化

让需要使用二级缓存的POJO类实现Serializable接口,如

public class User implements Serializable {

通过之前三步操作就可以使用二级缓存了。测试一下

@Test
    public void testFindUsersCache() throws Exception {
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.findUsers();
        //关闭sqlsession
        sqlSession.close();

        //通过sqlsessionFactroy创建一个新的sqlsession
        sqlSession = sqlSessionFactory.openSession();
        //获取mapper对象
        userMapper = sqlSession.getMapper(UserMapper.class);
        users = userMapper.findUsers();
        System.out.println(users);
    }

还有一个问题,之前说了,即使开启了二级缓存,不同的sqlsession之间的缓存数据也不是想互访就能互访的,必须等到sqlsession关闭了以后,才会把其一级缓存中的数据写入二级缓存。如果注释sqlSession.close();则下次查询不会从缓存获取。

参考

MyBatis映射文件的resultMap如何做表关联

MyBatis学习

《深入理解mybatis原理》

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值