4.3 映射器(Mapper) sql、参数、resultMap、关联标签及延时加载详解

1.sql

这个标签元素可以被用来定义可重用的SQL代码段,可以包含在其他语句中。也可以被静态地(在加载参数)参数化。不同的属性值通过包含的实例变化。

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
<select id="selectUsers" resultType="map">
  select
    <include refid="userColumns"><property name="alias" value="t1"/></include>,
    <include refid="userColumns"><property name="alias" value="t2"/></include>
  from some_table t1
    cross join some_table t2
</select>

通过include关键字进行引用sql元素。

1.1 refid属性也可以使用属性值表示

<sql id="commonselect">
     select * from <include refid="${target}"/>
</sql>

<sql id="table">
    ${tablename}
</sql>

<select id="getStudents"  resultMap="AllColumnMap">
    <include refid="commonselect">
        <property name="target" value="table"/>
        <property name="tablename" value="student"/>
    </include>
</select>

2.参数(Parameters)

定制参数属性时候,MyBatis不支持换行。

2.1简单的参数值(int,long,float等)

<select id="selectUsers" resultType="User">
  select id, username, password
  from users
  where id = #{id}
</select>

2.2Java POJO作为参数值

<insert id="insertUser" parameterType="User">
  insert into users (id, username, password)
  values (#{id}, #{username}, #{password})
</insert>

User 类型的参数对象传递到了语句中,id、username 和 password 属性将会被查找,然后将它们的值传入预处理语句的参数中。

2.3参数配置

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

#{property,javaType=int,jdbcType=NUMERIC}

对于数值类型,还有一个小数保留位数的设置,来确定小数点后保留的位数。

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

2.4 特殊字符串替换和处理(#和$)

默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并安全地设置值(比如?)

这样做更安全,更迅速,通常也是首选做法,不过有时你只是想直接在 SQL语句中插入一个不改变的字符串。比如,像 ORDER BY,你可以这样来使用:

ORDER BY ${columnName}

这里 MyBatis 不会修改或转义字符串。

注意: 以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的,会导致潜在的SQL注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。

3.resultMap结果映射集

resultMap是MyBatis里面最复杂的元素。它的作用是定义映射规则级联更新定制类型转化器等。

3.1 resultMap元素的构成

resultMap是由很多子元素构成的。

<!ELEMENT resultMap (constructor?,id*,result*,association*,collection*, discriminator?)>
  • 1.constructor

用于配置构造方法。主要用于告知MyBatis在把数据库结果集转化成POJO对象时候,使用对应的构造方法。

主要属性

idArg:ID 参数;标记结果作为 ID 可以帮助提高整体效能

arg:注入到构造方法的一个普通结果

public class User {
    private int id;

    private String name;

    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
<resultMap id="userMapper" type="model.User">
        <constructor>
            <arg column="age" javaType="int"></arg>
            <arg column="name" javaType="string"></arg>
        </constructor>
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
    </resultMap>
  • 2.id

id元素是表示哪个列是主键,允许多个主键,多个主键则称为联合主键。实际项目中,最好避免使用联合主键。会导致项目变的复杂。

  • 3.result

result元素是配置POJO到SQL列名的映射关系。

id与result的元素属性如下:

property

数据库列映射到哪个字段或者属性上。如果数据库列名(column)与pojo的属性一致。就可以无须额外配置。

column

这里对应的时数据库里面定义的列名。

javaType

配置POJO的Java类型

jdbcType

配置数据库列类型

typeHandler

类型处理器。可以使用自定义的类型处理器。

  • 4.级联

级联中存在3种对应关系。

1.association(一对一关系) 2.collection(一对多关系) 3.discriminator(鉴别器)它可以根据实际选择采用哪个类作为实例。允许你根据特定的条件去关联不同的结果集。(在下面单独讲解)

3.2 使用map存储结果集(不推荐)

一般而言,任何select语句都可以使用map存储。

  • dao层定义
public interface IUserDao {
    Map<Integer,String> getUserByIdResultMap(int id);
}
  • mapper sql语句
<select id="getUserByIdResultMap" resultType="map">
    select age,name from user where id=#{id};
</select>
  • 输出结果
{name=jack, age=21}

3.3 使用POJO存储结果集(推荐)

使用map方式会降低可读性。POJO是最常用的方法。一方面可以使用自动映射,或者使用select 元素属性的resultMap配置映射集合。

<resultMap id="userResultMap" type="model.User">
    <id property="id" column="id"></id>
    <result property="name" column="name"></result>
    <result property="age" column="age"></result>
</resultMap>

<select id="getUserById" parameterType="model.User" resultMap="userResultMap">
    select * from user where id=#{id};
</select>

4.级联

4.1 association(一对一关系)

比如博客系统里面,博客空间站点与作者一对一映射关系。

4.2 collection (一对多的关系)

比如博客系统里面,一个博客站点可以对应多个博文。

4.3 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>

上面的示例就是value值不同,返回不是结果的列。

5.级联案例分析

让我们通过blog系统的来全面掌握上面三种关联关系。

  • 创建数据库
CREATE DATABASE IF NOT EXISTS cnblogs DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
  • 创建表
CREATE TABLE blog (
  blog_id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键',
  blog_title VARCHAR (50) DEFAULT '' COMMENT '博客空间名称',
  blog_author_id BIGINT not null default 0 comment '用户id'
) ENGINE = INNODB CHARSET utf8
CREATE TABLE author (
  author_id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键',
  author_username VARCHAR (50) DEFAULT '' COMMENT '用户名',
  author_password VARCHAR (50) DEFAULT '' COMMENT '密码',
  author_email VARCHAR (50) DEFAULT '' COMMENT '邮箱',
  author_bio VARCHAR (500) DEFAULT '个人简介'
) ENGINE = INNODB CHARSET utf8
  • java pojo
package com.cnblogs.model;

import org.apache.ibatis.type.Alias;

/**
 * 作者
 */
@Alias("author")
public class Author {
    /**
     * 自增主键
     */
    private long id;

    /**
     * 用户名
     */
    private String userName;

    /**
     * 密码
     */
    private String password;

    /**
     * 邮箱
     */
    private String email;

    /**
     * 个人简介
     */
    private String bio;

   //省略getter setter

    @Override
    public String toString() {
        return "Author{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                ", bio='" + bio + '\'' +
                '}';
    }
}

package com.cnblogs.model;

import org.apache.ibatis.type.Alias;

/**
 * 博客站点
 */
@Alias("blog")
public class Blog {
    /**
     * 自增主键
     */
    private long id;

    /**
     * 博客空间名称
     */
    private String title;

    /**
     * 用户id
     */
    private long authorId;

    private Author author;

   //省略getter setter

    @Override
    public String toString() {
        return "Blog{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", authorId=" + authorId +
                ", author=" + author +
                '}';
    }
}

  • 创建dao
package com.cnblogs.dao;

import com.cnblogs.model.Author;

public interface AuthorDao {
    Author selectAuthor(int id);

    int insert(Author author);
}
package com.cnblogs.dao;

import com.cnblogs.model.Blog;

public interface BlogDao {
    Blog selectBlog(int id);

    int insert(Blog author);
}

  • 创建mybatis全局配置文件
<?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">
<!--配置-->
<configuration>
    <!--属性-->
    <properties resource="properties/datasource.properties"/>
    <!--设置-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--类型命名-->
    <typeAliases>
        <package name="com.cnblogs.model"/>
    </typeAliases>
    <!--类型处理器-->
    <!--<typeHandlers></typeHandlers>-->
    <!--对象工厂-->
    <!--<objectFactory type=""/>-->
    <!--插件-->
    <!--<plugins>-->
    <!--<plugin interceptor=""></plugin>-->
    <!--</plugins>-->
    <!--配置环境-->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器-->
            <transactionManager type="jdbc"/>
            <!--数据源-->
            <dataSource type="pooled">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--数据库厂商标识-->
    <!--<databaseIdProvider type=""/>-->
    <!--映射器-->
    <mappers>
        <mapper resource="mapper/blogmapper.xml"></mapper>
        <mapper resource="mapper/authormapper.xml"></mapper>
    </mappers>
</configuration>
  • 创建datasource.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/cnblogs?serverTimezone=Asia/Shanghai&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
  • 创建mapper文件
<?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.cnblogs.dao.AuthorDao">
    <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>

    <select id="selectAuthor" resultMap="authorResult">
        select * from author where author_id=#{id};
    </select>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO author (
        author_username,
        author_password,
        author_email,
        author_bio
        )
        VALUES
        (
        #{userName},
        #{password},
        #{email},
        #{bio}
        );
    </insert>
</mapper>
<?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.cnblogs.dao.BlogDao">
    <resultMap id="blogResult" type="blog">
        <id property="id" column="blog_id"/>
        <result property="title" column="blog_title"/>
        <result property="authorId" column="blog_author_id"/>
        <association property="author" column="blog_author_id" javaType="author"
                     select="com.cnblogs.dao.AuthorDao.selectAuthor"/>
    </resultMap>

    <select id="selectBlog" resultMap="blogResult">
      select * from blog where blog_id=#{id};
    </select>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO blog (blog_title,blog_author_id) VALUES (#{title},#{authorId});
    </insert>
</mapper>
  • clinet测试
package com.cnblogs.client;

import com.cnblogs.dao.AuthorDao;
import com.cnblogs.dao.BlogDao;
import com.cnblogs.model.Author;
import com.cnblogs.model.Blog;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) {
        SqlSessionFactory factory = null;
        SqlSession sqlSession = null;
        try {
            factory = buildSqlSessionFactory();
            sqlSession = factory.openSession();
            AuthorDao authorDao = sqlSession.getMapper(AuthorDao.class);
            BlogDao blogDao=sqlSession.getMapper(BlogDao.class);
//            Author author = buildAuthor1();
//            authorDao.insert(author);

//            Blog blog=buildBlog();
//            blogDao.insert(blog);


            Blog blog=blogDao.selectBlog(1);
            System.out.printf(blog.toString());
            sqlSession.commit();
        } catch (Exception ex) {
            ex.printStackTrace();
            sqlSession.rollback();
        }
    }

    public static SqlSessionFactory buildSqlSessionFactory() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("config/mybatis-config.xml");
        return new SqlSessionFactoryBuilder().build(inputStream);
    }

    public static Author buildAuthor() {
        Author author = new Author();
        author.setUserName("风凌天下");
        author.setPassword("fltx123456");
        author.setEmail("fltx123456@qq.com");
        author.setBio("哥就是传说!");
        return author;
    }


    public static Author buildAuthor1() {
        Author author = new Author();
        author.setUserName("天蚕土豆");
        author.setPassword("tctd123456");
        author.setEmail("tctd123456@qq.com");
        author.setBio("我是异火之父!");
        return author;
    }

    public static Blog buildBlog(){
        Blog blog=new Blog();
        blog.setTitle("风凌天下的博客站点");
        blog.setAuthorId(1);
        return blog;
    }
}

  • 结果
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2eda0940]
==>  Preparing: select * from blog where blog_id=?; 
==> Parameters: 1(Integer)
<==    Columns: blog_id, blog_title, blog_author_id
<==        Row: 1, 风凌天下的博客站点, 1
====>  Preparing: select * from author where author_id=?; 
====> Parameters: 1(Long)
<====    Columns: author_id, author_username, author_password, author_email, author_bio
<====        Row: 1, 风凌天下, fltx123456, fltx123456@qq.com, 哥就是传说!
<====      Total: 1
<==      Total: 1
Blog{id=1, title='风凌天下的博客站点', authorId=0, author=Author{id=1, userName='风凌天下', password='fltx123456', email='fltx123456@qq.com', bio='哥就是传说!'}}

5.1 association分析

根据上面例子,我们在blog的pojo里面定义了author属性。那么我们在查询blog的时候如何带出author的属性值呢?

在mapper映射文件里面resultMap里面使用association子元素

<resultMap id="blogResult" type="blog">
    <id property="id" column="blog_id"/>
    <result property="title" column="blog_title"/>
    <result property="authorId" column="blog_author_id"/>
    <association property="author" column="blog_author_id" javaType="author"
                 select="com.cnblogs.dao.AuthorDao.selectAuthor"/>
</resultMap>

association的column代表的是blog表里面存放authorid的列名。property代表的时blog的定义的author属性,

5.2 collection讲解

一个博客站点可以写多篇博文。博客站点与文章的对应关系是一对多。

  • 创建数据库
CREATE TABLE post (
    post_id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键',
    post_blog_id BIGINT DEFAULT 0 COMMENT '博客站点id',
    post_subject VARCHAR(50) DEFAULT '' COMMENT '文章标题',
    post_body VARCHAR(50) DEFAULT '' COMMENT '文章内容'
)  ENGINE=INNODB CHARSET UTF8
  • pojo
@Alias("post")
public class Post {
    private long id;

    private long blogId;

    private String subject;

    private String body;

    //省略getter setter

    @Override
    public String toString() {
        return "Post{" +
                "id=" + id +
                ", bloId=" + blogId +
                ", subject='" + subject + '\'' +
                ", body='" + body + '\'' +
                '}';
    }
}
  • 创建dao
package com.cnblogs.dao;

import com.cnblogs.model.Post;


import java.util.List;

public interface PostDao {
    int insert(Post post);

    int batchInsert(List<Post> posts);

    List<Post> selectPosts(int postId);
}


  • 新建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" >
<mapper namespace="com.cnblogs.dao.PostDao">
    <resultMap id="postResult" type="post">
        <id property="id" column="post_id"></id>
        <result property="blogId" column="post_blog_id"></result>
        <result property="subject" column="post_subject"></result>
        <result property="body" column="post_body"></result>
    </resultMap>

    <select id="selectPosts" resultMap="postResult">
        select * from post where post_blog_id=#{postId};
    </select>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO `cnblogs`.`post`
        (
        `post_blog_id`,
        `post_subject`,
        `post_body`)
        VALUES
        (
        #{postId}
        #{subject},
        #{body});
    </insert>

    <insert id="batchInsert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO `cnblogs`.`post`
        (
        `post_blog_id`,
        `post_subject`,
        `post_body`)
        VALUES
        <foreach item="item" collection="list" separator=",">
            (#{item.blogId}, #{item.subject}, #{item.body})
        </foreach>
    </insert>
</mapper>
  • 插入数据
public static List<Post> buildPosts() {
    List<Post> posts = new ArrayList<>();
    Post post = new Post();
    post.setPostId(1);
    post.setSubject("异世邪君");
    post.setBody("世间毁誉,世人冷眼,与我何干,我自淡然一笑。。。");
    posts.add(post);

    Post post1 = new Post();
    post1.setPostId(1);
    post1.setSubject("我是至尊");
    post1.setBody("药不成丹只是毒,人不成神终成灰。。。");
    posts.add(post1);
    return posts;
}
public static void main(String[] args) {
    SqlSessionFactory factory = null;
    SqlSession sqlSession = null;
    try {
        factory = buildSqlSessionFactory();
        sqlSession = factory.openSession();
        AuthorDao authorDao = sqlSession.getMapper(AuthorDao.class);
        BlogDao blogDao = sqlSession.getMapper(BlogDao.class);
        PostDao postDao = sqlSession.getMapper(PostDao.class);
        List<Post> posts = buildPosts();
        postDao.batchInsert(posts);
        sqlSession.commit();
    } catch (Exception ex) {
        ex.printStackTrace();
        sqlSession.rollback();
    }
}

blog关联多篇post文章

  • blog pojo加入posts属性
@Alias("blog")
public class Blog {
    /**
     * 自增主键
     */
    private long id;

    /**
     * 博客空间名称
     */
    private String title;

    /**
     * 用户id
     */
    private long authorId;

    private Author author;

    private List<Post> posts;

    //省略getter setter
    @Override
    public String toString() {
        return "Blog{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", authorId=" + authorId +
                ", author=" + author +
                ", posts=" + posts +
                '}';
    }
}
  • 修改blogmapper.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.cnblogs.dao.BlogDao">
    <resultMap id="blogResult" type="blog">
        <id property="id" column="blog_id"/>
        <result property="title" column="blog_title"/>
        <result property="authorId" column="blog_author_id"/>
        <association property="author" column="blog_author_id" javaType="author"
                     select="com.cnblogs.dao.AuthorDao.selectAuthor" fetchType="lazy"/>

        <collection property="posts" column="blog_id" select="com.cnblogs.dao.PostDao.selectPosts"></collection>
    </resultMap>

    <select id="selectBlog" resultMap="blogResult">
      select * from blog where blog_id=#{id};
    </select>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO blog (blog_title,blog_author_id) VALUES (#{title},#{authorId});
    </insert>
</mapper>
  • 测试
public static void main(String[] args) {
        SqlSessionFactory factory = null;
        SqlSession sqlSession = null;
        try {
            factory = buildSqlSessionFactory();
            sqlSession = factory.openSession();
            AuthorDao authorDao = sqlSession.getMapper(AuthorDao.class);
            BlogDao blogDao = sqlSession.getMapper(BlogDao.class);
            PostDao postDao = sqlSession.getMapper(PostDao.class);
            Blog blog = blogDao.selectBlog(1);
            System.out.printf(blog.toString());
            sqlSession.commit();
        } catch (Exception ex) {
            ex.printStackTrace();
            sqlSession.rollback();
        }
    }
  • 结果
Created connection 1375995437.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5204062d]
==>  Preparing: select * from blog where blog_id=?; 
==> Parameters: 1(Integer)
<==    Columns: blog_id, blog_title, blog_author_id
<==        Row: 1, 风凌天下的博客站点, 1
====>  Preparing: select * from post where post_blog_id=?; 
====> Parameters: 1(Long)
<====    Columns: post_id, post_blog_id, post_subject, post_body
<====        Row: 1, 1, 异世邪君, 世间毁誉,世人冷眼,与我何干,我自淡然一笑。。。
<====        Row: 2, 1, 我是至尊, 药不成丹只是毒,人不成神终成灰。。。
<====      Total: 2
====>  Preparing: select * from author where author_id=?; 
====> Parameters: 1(Long)
<====    Columns: author_id, author_username, author_password, author_email, author_bio
<====        Row: 1, 风凌天下, fltx123456, fltx123456@qq.com, 哥就是传说!
<====      Total: 1
<==      Total: 1
Blog{id=1, title='风凌天下的博客站点', authorId=1, author=Author{id=1, userName='风凌天下', password='fltx123456', email='fltx123456@qq.com', bio='哥就是传说!'}, posts=[Post{id=1, bloId=1, subject='异世邪君', body='世间毁誉,世人冷眼,与我何干,我自淡然一笑。。。'}, Post{id=2, bloId=1, subject='我是至尊', body='药不成丹只是毒,人不成神终成灰。。。'}]}
Process finished with exit code 0

5.3 discriminator

在实际项目中,使用的比较少。因为这样的设计会导致系统会变的复杂。下面只是一个简答的示例。根据车辆类型编号返回不同类型的车辆特性。

<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>

6.延迟加载

有时候,我们一开始并不想取出级联的数据,如果需要时候,再取访问。

MyBatis的配置有两个全局参数lazyLoadingEnabled、aggressiveLazyLoading

或者在对应节点上加入fetchType属性。它有两个值 lazy\eager。

7.缓存

7.1 系统缓存(一级缓存和二级缓存)

MyBatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存(一级缓存只是相对于同一个Sqlsession而言)

但是如果使用不同的SqlSession对象因为不同的SqlSession都是相互隔离的,所以使用相同的Mapper、参数和方法,它还是会再次发送SQL到数据库执行,返回结果。

public static void main(String[] args) {
        SqlSessionFactory factory = null;
        SqlSession sqlSession = null;
        try {
            factory = buildSqlSessionFactory();
            sqlSession = factory.openSession();
            AuthorDao authorDao = sqlSession.getMapper(AuthorDao.class);
            BlogDao blogDao = sqlSession.getMapper(BlogDao.class);
            PostDao postDao = sqlSession.getMapper(PostDao.class);
            Blog blog = blogDao.selectBlog(1);
            Blog blog2 = blogDao.selectBlog(1);
            System.out.printf(blog.toString());
            sqlSession.commit();
        } catch (Exception ex) {
            ex.printStackTrace();
            sqlSession.rollback();
        }
    }

blog2在获取数据的时候,就没有查询数据库。

7.2开启二级缓存

SqlSessionFactory层面上二级缓存是不开启的,需要进行配置。只需要在mapper映射文件加上以下配置。并且所有的POJO需要实现Serializable接口

<cache/>

效果

  • 1.映射语句文件中的所有 select 语句将会被缓存。
  • 2.映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
  • 3.映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
  • 4.根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
  • 5.缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
  • 6.缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

eviction属性

  • LRU – 最近最少使用的:移除最长时间不被使用的对象。(默认)
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容