ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MyBatis延迟加载、缓存、分页插件

2022-06-24 20:31:21  阅读:108  来源: 互联网

标签:username 插件 缓存 EnumSex sex public MyBatis id


一、MyBatis延迟加载策略

(一)什么是延迟加载:

当时不使用的时候不加载,使用的时候再加载.

(二)延迟加载的好处

好处:提高性能

(三)使用懒加载:

在mybatis.xml配置文件

<settings>

<setting name="lazyLoadingEnabled" value="true"/>

<setting name="aggressiveLazyLoading" value="false"/>

</settings>

(四)具体案例

1.在mybatis.xml不配置懒加载

<select id="findById" parameterType="int" resultMap="personMap">
    select * from person where id=#{id}
</select>
<resultMap id="personMap" type="com.tjetc.entity.Person">
    <id column="id" property="id"></id>
    <result column="name" property="name"></result>
    <association property="idCard" column="id" select="findByPid"></association>
</resultMap>
<select id="findByPid" parameterType="int" resultType="com.tjetc.entity.IdCard">
    select * from idcard where pid=#{id}
</select>

 

 @Test
    public void testFindById() {
//        创建SqlSessionFactory
       
SqlSessionFactory sqlSessionFactory = null;
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml"));
//            得到session对象
           
SqlSession session = sqlSessionFactory.openSession();
            //得到mapper
           
PersonMapper personMapper = session.getMapper(PersonMapper.class);
            //调用PersonMapper的方法
           
Person person = personMapper.findById(1);
//            System.out.println(person);
//            IdCard idCard = person.getIdCard();
//            System.out.println(idCard);
           
session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 

==>  Preparing: select * from person where id=?

==> Parameters: 1(Integer)

<==    Columns: id, name

<==        Row: 1, 张三

====>  Preparing: select * from idcard where pid=?

====> Parameters: 1(Integer)

<====    Columns: id, code, pid

<====        Row: 1, 12345678234567, 1

<====      Total: 1

<==      Total: 1

 

2.在mybatis.xml配置懒加载

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

 

==>  Preparing: select * from person where id=?

==> Parameters: 1(Integer)

<==    Columns: id, name

<==        Row: 1, 张三

<==      Total: 1

 

二、Mybatis缓存

(一)一级缓存

1.概述

如下图所示,MyBatis会在一次会话的表示----一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否存在,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。

对于会话(Session)级别的数据缓存,我们称之为一级数据缓存,简称一级缓存

2.一级缓存的工作流程

1.对于某个查询,根据statementId,params,rowBounds来构建一个key值,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果;

  1. 判断从Cache中根据特定的key值取的数据数据是否为空,即是否命中;
  2. 如果命中,则直接将缓存结果返回;
  3. 如果没命中:

        4.1  去数据库中查询数据,得到查询结果;

        4.2  将key和查询到的结果分别作为key,value对存储到Cache中;

        4.3. 将查询结果返回;

  1. 结束。

(二)二级缓存

1.概述

MyBatis的缓存机制整体设计以及二级缓存的工作模式

MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。

CachingExecutor是Executor的装饰者,以增强Executor的功能,使其具有缓存查询的功能,这里用到了设计模式中的装饰者模式。

2.二级缓存的相关配置

要想使某条Select查询支持二级缓存,你需要保证:

1.MyBatis支持二级缓存的总开关:全局配置变量参数cacheEnabled=true

2.该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效

3.该select语句的参数useCache=true

4.对象的类必须实现序列化接口

一级缓存和二级缓存的使用顺序 :

二级缓存———> 一级缓存——> 数据库

二级缓存作用域为 Mapper(Namespace);

configuration.MappedStatement.Cache;项目启动时会初始化;

3.Cache使用时的注意事项/避免使用二级缓存

注意事项

  1. 只能在【只有单表操作】的表上使用缓存,不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个namespace下。
  2. 在可以保证查询远远大于insert,update,delete操作的情况下使用缓存,这一点需要保证在1的前提下才可以!

 

避免使用二级缓存

可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。

1.缓存是以namespace为单位的,不同namespace下的操作互不影响。

2.insert,update,delete操作会清空所在namespace下的全部缓存。

3.通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。

 

多表操作一定不能使用缓存

首先不管多表操作写到那个namespace下,都会存在某个表不在这个namespace下的情况。

例如两个表:role和user_role,如果我想查询出某个用户的全部角色role,就一定会涉及到多表的操作。

<select id="selectUserRoles" resultType="UserRoleVO">

    select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid}

</select>

 

像上面这个查询,你会写到那个xml中呢??

不管是写到RoleMapper.xml还是UserRoleMapper.xml,或者是一个独立的XxxMapper.xml中。如果使用了二级缓存,都会导致上面这个查询结果可能不正确。

如果你正好修改了这个用户的角色,上面这个查询使用缓存的时候结果就是错的。

三、typeHandler使用

数据表:

CREATE TABLE `admin` (

  `id` bigint NOT NULL AUTO_INCREMENT,

  `username` varchar(255) NOT NULL,

  `password` varchar(255) NOT NULL,

  `sex` int DEFAULT NULL,

  PRIMARY KEY (`id`)

)

枚举定义

/**
 *
性别枚举
 
*/
public enum EnumSex {
    FEMALE(0, "女"),
    MALE(1, "男");
    /**
     *
编码
    
*/
   
private int code;
    /**
     *
显示的名称
    
*/
   
private String name;
    EnumSex(int code, String name) {
        this.code = code;
        this.name = name;
    }
    public int getCode() {
        return code;
    }
    public String getName() {
        return name;
    }
    public static EnumSex getByCode(int code) {
        //获取所有的枚举值(枚举数组)
       
EnumSex[] values = EnumSex.values();
        //遍历数组,查找每一个枚举的code是否与传进来的参数code相等,如果相等就返回对应的枚举
       
for (EnumSex value : values) {
            if (value.getCode() == code) {
                return value;
            }
        }
        return null;
    }
}

自定义typeHandler处理器

/**
 *
自定义性别枚举处理器
 
*/
public class EnumSexTypeHandler implements TypeHandler<EnumSex> {
    /**
     * javaType
转换 jdbcType 参数设置调用
    
*
     * @param
preparedStatement
    
* @param i
    
* @param enumSex
    
* @param jdbcType
    
* @throws SQLException
    
*/
   
@Override
    public void setParameter(PreparedStatement preparedStatement, int i, EnumSex enumSex, JdbcType jdbcType) throws SQLException {
        //增加和修改 sex字段 用到jdbc参数设置
       
preparedStatement.setObject(i, enumSex.getCode());
    }

    /**
     * jdbctye
javatype  用户查询
    
*
     * @param
resultSet
    
* @param s
    
* @return
     * @throws
SQLException
    
*/
   
@Override
    public EnumSex getResult(ResultSet resultSet, String s) throws SQLException {
        //根据columnLabel 获取对应结果集的值 sex 对应code
       
int sexCode = resultSet.getInt(s);
        //sexCode转换成枚举值 返回出去
       
return EnumSex.getByCode(sexCode);
    }

    @Override
    public EnumSex getResult(ResultSet resultSet, int i) throws SQLException {
        //根据columnIndex 获取对应结果集的值 sex 对应code
       
int sexCode = resultSet.getInt(i);
        //sexCode转换成枚举值 返回出去
       
return EnumSex.getByCode(sexCode);
    }

    /**
     *
存储过程调用
    
*
     * @param
callableStatement
    
* @param i
    
* @return
     * @throws
SQLException
    
*/
   
@Override
    public EnumSex getResult(CallableStatement callableStatement, int i) throws SQLException {
        int sexCode = callableStatement.getInt(i);
        //sexCode转换成枚举值 返回出去
       
return EnumSex.getByCode(sexCode);
    }
}

Admin实体类

public class Admin {
    private Long id;
    private String username;
    private String password;
    private EnumSex sex;

    public Admin() {
    }

    public Admin(String username, String password, EnumSex sex) {
        this.username = username;
        this.password = password;
        this.sex = sex;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public EnumSex getSex() {
        return sex;
    }

    public void setSex(EnumSex sex) {
        this.sex = sex;
    }

    public Admin(Long id, String username, String password, EnumSex sex) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Admin{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", sex=" + sex +
                '}';
    }
}

AdminMapper接口

public interface AdminMapper {
    void insert(Admin admin);

    Admin selectById(Long id);
}

AdminMapper.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" >
<mapper namespace="com.tjetc.dao.AdminMapper">
    <insert id="insert" parameterType="admin" useGeneratedKeys="true" keyProperty="id">
        insert into admin(username,password,sex) values(#{username},#{password},#{sex,typeHandler=com.tjetc.handler.EnumSexTypeHandler})
    </insert>
    <select id="selectById" parameterType="long" resultMap="adminMap">
        select id,username,password,sex from admin where id=#{id}
    </select>
    <resultMap id="adminMap" type="admin">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="sex" property="sex" typeHandler="com.tjetc.handler.EnumSexTypeHandler"></result>
    </resultMap>
</mapper>

Mybatis.xml增加配置

<!--配置自定义typeHandler-->
<typeHandlers>
    <!--<package name=""/>-->
   
<typeHandler handler="com.tjetc.handler.EnumSexTypeHandler"/>
</typeHandlers>

测试:

public class TestAdmin {
    @Test
    public void testInsert() throws IOException {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
        Admin admin = new Admin("wangwu", "5555", EnumSex.FEMALE);
        mapper.insert(admin);
        sqlSession.commit();
        System.out.println(admin);
        sqlSession.close();
    }

    @Test
    public void testSelectById() throws IOException {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
        Admin admin = mapper.selectById(4L);
        System.out.println(admin);
        sqlSession.close();
    }
}

 

四、基于Annotation注解实现映射处理

在mapper映射接口的方法上写SQL,这样可以省略mapper的xml映射文件

public interface UserMapper {
    @Select("SELECT * FROM user where id=#{id}")
    User findById(int id);

 

 @Test
    public void testFind2() {
        try {
//        创建SqlSessionFactory
           
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml"));
//            得到session对象
           
SqlSession session = sqlSessionFactory.openSession();
            //得到mapper接口的实现对象
           
UserMapper mapper = session.getMapper(UserMapper.class);
//            通过session对象操作数据库
           
User user = mapper.findById(1);
//            控制台打印user对象
           
System.out.println(user);
//            关闭session
           
session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 

==>  Preparing: SELECT * FROM user where id=?

==> Parameters: 1(Integer)

<==    Columns: id, password, username

<==        Row: 1, 123456, admin

<==      Total: 1

User{id=1, username='admin', password='123456'}

五、MyBatis分页插件PageHelper

<!--mybatis的分页插件-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.9</version>
</dependency>

 

<plugins>

    <!-- com.github.pagehelperPageHelper类所在包名 -->

   
<plugin interceptor="com.github.pagehelper.PageInterceptor">

        <!-- 什么都不配,使用默认的配置 -->

   
</plugin>

</plugins>

 

 public void testFindAll2() {
        try {
//        创建SqlSessionFactory
           
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml"));
//            得到session对象
           
SqlSession session = sqlSessionFactory.openSession();
            //得到mapper接口的实现对象
           
UserMapper mapper = session.getMapper(UserMapper.class);
            PageHelper.startPage(2, 2);
//            通过session对象操作数据库
           
List<User> list = mapper.findAll();
            PageInfo<User> pageInfo = new PageInfo<>(list);
//            控制台打印list对象
           
for (User user : list) {
                System.out.println(user);
            }
//            关闭session
           
session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 

 

标签:username,插件,缓存,EnumSex,sex,public,MyBatis,id
来源: https://www.cnblogs.com/seventeen9588/p/16400370.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有