mybatis使用总结

来源:互联网 发布:国家人文历史杂志 知乎 编辑:程序博客网 时间:2024/05/17 08:26

公司目前使用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">selectfw_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.actionfromfw_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原理》