ICode9

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

《Mybatis框架》第2章 Mapper映射文件

2021-10-23 11:03:39  阅读:121  来源: 互联网

标签:语句 Mapper 缓存 name 映射 UserMapper Mybatis 属性


# 一、基础使用

1.mybatis-config.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.jianan.mapper.xxx">


</mapper>

2.顶级元素

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。

SQL 映射文件只有很少的几个顶级元素

  • cache – 该命名空间的缓存配置。
  • cache-ref – 引用其它命名空间的缓存配置。
  • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
  • sql – 可被其它语句引用的可重用语句块。
  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。

3.select

select 元素允许你配置很多属性来配置每条语句的行为细节。

<select
  id="selectPerson"
  parameterType="int"
  resultType="hashmap"
  resultMap="personResultMap"
  flushCache="false"
  useCache="true"
  timeout="10"
  fetchSize="256"
  statementType="PREPARED">
</select>
属性描述
id唯一标识符
parameterType参数的类全限定名或别名
resultType结果的类全限定名或别名
resultMap对外部 resultMap 的命名引用
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
fetchSize这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetTypeFORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。

4.insert, update 和 delete

1.基础使用

<insert
  id="insertAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  keyProperty=""
  keyColumn=""
  useGeneratedKeys=""
  timeout="20">

<update
  id="updateAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">

<delete
  id="deleteAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">
属性描述
id唯一标识符。
parameterType参数的类全限定名或别名
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys(仅适用于 insert 和 update)是否返回自动生成的主键,默认值:false。
keyProperty(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。
keyColumn(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。

2.返回生成主键

注意: 通过这种方式返回生成主键的时候,传递参数不能使用@Param注解

<insert id="add" parameterType="com.jianan.entity.User" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO `user`(`name`) VALUES(#{name})
</insert>

对于不支持自动生成主键列的数据库和可能不支持自动生成主键的 JDBC 驱动,MyBatis 有另外一种方法来生成主键。

<insert id="insertAuthor">
  <selectKey keyProperty="id" resultType="int" order="BEFORE">
    select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
  </selectKey>
  insert into Author
    (id, username, password, email,bio, favourite_section)
  values
    (#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR})
</insert>

在上面的示例中,首先会运行 selectKey 元素中的语句,并设置 Author 的 id,然后才会调用插入语句。

属性描述
keyPropertyselectKey 语句结果应该被设置到的目标属性。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyColumn返回结果集中生成列属性的列名。如果生成列不止一个,可以用逗号分隔多个属性名称。
resultType结果的类型。通常 MyBatis 可以推断出来,但是为了更加准确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果生成列不止一个,则可以使用包含期望属性的 Object 或 Map。
order可以设置为 BEFOREAFTER。如果设置为 BEFORE,那么它首先会生成主键,设置 keyProperty 再执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。
statementType和前面一样,MyBatis 支持 STATEMENTPREPAREDCALLABLE 类型的映射语句,分别代表 Statement, PreparedStatementCallableStatement 类型。

5.参数传递

1.单个参数

<insert id="insert" parameterType="com.jianan.entity.User">
    INSERT INTO `user`(`name`) VALUES(#{name})
</insert>

2.多个参数

会自动封装成Map传入,Map的key时param1,param2…

<insert id="add2" parameterType="com.jianan.entity.User">
    INSERT INTO `user`(`name`) VALUES(#{param1},#{param2})
</insert>

3.命名参数

通过@Param注解,并且设置参数名

// 传递POJO 在里面使用需要user.xxx这样来使用
// 传递普通类型 直接使用
int add(@Param("user") User user,@Param("age") Integer age);

4.POJO

// 我们直接传递POJO,在mapper文件里面直接使用字段
int add(User user);
<insert id="add" parameterType="com.jianan.entity.User">
    INSERT INTO `user`(`name`) VALUES(#{name})
</insert>

5.Map

可以封装多个参数为map,直接传递

int insert2(@Param("map")HashMap<String,String> map);

6.参数处理

参数也可以指定一个特殊的数据类型

#{age,javaType=string,jdbcType=int}

要更进一步地自定义类型处理方式,可以指定一个特殊的类型处理器类

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

对于数值类型,还可以设置 numericScale指定小数点后保留的位数

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

尽管上面这些选项很强大,但大多时候,你只须简单指定属性名,顶多要为可能为空的列指定 jdbcType,其他的事情交给 MyBatis 自己去推断就行了。

6.字符串替换 #{ } 和 ${ }

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数,这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。比如 ORDER BY 子句,这时候你可以:

ORDER BY ${columnname}

#{ } 和 ${ } 的区别

#{ } 获取参数的值,预编译到SQL中,安全。

${ } 获取参数的值,拼接到SQL中,有SQL注入问题

二、结果映射 resultMap

1.使用示例

<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
  <constructor>
    <idArg column="blog_id" javaType="int"/>
  </constructor>
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
    <result property="password" column="author_password"/>
    <result property="email" column="author_email"/>
    <result property="bio" column="author_bio"/>
    <result property="favouriteSection" column="author_favourite_section"/>
  </association>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <association property="author" javaType="Author"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <collection property="tags" ofType="Tag" >
      <id property="id" column="tag_id"/>
    </collection>
    <discriminator javaType="int" column="draft">
      <case value="1" resultType="DraftPost"/>
    </discriminator>
  </collection>
</resultMap>

2.概念试图(resultMap)

  • constructor - 用于在实例化类时,注入结果到构造方法中
    • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
    • arg - 将被注入到构造方法的一个普通结果
  • id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
  • result – 注入到字段或 JavaBean 属性的普通结果
  • association – 一个复杂类型的关联;许多结果将包装成这种类型
  • 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
  • collection – 一个复杂类型的集合
    • 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
  • discriminator – 使用结果值来决定使用哪个resultMap
    • case – 基于某些值的结果映射
      • 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射

3.ResultMap 的属性列表

属性描述
id唯一标识
type类的完全限定名或者别名

4.Id 和 Result 的属性

属性描述
property映射到列结果的字段或属性。如果 JavaBean 有这个名字的属性(property),会先使用该属性。
column数据库中的列名,或者是列的别名。
javaType一个 Java 类的全限定名或别名
jdbcTypeJDBC 类型
typeHandler类型处理器
select用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据,作为参数传递给此 select 语句。

5.构造方法

我们在获取结果的时候,默认会调用类的无参构造来创建对象,构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。

public class User {
   // 有参构造方法
   public User(Integer id, String username, int age) {
     //...
  }
}

设置使用的构造方法

<constructor>
   <idArg column="id" javaType="int" name="id" />
   <arg column="age" javaType="_int" name="age" />
   <arg column="username" javaType="String" name="username" />
</constructor>
属性描述
column数据库中的列名,或者是列的别名。
javaType一个 Java 类的完全限定名,或一个类型别名
jdbcTypeJDBC 类型
typeHandler类型处理器
select用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据,作为参数传递给此 select 语句。
resultMap结果映射的 ID
name构造方法形参的名字

6.一对一关联association

	// 方式一:直接配置映射的结果
	<resultMap id="parent" type="com.jianan.entity.Parent">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <association property="son" javaType="com.jianan.entity.Son">
            <id column="id" property="id" />
            <result column="name" property="name" />
        </association>
    </resultMap>
// 方式二:通过select调用单独的查询映射结果
<resultMap id="blogResult" type="Blog">
  // 通过单独的select查询对象
  // column可以作为参数传入,如果为多个,可以通过map封装
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" resultType="Author">
    SELECT * FROM AUTHOR WHERE ID = #{id}
</select>
// 方式三:单独配置一个resultMap来获取结果
<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  // 可以通过resultMap单独配置结果映射
  <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>

<resultMap id="authorResult" type="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
  <result property="password" column="author_password"/>
  <result property="email" column="author_email"/>
  <result property="bio" column="author_bio"/>
</resultMap>

属性列表

属性描述
property映射到列结果的字段或属性。
column用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据,作为参数传递给此 select 语句,可以为多个
javaType一个 Java 类的完全限定名,或一个类型别名
jdbcTypeJDBC 类型
typeHandler类型处理器
select用于加载复杂类型属性的映射语句的 ID
resultMap调用单独的映射集

7.一对多关联collection

    // 方式一:直接映射一对多结果
    <resultMap id="parent" type="com.jianan.entity.Parent">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <collection property="son" ofType="com.jianan.entity.Son" >
            <id column="id" property="id" />
            <result column="name" property="name" />
        </collection>
    </resultMap> 
// 方式二:调用单独的查询集
<resultMap id="blogResult" type="Blog">
  <collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectPostsForBlog" resultType="Post">
  SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
// 方式三:通过resultMap来单独映射结果
<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/>
</resultMap>

<resultMap id="blogPostResult" type="Post">
  <id property="id" column="id"/>
  <result property="subject" column="subject"/>
  <result property="body" column="body"/>
</resultMap>

8.鉴别器

一个数据库查询可能会返回多个不同的结果集, 鉴别器(discriminator)元素就是被设计来应对这种情况的,它很像 Java 语言中的 switch 语句。

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultMap="carResult"/>
    <case value="2" resultMap="truckResult"/>
    <case value="3" resultMap="vanResult"/>
    <case value="4" resultMap="suvResult"/>
  </discriminator>
</resultMap>

向上面部分我们需要定义多个resultMap,同时我们也可以使用简洁的映射风格,都代表相同的意义

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultType="carResult">
      <result property="doorCount" column="door_count" />
    </case>
    <case value="2" resultType="truckResult">
      <result property="boxSize" column="box_size" />
      <result property="extendedCab" column="extended_cab" />
    </case>
    <case value="3" resultType="vanResult">
      <result property="powerSlidingDoor" column="power_sliding_door" />
    </case>
    <case value="4" resultType="suvResult">
      <result property="allWheelDrive" column="all_wheel_drive" />
    </case>
  </discriminator>
</resultMap>

三、动态SQL

动态 SQL 是 MyBatis 的强大特性之一。

1.if

<if test="author != null and author.name != null and author.name != ''">
    AND author_name like #{author.name}
</if>

2.choose、when、otherwise

 <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>

3.where

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

4.set

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

5.trim

属性描述
prefix前缀
suffix后缀
prefixoverride删掉前缀内容
suffixoverride删掉后缀内容

通过trim来定制where功能

// 当标签内返回内容的时,添加where字段,并且删除设置的前缀
SELECT id,name FROM `user`
<trim prefix="WHERE" prefixOverrides="AND |OR">
   <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
</trim>

通过trim来定制set功能

// 当标签内返回内容的时候,添加set字段,并且删除设置的后缀
UPDATE `user` 
<trim prefix="SET" suffixOverrides=",">
  	<if test="username != null">username=#{username},</if>
     <if test="password != null">password=#{password},</if>
</trim>

6.foreach

 <foreach item="item" index="index" collection="list"  open="(" separator="," close=")">
        #{item}
  </foreach>

7.sql

<sql id="sqlid">
    SELECT * FROM ....
</sql>

<include refid="sqlid"/>

8.bind

bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:

<select id="selectBlogsLike" resultType="Blog">
  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>

9.OGNL 对象图导航语言

调用对象的属性person.name
调用方法person.getName()
调用静态属性/方法@java.util.UUID@randomUUID()
调用构造方法new com.jianan.entity.User().getName()
运算符+ - * / %
逻辑运算符in, not in, > >= < <= == !=

四、缓存

1.概述

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。缓存可以极大的提升查询效率,当开启了缓存以后,数据库的查询流程是二级缓存 --> 一级缓存 --> 数据库

Mybatis系统中默认定义了两级缓存

  1. 一级缓存:默认情况下,只有一级缓存开启
  2. 二级缓存:二级缓存需要手动开启和配置,他是基于namespace级别的缓存
  3. 为了提高扩展性,Mybatis定义了缓存接口cache,我们可以通过实现Cache接口来自定义二级缓存

2.一级缓存

1)基础

一级缓存为本地缓存,作用域默认为sqlSession,当Session flush或close后,该Session中的所有Cache将被清空

本地缓存不能关闭,但可以调用clearCache()来清空本地缓存,或者改变缓存的作用域

2)缓存测试

	// 创建session会话
    public SqlSession getSqlSession() {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            return factory.openSession();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Test
    public void m1() {
        // 创建SqlSerssion
        SqlSession sqlSession = getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 第一次查询
        List<User> list = userMapper.listAll("佳林");
        // 第二次查询
        List<User> list2 = userMapper.listAll("佳林");
        System.out.println(list);
        System.out.println(list2);
        MybatisTest.sqlSession.commit();
        MybatisTest.sqlSession.close();
    }

通过控制台查询日志,发现我查询了两次,但是第二次并没有查询日志,这代表使用了一级缓存

17:29:41.115 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6986852]
17:29:41.117 [main] DEBUG com.jianan.mapper.UserMapper.listAll - ==>  Preparing: SELECT id,name FROM `user` WHERE name LIKE CONCAT('%',?,'%') 
17:29:41.152 [main] DEBUG com.jianan.mapper.UserMapper.listAll - ==> Parameters: 佳林(String)
17:29:41.193 [main] DEBUG com.jianan.mapper.UserMapper.listAll - <==      Total: 2
[User{id=5, name='null'}, User{id=6, name='null'}]
[User{id=5, name='null'}, User{id=6, name='null'}]

3)缓存失效

  1. 不同的SqlSession对应不同的一级缓存
  2. 同一个SqlSession但是查询条件不同
  3. 同一个SqlSession两次查询期间执行了任何一次增删改操作
  4. 同一个SqlSession两次查询期间手动清空了缓存

4)缓存失效测试

    // 不同的SqlSession 会导致缓存失效
	@Test
    public void m2() {
        // 创建第一个SqlSession
        SqlSession sqlSession1 = getSqlSession();
        // 创建第二个SqlSession
        SqlSession sqlSession2 = getSqlSession();
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
        List<User> list1 = userMapper1.listAll("佳林");
        List<User> list2 = userMapper2.listAll("佳林");
        System.out.println(list1);
        System.out.println(list2);
    }
	// 查询条件不同
	@Test
    public void m3() {
        SqlSession sqlSession = getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = userMapper.listAll("佳林");
        List<User> list2 = userMapper.listAll("测试");
        System.out.println(list);
        System.out.println(list2);
        MybatisTest.sqlSession.commit();
        MybatisTest.sqlSession.close();
    }	
	// 中间执行了增删改操作 或者 手动清空缓存
	// 从日志可以看到查询了两次
    @Test
    public void m4() {
        SqlSession sqlSession = getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = userMapper.listAll("佳林");
        // 添加数据
        userMapper.add("添加数据");
        // 清空缓存
        // sqlSession.clearCache();
        List<User> list2 = userMapper.listAll("测试");
        System.out.println(list);
        System.out.println(list2);
        MybatisTest.sqlSession.commit();
        MybatisTest.sqlSession.close();
    }

3.二级缓存

1)基础

  • 二级缓存,全局作用域缓存
  • 二级缓存默认不开启,需要手动配置
  • Mybatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口
  • 二级缓存在SqlSession关闭或提交之后才会生效
  • 二级缓存是事务性的

2)使用步骤

  1. 全局配置文件中开启二级缓存

    // 默认开启的
    <setting name="cacheEnabled" value="true" />
    
  2. 注意:POJO需要实现Serializable接口

  3. 映射文件配置二级缓存

    <cache />
    

    通过这样一个简单的配置,这个简单语句的效果如下:

  • 映射语句文件中的所有select语句的结果将会被缓存
  • 映射语句文件中的所有insert、update和delete语句会刷新缓存
  • 缓存会使用最近最少使用算法(LRU)算法来清楚不需要的缓存
  • 缓存不会定时进行刷新
  • 缓存会保存列表或对象的1024个引用
  • 缓存会被是为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改

3)缓存测试

	public SqlSessionFactory getFactory(){
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            return factory;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Test
    public void m4(){
        // 通过方法获取到factory 注意这里需要获取到同一个工厂
        // 如果上面的方法返回的是SqlSession 那么会产生不同的工厂返回不同的会话
        SqlSessionFactory factory = getFactory();
        // 创建两个会话
        SqlSession sqlSession1 = factory.openSession(true);
        SqlSession sqlSession2 = factory.openSession(true);
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
	   // 第一次查询
        System.out.println(userMapper1.listAll("佳林"));
        // SqlSession关闭 存入二级缓存
        sqlSession1.close();
        // 第二次查询 从缓存中获取
        System.out.println(userMapper2.listAll("佳林"));
    }
// 日志
09:50:24.274 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Created connection 115433442.
09:50:24.276 [main] DEBUG com.jianan.mapper.UserMapper.listAll - ==>  Preparing: SELECT id,name FROM `user` WHERE name LIKE CONCAT('%',?,'%') 
09:50:24.325 [main] DEBUG com.jianan.mapper.UserMapper.listAll - ==> Parameters: 佳林(String)
09:50:24.347 [main] DEBUG com.jianan.mapper.UserMapper.listAll - <==      Total: 2
[User{id=5, name='null'}, User{id=6, name='null'}]
09:50:24.355 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6e15fe2]
09:50:24.355 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 115433442 to pool.
09:50:24.359 [main] DEBUG com.jianan.mapper.UserMapper - Cache Hit Ratio [com.jianan.mapper.UserMapper]: 0.5
[User{id=5, name='null'}, User{id=6, name='null'}]

4)cache标签

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

cache标签可以设置的属性为:

属性描述
eviction缓存回收策略,默认LRU,最近最少使用的被清除
flushInterval(刷新间隔),默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
size(引用数目)代表缓存最多可以存储多少个对象,太大容易导致内存溢出。默认值是 1024。
readOnly(只读)true:只读缓存;会给所有调用者返回缓存对象的相同实例。false:读写缓存;会返回缓存对象的拷贝。这会慢一些,但是安全,因此默认是 false。

5)设置总结

1.全局setting的cacheEnable 配置二级缓存的开关。一级缓存一直是打开的

2.select标签useCache标签,配置这个select是否使用二级缓存。一级缓存一直是使用的

<select id="listAll" resultType="com.jianan.springtest.entity.Car" useCache="true">
    SELECT * FROM `car`
</select>

3.sql标签的flushCache属性,增删改默认flushCache=true。sql执行后,会同时清空一级和二级缓存。查询默认的flushCache=false

<insert id="add" flushCache="true">

</insert>

4.sqlSession.clearCache()用来清除一级缓存

5.当在某一个作用域进行了C/U/D操作后,默认该作用域下所有select中的缓存将被clear

标签:语句,Mapper,缓存,name,映射,UserMapper,Mybatis,属性
来源: https://blog.csdn.net/weixin_44051038/article/details/120918280

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

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

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

ICode9版权所有