Mybatis学习笔记,包含mybatis基本使用、关系映射、动态SQL、分页插件等等

news2024/11/14 19:27:37

😀😀😀创作不易,各位看官点赞收藏.

文章目录

  • MyBatis 学习笔记
    • 1、Mybatis Demo 程序
    • 2、Mybatis 核心配置文件
    • 3、Mybatis Mapper 传参映射
    • 4、Mybatis 查询结果
    • 5、Mybatis 关系映射处理
      • 5.1、多对一关系映射处理
      • 5.2、一对多关系映射处理
    • 6、Mybatis 动态 SQL
    • 7、Mybatis 缓存
    • 8、Mybatis 分页插件

MyBatis 学习笔记

简介:MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。简单来说,mybatis就是用来操作数据库的,可以使程序猿更加容易书写 dao 层。

1、Mybatis Demo 程序

搭建环境:导入依赖、创建数据库表user(id,name,address)

<!--    junit-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
</dependency>
<!--    mybatis-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<!--    数据库连接-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>
<!--      log4j-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
</dependency>

编写配置文件:mybatis-config.xml,XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的主配置文件-->
<configuration>
    <!-- 数据库配置环境-->
    <!-- default和下面的id名称要一样,默认使用,可以定义多个环境-->
    <environments default="mysql">
        <!-- 配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务类型为jdbc-->
            <transactionManager type="JDBC"/>
            <!--   配置数据池连接源-->
            <!--   type有三种类型
                        1、POOLED是使用数据库连接池的类型
                        2、UNPOOLED是不适用数据库连接池的类型
                        3、JNDI是JNDI类型的数据源 JndiDataSource
             -->
            <dataSource type="POOLED">
                <!-- 配置数据库的4个基本信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?characterEncoding=utf-8&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 引入映射文件-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

编写 Mapper 接口:

public interface UserMapper {
    // 查询所有的用户
    List<User> findAllUser();
}

编写 mapper.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">
<!--namespace会绑定一个mapper接口,可以理解为实现这个接口,必须写全限定类名-->
<mapper namespace="com.jx.app.mybatis.mapper.UserMapper">
    <!--   id是接口中的方法名称,resultType是实体的全限定类名,标签体中写sql语句-->
    <select id="findAllUser" resultType="com.jx.app.mybatis.entity.User">
        select * from user
    </select>
</mapper>

编写 Mybatis 工具类:

public class MybatisUtils {
    // 成员变量
    private static SqlSessionFactory sqlSessionFactory;
    // 静态代码初始化
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 获取sqlSession
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

测试查询结果:

@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = mapper.findAllUser();
    System.out.println(users);
}

2、Mybatis 核心配置文件

environments:配置数据库连接配置环境。

<!-- default和下面的id名称要一样,默认使用,可以定义多个环境-->
<environments default="mysql">
    <!-- 配置mysql的环境,id是唯一标识不能重复-->
    <environment id="mysql">
        <!-- 配置事务管理方式:JDBC(原生事务)、MANAGED()-->
        <transactionManager type="JDBC"/>
        <!--   配置数据池连接源-->
        <!--   type有三种类型
                        1、POOLED是使用数据库连接池的类型
                        2、UNPOOLED是不适用数据库连接池的类型
                        3、JNDI使用上下文的数据源
         -->
        <dataSource type="POOLED">
            <!-- 配置数据库的4个基本信息-->
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql:///mybatis?characterEncoding=utf-8&amp;serverTimezone=UTC"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </dataSource>
    </environment>
</environments>

propertes:可以引入 properties 文件,然后通过某种方式去访问文件中的值。

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///mybatis?characterEncoding=utf-8&amp;serverTimezone=UTC
username=root
password=123456
<!-- 引入文件,然后可以在下面通过 ${key值} 获取对应的value-->
<properties resource="jdbc.properties"/>

settings:Mybatis 的全局配置,还有很多配置,可以去官网上查看。

<settings>
    <!-- 字段名与属性名驼峰命名映射:user_name == userName-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!-- 指定 mybatis 中的日志输出-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

typeAliases:取别名标签,给实体类取一个别名,在映射结果时就可以使用别名就不再使用全限定类名。

<typeAliases>
    <!-- 在编写 mapper 映射文件时就可以使用 User 来代替这个全限定类名,不设置 alias 别名就是类名-->
    <typeAlias type="com.jx.app.mybatis.entity.User" alias="User"/>
    
    <!-- 把指定包下的所有类都起别名,别名都是类名-->
    <package name="com.jx.app.mybatis.entity"/>
</typeAliases>

mappers:引入 mapper 映射文件。

<!-- 引入映射文件-->
<mappers>
    <!-- 需要引入 mapper 文件存放在 resources 目录下-->
    <mapper resource="mapper/UserMapper.xml"/>

    <!-- 通过包名进行引入:1、mapper 文件名需要与接口一样,2、mapper 存放的目录结构也必须和接口保持一致-->
    <package name="com.jx.app.mybatis.mapper"/>
</mappers>

3、Mybatis Mapper 传参映射

​ 在 mapper 映射文件获取接口的参数有两种方式,${}#{}

  • ${}: 本质是字符串拼接,将参数与 SQL 语句进行简单拼接,这种方式可能存在 SQL 注入问题,使用这种方式需要注意字符串的单引号拼接。
  • #{}:本质是占位符方式来拼接 SQL,自动给参数加上单引号,这种方式防止 SQL 注入问题。

单个字面量参数:

// 参数 name 是单个字面量
User getUserByName(String name);
<select id="getUserByName" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    WHERE u.user_name = #{name} 
    <!-- name参数需要和接口参数名保持一致-->
</select>

多个字面量参数:

// 存在多个参数
User getUser(String id, String name);
<!-- 如果存在多个参数,那么 mybatis 会把参数存储在一个 map 中,key:[arg0,arg1...,param1,param2...] 
     可以通过对应的键获取参数值,但是不能通过参数名去获取,这两种 key 可以混用,顺序就是指定的下标
-->
<select id="getUser" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    <!-- WHERE u.id = #{arg0} AND u.user_name = #{arg1}-->
    WHERE u.id = #{param1} AND u.user_name = #{param2}
</select>

map 传参:

// 参数是一个map
User getUserByMap(Map<String,String> map);
<!-- 参数是一个 map,可以直接根据 key 获取对应的值-->
<select id="getUserByMap" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    WHERE u.id = #{id} AND u.user_name = #{username}
</select>

实体类传参:

// 参数是一个是实体类
int insert(User user);
<!-- 参数是实体类,可以通过类的属性名获取对应的属性值-->
<insert id="insert">
    INSERT INTO user values(null,#{userName},#{password},#{money})
</insert>

@param 注解:可以命名参数,标识参数后依然后把参数放入 map 中,可以通过命名参数的 key 来获取参数值。

// @Param 将参数进行取别名命名
User getUser(@Param("id") String id, @Param("name") String name);
<!-- 使用 @param 注解后可以直接使用对应的命名 key 获取对应的值-->
<select id="getUser" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    WHERE u.id = #{id} AND u.user_name = #{name}
</select>

4、Mybatis 查询结果

查询结果为实体对象:

// 接口返回值为实体对象
User getUserByName(String name);
<!-- resultType:属性需要指定返回值的全限定类名或者是别名-->
<select id="getUserByName" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    WHERE u.user_name = #{name}
</select>

注意:返回值是一个实体类对象时,返回结果只能是一条数据或者 null,如果查询出来是多条数据就会报错。

查询结果为集合:

// 接口返回值为集合类型,并指定对应泛型
List<User> getUserByName(@Param("name") String name);
<!-- resultType:需要指定集合中泛型对应类的全限定类名或者别名-->
<select id="getUserByName" resultType="com.jx.app.mybatis.entity.User">
    SELECT * FROM user u
</select>

注意:如果查询出来一条或多条结果就会封装到集合中,如果没有结果就会返回空集合但是不会返回 null。

查询结果为 map 集合:

// 接口返回值是map类型
Map<String,Object> getUserToMap();
<!-- 将查询的接口以字段名为key,然后字段值为 value 的 map-->
<select id="getUserToMap" resultType="java.util.Map">
    SELECT * FROM user u
</select>

注意:查询结果为 map 只能查询一条数据,查询出多条就会报错,而且如果某个字段是 null,这个字段不会封装到 map 中。

多条结果封装成 map:

/**
 * 如果查询多条数据也想封装成 map,@MapKey 可以指定查询出来那个字段可以作为 key,
 * 然后这一条数据又会封装成一个 map 作为 value 存储进去
*/
@MapKey("id")
Map<String, Map<String,Object>> getUserToMap();

获取自增主键:在插入数据时,可以获取插入数据后对应的自动递增的 id。

// 插入元素
int insert(User user);
<!-- 
    useGeneratedKeys:设置是否能够获取到自增主键
    keyProperty:获取到的主键的值存储到参数实体的哪个属性
-->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO user values(null,#{userName},#{password},#{money})
</insert>

resultMap 字段关系映射:查询出来的结果与实体类上的字段名称不一致,我们就需要通过 resultMap 属性去自定义映射关系。

方式一:字段起别名,可以在 SQL 语句中把字段名通过起别名方式与属性名一一对应。

方式二:使用 resultMap 映射,将查询出来字段名与对象属性名进行一个自定义映射。

<!-- 设置返回值类型为 resultMap,并且创建一个映射-->
<select id="getUserList" resultMap="UserListMap">
    SELECT * FROM user u
</select>

<!-- 关系映射,id属性:需要和映射返回值相同,type属性:就是映射的实体对象类型-->
<!-- id:数据库主键字段,result:普通字段。
       column属性:查询数据库对应字段名,property属性:需要映射的属性名称。
 -->
<resultMap id="UserListMap" type="com.jx.app.mybatis.entity.User">
    <id column="id" property="id"/>
    <result column="user_name" property="userName"/>
    <result column="password" property="password"/>
    <result column="money" property="money"/>
</resultMap>

注意:如果查询出来字段名与属性名对应不上,不会报错,只是他们对应属性值都是对象默认值。

5、Mybatis 关系映射处理

两个实体:Student 和 Teacher,一个学生有一个老师,一个老师有多个学生。

@Data
public class Student {
    private String id;
    private String studentName;
    private Teacher teacher;
}
@Data
public class Teacher {
    private String id;
    private String teacherName;
    private List<Student> students;
}

5.1、多对一关系映射处理

方式一:使用连接查询查询对学生对应的老师信息,然后使用级联属性映射。

<!-- 使用连接查询获取学生信息以及老师信息-->
<select id="getStudentById" resultMap="StudentMap">
    SELECT * FROM student s
    LEFT JOIN teacher t ON s.t_id = t.id
    WHERE s.id = #{id}
</select>

<!-- 使用级联方式进行属性映射-->
<resultMap id="StudentMap" type="com.jx.app.mybatis.entity.Student">
    <id column="id" property="id"/>
    <result column="student_name" property="studentName"/>
    <result column="t_id" property="teacher.id"/>
    <result column="teacher_name" property="teacher.teacherName"/>
</resultMap>

方式二:使用连接查询查询对学生对应的老师信息,然后通过 resultMap 进行关系映射。

<!-- 使用连接查询获取学生信息以及老师信息-->
<select id="getStudentById" resultMap="StudentMap">
    SELECT * FROM student s
    LEFT JOIN teacher t ON s.t_id = t.id
    WHERE s.id = #{id}
</select>

<!-- 使用 association 关系映射-->
<resultMap id="StudentMap" type="com.jx.app.mybatis.entity.Student">
    <id column="id" property="id"/>
    <result column="student_name" property="studentName"/>
    <!-- property:需要映射的属性名,javaType:这个属性的 java 类型是什么-->
    <association property="teacher" javaType="com.jx.app.mybatis.entity.Teacher">
        <id column="t_id" property="id"/>
        <result column="teacher_name" property="teacherName"/>
    </association>
</resultMap>

方式三:通过子查询去查询老师信息,然后通过 resultMap 进行关系映射。

<!-- 先获取学生信息-->
<select id="getStudentById" resultMap="StudentMap">
    SELECT * from student WHERE id = #{id}
</select>

<resultMap id="StudentMap" type="com.jx.app.mybatis.entity.Student">
    <id property="id" column="id"/>
    <result property="studentName" column="student_name"/>
    <!-- select:子查询的唯一标识(命名空间+id),column:给子查询的查询参数-->
    <association property="teacher" select="com.jx.app.mybatis.mapper.UserMapper.getTeacher" column="t_id"/>
</resultMap>

<!-- 子查询-->
<select id="getTeacher" resultType="com.jx.app.mybatis.entity.Teacher">
    SELECT * from teacher where id = #{t_id}
</select>

注意:子查询有一个好处就是可以设置关联对象的延迟加载,只有在使用到延迟对象时才会去执行对应的子查询 SQL 语句然后返回结果。

  • 需要开启 mybatis 的全局懒加载设置,<setting name="lazyLoadingEnabled" value="true"/>
  • association 有一个 fetchType 属性手动控制懒加载,值有 lazy(懒加载)、eager(立即加载),如果不设置这个属性默认是懒加载。

5.2、一对多关系映射处理

方式一:通过连接查询出老师对应的所有学生信息,然后通过 resultMap 进行关系映射。

<!-- 连接查询-->
<select id="getTeacherById" resultMap="TeacherMap">
    SELECT * FROM teacher t
    LEFT JOIN student s ON t.id = s.t_id
    WHERE t.id = #{id}
</select>

<resultMap id="TeacherMap" type="com.jx.app.mybatis.entity.Teacher">
    <id property="id" column="id"/>
    <result property="teacherName" column="teacher_name"/>
     <!-- 查询出来学生信息进行集合映射,ofType:集合泛型中的属性-->
    <collection property="students" ofType="com.jx.app.mybatis.entity.Student">
        <id property="id" column="s_id"/>
        <result property="studentName" column="student_name"/>
    </collection>
</resultMap>

方式二:分步查询老师信息和学生信息,然后通过 resultMap 映射关联。

<select id="getTeacherById" resultMap="TeacherMap">
    SELECT * FROM teacher t
    WHERE t.id = #{id}
</select>

<resultMap id="TeacherMap" type="com.jx.app.mybatis.entity.Teacher">
    <id property="id" column="id"/>
    <result property="teacherName" column="teacher_name"/>
    <!-- 查询出来学生信息进行集合映射,ofType:集合泛型中的属性-->
    <collection property="students" ofType="com.jx.app.mybatis.entity.Student"
            select="com.jx.app.mybatis.mapper.UserMapper.getStudent"
            column="id">
    </collection>
</resultMap>

<select id="getStudent" resultType="com.jx.app.mybatis.entity.Student">
    select * from student where t_id = #{tid}
</select> 

6、Mybatis 动态 SQL

​ 根根据特定的条件动态拼接 SQL 语句的功能,它就是解决在拼接 SQL 时字符串问题。

if 标签:会根据标签的 test 属性对应表达式返回 true 或者 false 决定是否拼接到 SQL 语句中。

// 使用 if 进行多条件查询
List<User> DynamicSQL(User user);
<select id="DynamicSQL" resultType="com.jx.app.mybatis.entity.User">
    select * from user 
    where 1=1
    <!-- 如果查询条件有 username 就会在 SQL 中进行拼接-->
    <if test="userName != null and userName != ''">
        and user_name = #{userName}
    </if>
    <if test="money != null and money != ''">
        and money = #{money}
    </if>
</select>

where 标签:动态生成 where 条件语句,根据拼接 SQL 在前面添加或去掉 and、or 关键字,如果没有条件就不会有 where 关键字。

<select id="DynamicSQL" resultType="com.jx.app.mybatis.entity.User">
    select * from user
    <!-- 会动态生成 where 关键字,并且去除或添加开头的 and、or 关键字-->
    <where>
        <!-- 如果查询条件有 username 就会在 SQL 中进行拼接-->
        <if test="userName != null and userName != ''">
            and user_name = #{userName}
        </if>
        <if test="money != null and money != ''">
            or money = #{money}
        </if>
    </where>
</select>

trim 标签:如果拼接 SQL 字符串有内容可以在内容前后添加内容,如果没有内容也没有任何效果。

<select id="DynamicSQL" resultType="com.jx.app.mybatis.entity.User">
    select * from user
    <!--
        prefix|suffix:在内容的前面|后面添加指定内容
        prefixOverrides|suffixOverrides:在内容的前面|后面去掉指定内容
    -->
    <trim prefix="where" suffix="" prefixOverrides="and|or" suffixOverrides="">
            <if test="userName != null and userName != ''">
                and user_name = #{userName}
            </if>
            <if test="money != null and money != ''">
                or money = #{money}
            </if>
    </trim>
</select>

chose…when…otherwise 标签:相当于 if…eles if…else,指定条件选择一个进行执行,其它内容不执行。

<select id="DynamicSQL" resultType="com.jx.app.mybatis.entity.User">
    select * from user
    <where>
        <!-- 只选择一个条件进行执行,如果 when 都不满足则执行 otherwise 中的内容-->
        <choose>
            <when test="userName != null and userName != ''">
                user_name = #{userName}
            </when>
            <when test="money != null and money != ''">
                money = #{money}
            </when>
            <otherwise>
                id = #{id}
            </otherwise>
        </choose>
    </where>
</select>

注意:这个条件选择执行只会满足一个,要么是 when 中的一个要么就是 otherwise。

foreach 标签:如果参数是集合类型,可以通过标签遍历集合中内容,例如进行批量删除、增加等操作。

// 批量删除
int deleteBatch(@Param("ids") List<String> ids);
<delete id="deleteBatch">
    delete from user
    <where>
        id in
        <!-- collection:操作的集合参数,item:遍历出来的每个元素,open:指定开始内容,
                 close:指定结束内容,index:遍历到的下标,separator:指定每个元素之间的分隔符
            -->
        <foreach collection="ids" item="id" close=")" open="(" separator="," index="i">
            #{id}
        </foreach>
    </where>
</delete>

sql 标签:对常用的 SQL 语句进行一个抽取,如果在其它地方使用直接引用。

<!-- id:唯一标识 sql 标签,在引用时通过 id 引入-->
<sql id="CommonSQL">
    id,user_name,password,money
</sql>

<!-- 通过 include 标签进行引入动态的 sql-->
<select id="selectAll" resultType="com.jx.app.mybatis.entity.User">
    select <include refid="CommonSQL"/> from user
</select>

7、Mybatis 缓存

一级缓存:这个级别缓存是 SqlSession 级别的缓存,通过同一个 SqlSession 对象去查询数据,那么在第二次查询就会去缓存中获取而不会去查询数据库,这种缓存是默认开启的。

@Test
public void test4(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper userMapper1 = sqlSession.getMapper(UserMapper.class);
    List<User> allUser1 = userMapper1.findAllUser();
    System.out.println(allUser1);

    // 即使是不同 mapper 对象,但是是同一个 sqlSession,那么第二次就会去缓存中取数据
    UserMapper userMapper2 = sqlSession.getMapper(UserMapper.class);
    List<User> allUser2 = userMapper2.findAllUser();
    System.out.println(allUser2);
}

一级缓存失效:

  • 使用不同的 SqlSession 进行查询数据。
  • 同一个 SqlSession 但是查询条件不同。
  • 同一个 SqlSession 的两次查询之间执行了其它的增、删、改等操作。
  • 同一个 SqlSession 的两次查询之间手动清空了缓存。
// 手动清空缓存
sqlSession.clearCache();

二级缓存:二级缓存是 SqlSessionFactory 级别的缓存,通过同一个 SqlSessionFactory 创建的 SqlSession 去查询结果会被缓存,那么第二次去执行相同查询就会去缓存中查询,二级缓存需要手动开启。

  • 需要在 mybatis 核心配置文件中开启缓存。
<settings>
    <!-- 开启全局缓存,默认是开启的-->
    <setting name="cacheEnabled" value="true"/>
</settings>
  • 在 mapper 映射文件中开启缓存。
<!-- 开启缓存-->
<cache />
@Test
public void test5(){
    SqlSession sqlSession1 = MybatisUtils.getSqlSession();
    SqlSession sqlSession2 = MybatisUtils.getSqlSession();

    UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
    List<User> users1 = mapper1.selectAll();
    System.out.println(users1);
    sqlSession1.commit();

    // 同一个 SqlSessionFactory 获取的不同 SqlSession 查询结果会被缓存
    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
    List<User> users2 = mapper2.selectAll();
    System.out.println(users2);
}

注意事项:

  • 必须是同一个 SqlSessionFactory 的 SqlSession 的二级缓存才会生效。
  • 只有每一个将 SqlSession 查询后提交或者关闭,数据才会被缓存。
  • 查询的结果对象必须实现序列化,不然使用缓存会报错。
  • 两次相同查询之间,执行了增、删、改操作,一级缓存、二级缓存都会失效。

image-20230624210726280

二级缓存相关设置:在 mapper 映射文件中的 cache 标签可以设置以下属性。

<!-- 相关设置:
           eviction(缓存回收策略)=LRU(最近最少使用,默认值) | FIFO(先进先出)
           flushInterval:缓存刷新时间,单位秒,不设置就是不刷新就只有执行增删改语句才会刷新
           size:缓存对象数目,防止内存溢出
           readOnly(是否只读)=true(缓存返回是同一个对象,且这个对象不能修改,修改会报错) 
                            false(返回的缓存中的一个拷贝对象,这个对象可以修改,默认值)
-->
<cache eviction="LRU" flushInterval="1000" size="10" readOnly="false"/>

Mybatis 缓存查询顺序:

  • 先查询二级缓存,二级缓存的范围比一级缓存大一些。
  • 如果二级缓存没有命中就回去查询一级缓存。
  • 如果一级缓存也没有命中,就会去查询数据库。
  • SqlSession 关闭后,会将一级缓存的数据写入二级缓存。

第三方缓存工具 EHCache:

  • 导入依赖:
<!-- ehcache和mybatis整合包-->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>
  • 编写 ehcache 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
        updateCheck="false">
    <!--
    diskStore:为缓存路径,ehcache分为内存和磁盘两级,
    此属性定义磁盘的缓存位 置。
    参数解释如下:
    user.home – 用户主目录
    user.dir – 用户当前工作目录
    java.io.tmpdir – 默认临时文件路径
    -->
    <diskStore path="E:\ehcache"/>
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="true"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>
    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
    <!--name:缓存名称。
    maxElementsInMemory:缓存最大数目
    maxElementsOnDisk:硬盘最大缓存个数。
    eternal:对象是否永久有效,一但设置了,timeout将不起作用。
    overflowToDisk:是否保存到磁盘,当系统当机时
    timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。 仅当 eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
    timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建 时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存 活时间无穷大。
    diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默 认是30MB。每个Cache都应该有自己的一个缓冲区。
    diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
    memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将 会根据指定的策略去清理内存。
    默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先 出)或是LFU(较少使用)。
    clearOnFlush:内存数量最大时是否清除。 memoryStoreEvictionPolicy:
    可选策略有:
    LRU(最近最少使用,默认策略)、
    FIFO(先进先出)、
    LFU(最少访问次数)。
    FIFO,first in first out,这个是大家最熟的,先进先出。
    LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以 来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。 L'
    RU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容 量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的 元素将被清出缓存。 -->
</ehcache>
  • 使用三方缓存工具:在 mapper 映射文件中修改。
<!-- type:指定缓存类型,不指定就是使用 mybatis 的缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

8、Mybatis 分页插件

导入依赖:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.3.3</version>
</dependency>

设置 mybatis 插件:

<plugins>
    <!-- 设置分页插件拦截器-->
    <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>

使用方式:

@Test
public void test6(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    // 开启分页,在下一个查询语句会进行分页拦截,参数一:页码,参数二:一页数量
    PageHelper.startPage(1,5);

    List<User> users2 = mapper.selectAll();
    
    // 参数是查询后的 list 结果
    PageInfo<User> pageInfo = new PageInfo<>(users2);

    System.out.println(pageInfo.getList());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/801744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前后端分离开发流程

1、介绍 在前后端分离开发中&#xff0c;前端负责用户界面和交互逻辑的实现&#xff0c;后端则处理业务逻辑和数据持久化。这种开发模式的优势在于前后端可以独立进行开发&#xff0c;提高了开发效率&#xff0c;并且使得前后端可以采用不同的技术栈来实现各自的功能。 2、开…

golang 中的 cronjob

引言 最近做了一个需求&#xff0c;是定时任务相关的。以前定时任务都是通过 linux crontab 去实现的&#xff0c;现在服务上云(k8s)了&#xff0c;尝试了 k8s 的 CronJob&#xff0c;由于公司提供的是界面化工具&#xff0c;使用、查看起来很不方便。于是有了本文&#xff0c…

【技术积累】Vue.js中的核心知识

Vue的生命周期 Vue中的生命周期是指组件从创建到销毁的整个过程中&#xff0c;会触发一系列的钩子函数 Vue2中的生命周期 Vue2中的生命周期钩子函数是在组件的不同阶段执行的特定函数。这些钩子函数允许开发者在组件的不同生命周期阶段执行自定义的逻辑。 Vue2中的生命周期钩…

【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境5

#尝试搭建K210的Micropython开发环境&#xff08;Win10&#xff09; #实验程序之三&#xff1a;更新频率演示 #尝试搭建K210的Micropython开发环境&#xff08;Win10&#xff09; #实验程序之三&#xff1a;更新频率演示from Maix import freqcpu_freq, kpu_freq freq.get() …

数学建模-蒙特卡洛模拟

%% 蒙特卡罗用于模拟三门问题 clear;clc %% &#xff08;1&#xff09;预备知识 % randi([a,b],m,n)函数可在指定区间[a,b]内随机取出大小为m*n的整数矩阵 randi([1,5],5,8) %在区间[1,5]内随机取出大小为5*8的整数矩阵 % 2 5 4 5 3 1 4 2 %…

市面上的ipad国产触控笔怎么样?精选的性价比电容笔

要知道&#xff0c;真正的苹果品牌的那款原装电容笔&#xff0c;光是一支电容笔就价格近千元。实际上&#xff0c;平替电容笔对没有太多预算的用户是个不错的选择。一支苹果品牌的电容笔&#xff0c;价格是平替品牌的四倍&#xff0c;但电容笔的书写效果&#xff0c;却丝毫不逊…

植物一区HR | 植物生理组+转录组:揭示豆科植物响应干旱胁迫机制

PlantArray 植物高通量生理学表型监测系统 是一套以植物生理学为基础的高精度&#xff0c;高通量&#xff0c;自动化表型监测系统&#xff0c;集合实验设置、数据分析、决策工具于一身&#xff0c;能够高通量实时动态监测并进行全天候生理及环境参数采集&#xff0c;是进行植物…

使用 element-resize-detector 插件实现左侧菜单展开收起时,Echarts图表自适应功能

问题&#xff1a; 在项目中开发 echarts 图表的时候遇到了一个问题&#xff0c;就是左侧菜单展开和收起的时候图表没办法自适应的改变宽度&#xff0c;导致图表不能完美展示。 方案&#xff1a; 使用 element-resize-detector 插件来实现菜单展开或收起时候的图表自适应更新…

2024届IC秋招兆易创新数字IC后端笔试面试题

数字IC后端实现PR阶段设计导入需要哪些文件&#xff1f; 设计导入需要的文件如下图所示。这个必须熟练掌握。只要做过后端训练营项目的&#xff0c;对这个肯定是比较熟悉的。大家还要知道每个input文件的作用是什么。 在吾爱IC后端训练营Cortexa7core项目中&#xff0c;你认为…

ECharts柱状图实现从y轴指定数渲染,而不是始终从y=0处渲染

咱们先看看对比图&#xff0c;下图是echarts统计图放入数据不做处理的结果&#xff08;只看蓝色柱子即可&#xff09;&#xff0c;可以看到柱状图不管数据时正数还是负数&#xff0c;都是以y0为图形的起点 下图是我想要实现的效果&#xff0c;相当于是以y轴最小值为起点渲染柱…

如何将数字高程模型加载到地图中查看,并进行在线编辑和分享?

四维轻云是一款地理空间数据在线管理平台&#xff0c;具有地理空间数据的在线管理、查看及分享等功能。在四维轻云平台中&#xff0c;用户可以将数据加载至地图中查看&#xff0c;并使用渲染、视图、标绘等工具。 现在&#xff0c;小编就来告诉大家如何将数字高程模型加载到地…

git从主仓库同步到fork仓库

git从主仓库同步到fork仓库 1. fork远程仓库到本地仓库2. 将远程仓库添加到本地3. 更新本地项目主库地址4. 将远程仓库更新到本地仓库5. 将本地仓库合到远程分支 1. fork远程仓库到本地仓库 方式一&#xff1a;通过git命令 git clone fork库地址方式二&#xff1a;通过git页面…

home-assistant整合sso

其他软件都可以通过nginx直接做代理添加鉴权&#xff0c;但是这个hass果然是用户安全隐私很强&#xff0c;做代理需要配置白名单&#xff0c;而且支持的三方鉴权都不太适合我的需求&#xff0c;非要改源码才行&#xff0c;后来我发现不用改源码的折中方式 参考文章 External …

移动端适配rem

1.安装amfe-flexible和postcss-pxtorem&#xff0c; npm install amfe-flexible --save npm install postcss-pxtorem5.1.1 (这里我使用的postcss-pxtorem是5.1.1版本)或者在pageage.json中写入 "amfe-flexible": "^2.2.1","postcss-pxtorem": …

QT 视图(view)模型(model)汇总

QStringListModel和QListView UI界面 widget头文件 #ifndef WIDGET_H #define WIDGET_H#include <QStringList> #include <QStringListModel> #include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : publi…

全面升级 | MoHub 2023b版本正式上线

为了满足装备数字化发展需求&#xff0c;为知识模型化与模型开放共享提供自主平台&#xff0c;同元软控于2023年初推出来工业知识模型互联服务平台MoHub。7月27日&#xff0c;工业知识模型互联平台MoHub 2023b如期升级上线。此次升级&#xff0c;面向平台用户重点在云化工具、知…

PDU+远控,企业如何应用工业级智能PDU远程赋能业务?

在很多企业级业务场景下&#xff0c;如何保障相关业务设备的稳定供电非常重要&#xff0c;插座也就成为了这些业务体系中的核心基建。 为了保证相关设备供电的稳定&#xff0c;并且实现高效的远程管理&#xff0c;很多企业级的业务场景会部署专业的智能PDU&#xff0c;而在众多…

医疗器械维修工程师心得

彩虹医械维修技能班9月将开展本年第三期长期班&#xff0c;目前咨询人员也陆续多了起来&#xff0c;很多刚了解到医疗行业的&#xff0c;自身也没有多少相关的基础&#xff0c;在咨询时会问到没有基础能否学的会&#xff1f; 做了这行业的都知道&#xff0c;无论多么复杂的设备…

探讨缓存一致性问题

探讨缓存一致性问题 本文只探讨只读缓存&#xff0c;即只对缓存进行读取、写入、删除&#xff0c;不进行更新操作 前言 数据库的读写性能上限是比较低的&#xff0c;工程中经常在数据库前面加一层缓存&#xff0c;可能是Redis或者本地缓存。既然有缓存&#xff0c;那么不可避免…

归并交换基数简单选择排序

文章目录 1 交换排序1.1 冒泡排序1.1.1 冒泡排序算法1.1.2 性能分析 1.2 快速排序1.2.1 快排的算法1.2.2 性能分析1.2.3 快排的特点 2 简单选择排序2.1 简单排序算法2.1.1 性能分析 2.2 堆排序2.2.1 堆的调整2.2.2 筛选过程算法2.2.3 堆的建立算法2.2.4 性能分析 3 归并排序3.1…