Mybatis配置及使用

目录

一、初步配置Mybatis及一个简单测试

1、利用Maven引入依赖

2、配置Mybatis的xml文件

3、获取SqlSession的实例

4、建立对象类进行测试

二、CRUD操作

1、插入

 2、步骤总结

3、Map和模糊查询拓展

三、配置解析

1、核心配置文件

 2、环境配置(environments)

3、属性(properties)

 4、类型别名(typeAliases)

 5、 映射器(mappers)

四、解决属性名和字段名不一致的问题

五、日志 

1、log4j

2、使用

 六、分页

七、使用注解开发

1、查询

2、添加

八、Lombok

九、多对一的处理

1、按照查询嵌套处理

2、按照结果嵌套处理

 十、一对多处理

1、按照查询嵌套处理

 2、按照结果嵌套处理【推荐】

 小结

十一、动态SQL

建立环境

 1、IF

2、choose

3、trim、where、set 

4、SQL片段

5、forEach 

十二、缓存

1、一级缓存

1、二级缓存


一、初步配置Mybatis及一个简单测试


Mybatis是应用在持久层的框架,大大简化jdbc的代码操作,隐藏了大量的细节

1、利用Maven引入依赖

  • mysql依赖

  • mybatis依赖

2、配置Mybatis的xml文件

如果是maven工程,在resource文件夹中创建一个mybatis的xml配置文件

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心配置文件-->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=UTC&amp;rewriteBatchedStatements=true"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>

</configuration>

*核心内容是数据库的四个属性值 

3、获取SqlSession的实例

  • Mybatis框架提供了一个SqlSessionFactory接口,它的一个实现类SqlSession中有对数据库的增删改查等操作,以下建立一个工具类作为获取实例的类
package com.kuang.utils;

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;

//sqlSessionFactory -->sqlSession
public class MybatisUtils {
    private static  SqlSessionFactory sqlSessionFactory;

    static {
        //使用Mybatis第一步:获取sqlSessionFactory对象
        String resource = "mybatis-config.xml";
        try {
            InputStream is = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句*/
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
        }

}

4、建立对象类进行测试

  • 以下为建立的User类,用于下一步测试 
package com.kuang.pojo;

public class User {
    private Integer id;
    private String name;
    private String pwd;

    public User(Integer id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public User() {
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
  •  写一个持久层的接口
  • package com.kuang.dao;
    
    import com.kuang.pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
        List<User> getUserList();
    }
    

    注意:传统代码式jdbc操作中,需要创建一个UserMapper的实现类,在实现类中实现上代码段中的getUserList()方法,而在Mybatis中,使用一个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绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.kuang.dao.UserMapper">
<!--    查询语句-->
    <select id="getUserList" resultType="com.kuang.pojo.User">
        select * from user;
    </select>
</mapper>

此文件也需要在Mybatis的配置文件中配置,配置格式见本文第一张图片的<mappers>标签

最后,编写测试类

package com.kuang.dao;

import com.kuang.pojo.User;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserMapperTest {
    @Test
    public void test(){
        //获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //方式一:执行SQL
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user :
                userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

结果如下:

User{id=1, name='狂神', pwd='123456'}
User{id=2, name='张三', pwd='123456'}
User{id=3, name='李四', pwd='123456'}

如有疑问详情访问Mybatis的官方中文文档:

mybatis – MyBatis 3 | 简介

二、CRUD操作

1、插入

//插入一个用户
int addUser(User user);

UserMapper.xml文件中配置如下 

@Test
    public void testAddUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int reuslt = mapper.addUser(new User(null, "韩阳", "1999225a"));
        System.out.println("影响了:"+reuslt+"条语句.");
        sqlSession.commit();
        sqlSession.close();
    }

 2、步骤总结

  1. 编写接口
  2. 在对应xml文件中编写sql
  3. 测试

注意:

  • 插入操作时,应加入一条语句对事务进行提交,否则,插入不会生效
  • sqlSessoin.commit(); 
  • #{id} 中的id字段,为pojo包中User类属性

3、Map和模糊查询拓展

假设我们的实体类或者数据库中的表,字段过多,应当考虑使用Map

  1. 编写接口
//万能Map
int addUserByMap(Map<String,Object> map);

2、编写xml

<insert id="addUserByMap" parameterType="Map">
    insert into user values (#{id},#{username},#{password});
</insert>

3、编写测试

@Test
    public void testAddUserByMap(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String,Object> map = new HashMap<>();
        map.put("id",null);
        map.put("username","李勇");
        map.put("password","123789a");
        int i = mapper.addUserByMap(map);
        if (i>0){
            System.out.println("插入成功");
        }
        sqlSession.commit();
        sqlSession.close();
    }

Map传递参数,直接在sql中取key即可

parameterType="Map"

对象传递参数,直接在sql中取对象属性

parameterType="Object"

只有一个基本类型参数的情况下,可以直接在sql中取到 

多个参数用Map或者注解

三、配置解析

1、核心配置文件

  • mybatis-config.xml
  • Mybatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息

 2、环境配置(environments)

MyBatis可以配置成适应多种环境

但是每个SqSessionFactory实例只能选择一个环境

Mybatis默认的事务管理器是JDBC,连接池:POOL

3、属性(properties)

我们可以通过该properties属性实现引用配置文件        

这些属性都是可外部配置且可动态替换的,既可以在典型的java属性配置文件配置,亦可以通过properties元素的子元素来传递

在xml中,约定properties必须放在第一个

1、创建jdbc.properties

username=root
password=root
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=truez

在核心配置文件中引入

<properties resource="jdbc.properties"/>

 4、类型别名(typeAliases)

<!--    给实体类起别名-->
    <typeAliases>
        <typeAlias type="com.kuang.pojo.User" alias="User"/>
    </typeAliases>
<!--    查询语句-->
    <select id="getUserList" resultType="User">
        select * from mybatis.user;
    </select>

 也可以指定一个包名,Mybatis会在包名下面搜索需要的JavaBean,比如:扫描实体类的包,它的默认别名就为这个类的类名首字母小写。

<!--    给实体类起别名-->
    <typeAliases>
        <package name="com.kuang.pojo"/>
    </typeAliases>
<!--    查询语句-->
    <select id="getUserList" resultType="user">
        select * from mybatis.user;
    </select>

 在扫描包的情况下,也可以用注解@Alias起别名

总结:

        如果用  typeAlias标签给一个类起别名,而不指定alias="xx"属性时,以及用包来指定别名时,别名都是不区分大小写的类名

 5、 映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件

方式一:【推荐】

<!--    每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>

 方式二:使用class文件绑定注册

<!--    每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com.kuang.dao.UserMapper"/>
    </mappers>

 注意:

  • 接口和它的mapper配置文件必须同名
  • 接口和它的配置文件必须在同一包下

方式三:使用扫描包进行注入绑定

<!--    每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
    <mappers>
<!--        <mapper resource="com/kuang/dao/UserMapper.xml"/>-->
        <package name="com.kuang.dao"/>
    </mappers>

注意:

  • 接口和它的mapper配置文件必须同名
  • 接口和它的配置文件必须在同一包下

四、解决属性名和字段名不一致的问题

数据库中的字段

 测试

public class User {
    private Integer id;
    private String name;
    private String password;
<!--    查询语句-->
    <select id="getUserById" resultType="user" parameterType="int">
        select * from user where `id`=#{id};
    </select>
public class UserMapperTest {
    @Test
    public void test(){
        //获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //方式一:执行SQL
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
    }

}

查询结果:

 

查出password为空

解决方案 

  • 在sql中给字段起别名,达到名称效果一致
<!--    查询语句-->
    <select id="getUserById" resultType="user" parameterType="int">
        select id,name,pwd password from user where `id`=#{id};
    </select>

  • resultMap(结果集映射)

在对象类的xml中创建结果集映射

<resultMap id="UserMap" type="User">
        <result column="username" property="username"/>
        <result column="id" property="id"/>
        <result column="pwd" property="password"/>
    </resultMap>
<!--    查询语句-->
    <select id="getUserById" resultMap="UserMap" parameterType="int">
        select * from user where `id`=#{id};
    </select>

resultMap是Mybatis中最重要最强大的元素

resultMap的设计思想是:对于简单的语句根本不需要配置显示的结果映射,而对于复杂一点的语句只要描述它们的关系就行了

五、日志 

1、log4j

  • log4j是一个apche的开源项目,可以控制日志信息的输送目的地是控制台、文件GUI组件
  • 可以控制日志的输出格式
  • 通过定义每条日志信息的级别,我们能更细致地控制日志的生成过程
  • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码

2、使用

  1. 先导入log4j的依赖
  2. 设置log4j为日志的实现
    <settings>
<!--        标准日志工厂-->
<!--        <setting name="logImpl" value="STDOUT_LOGGING"/>-->
<!--        log4j-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

 六、分页

  1. 接口
     List<User> getUserByLimit(Map<String,Integer> map);

  2. UserMapper.xml

        <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
            select * from user limit #{startIndex},#{pageSize};
        </select>

  3. 测试
        @Test
        public void testGetUserByLimit(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            Map<String,Integer> map = new HashMap<>();
            map.put("startIndex",0);
            map.put("pageSize",3);
            List<User> userByLimit = mapper.getUserByLimit(map);
            for (User user : userByLimit) {
                System.out.println(user);
            }
        }

    七、使用注解开发

1、查询

1、注解在接口上实现

public interface UserMapper {
    @Select("select * from user")
    List<User> getUsers();
}

2、需要在核心配置文件中绑定接口(仅绑定一次)

    <mappers>
        <mapper class="com.kuang.dao.UserMapper"/>
    </mappers>

3、测试

    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
    }

本质:反射机制

底层:动态代理

当方法中有多个参数时,用注解@Param来标注对应参数

    @Select("select * from user where id=#{id}")
    User getUserById(@Param("id")int id);

2、添加

1、在接口上添加注解

    @Insert("insert into user values(null,#{name},#{password})")
    int addUser(User user);

 2、测试

    @Test
    public void testAddUser(){
        int i = MybatisUtils.getSqlSession().getMapper(UserMapper.class).addUser(new User(null, "盲僧", "mangseng666"));
        if (i>0){
            System.out.println("添加成功!!!");
        }
    }

修改、 删除同理

关于@Param注解

  • 基本类型参数或者String类型 需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型,可以忽略
  • 我们在SQL中引用的就是我们在注解中设置的属性名

关于#{}和${}

  • #{}       用来传入参数时,sql解析时会加上" ",能够很大程度上防止sql注入
  • ${}       是直接显示在生成的sql中,无法防止sql注入
  • 能用#{}尽量用

八、Lombok

*java插件

安装步骤:

*在idea中选择settings--->Plugins--->搜索lombok安装即可

*在项目中导入lombok的依赖

*功能:利用注解自动生成get,set,hashcode,equals,构造器等

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data   生成get,set,hashcode,equals,toString,无参构造【常用】
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
@ExtensionMethod (Experimental, activate manually in plugin settings)
Lombok config system
Code inspections
Refactoring actions (lombok and delombok)

九、多对一的处理

创建一个多对一的模型

CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师'); 

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 

INSERT INTO `student` (`id`, `name`, `tid`) VALUES (1, '小明', 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, '小红', 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, '小张', 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, '小李', 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, '小王', 1);

1、按照查询嵌套处理

实体类如下:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias(value = "tea")
public class Teacher {
    private int id;
    private String name;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias(value = "stu")
public class Student {
    private int id;
    private String name;

    //学生需要关联一个老师
    private Teacher teacher;

}

需求:

public interface StudentMapper {
    //查询所有学生信息及对应老师
    public List<Student> getStu();
}

查询方式如下: 

<!--
    思路:
    1、查询所有学生信息
    2、根据查询出来的学生tid,查找对应老师
-->
    <select id="getStu" resultMap="StuTea">
        SELECT * FROM student;
    </select>

    <resultMap id="StuTea" type="stu">
<!--        复杂的属性,要单独处理 对象:association  集合:collection-->
        <association property="teacher" column="tid" javaType="tea" select="getTeacher"/>
    </resultMap>

    <select id="getTeacher" resultType="tea">
        select * from teacher where id = #{id};
    </select>

2、按照结果嵌套处理

<!--    按照结果嵌套处理-->
    <select id="getStu2" resultMap="StuTea2">
        SELECT s.id sid,s.name sname,t.name tname FROM student s,teacher t WHERE s.tid=t.id;
    </select>
    
    <resultMap id="StuTea2" type="stu">
        <result column="sid" property="id"/>
        <result column="sname" property="name"/>
        <association property="teacher" javaType="tea">
            <result property="name" column="tname"/>
        </association>
    </resultMap>

 两种方式查询结果一样

 十、一对多处理

一个老师拥有多个学生,对老师而言,就是一对多的关系

 实体类如下:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias(value = "stu")
public class Student {
    private int id;
    private String name;
    private int tid;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias(value = "tea")
public class Teacher {
    private int id;
    private String name;

    //一个老师有多个学生
    private List<Student> students;
}

1、按照查询嵌套处理

实体类如下:

    //获取指定老师下所有学生和老师信息
    Teacher getTeachers(@Param("tid") int id);

<!--    子查询-->
    <select id="getTeachers2" resultMap="TeaStu">
        select * from teacher where id=#{tid};
    </select>
    
    <resultMap id="TeaStu" type="tea">
        <collection property="students" javaType="ArrayList" ofType="stu" select="getStusByTeacherId" column="id"/>
    </resultMap>

    <select id="getStusByTeacherId" resultType="stu">
        select * from student where tid=#{tid};
    </select>

 2、按照结果嵌套处理【推荐】


    Teacher getTeachers2(@Param("tid") int id);
<!--    按结果嵌套查询-->
    <select id="getTeachers" resultMap="StuTea">
        select s.id sid,s.name sname,t.name tname,t.id
        tid from student s,teacher t
        where s.tid=t.id and t.id=#{tid};
    </select>

    <resultMap id="StuTea" type="tea">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
<!--        复杂的属性,我们需要单独处理,对象:association  集合:collection
            javaType 指定属性的类型
            集合中的泛型,我们使用ofType获取
-->
        <collection property="students" ofType="stu">
            <result property="name" column="sname"/>
            <result property="id" column="sid"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

 小结

1、关联 association 【多对一】

2、集合 collection    【一对多】

3、javaType  指定实体类属性的类型

4、ofType       指定映射到集合中的泛型约束类型

十一、动态SQL

动态sql就是根据不同的条件生成不同的SQL语句

利用动态SQL这一特性可以彻底摆脱这种痛苦

        如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

建立环境

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8

编写实体类如下

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Blog {
    private String name;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

 配置核心配置文件,设置为可以将经典sql和java驼峰命名字段的自动映射

    <settings>
<!--        标准日志工厂-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

 1、IF

    <select id="queryBlogIf" parameterType="map" resultType="blog">
        select * from blog where 1=1
        <if test="title != null">
            and title=#{title}
        </if>
        <if test="author != null">
            and author=#{author}
        </if>
    </select>

2、choose

    <select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <choose>
                <when test="title != null">
                    title=#{title}
                </when>
                <when test="author != null">
                    and author=#{author}
                </when>
                <otherwise>
                    and views=#{views}
                </otherwise>
            </choose>
        </where>
    </select>

原理与java中的switch-case相似,搭配where标签使用 

3、trim、where、set 

where标签可以去掉sql拼接时第一个多余的and

    <select id="queryBlogIf" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <if test="title != null">
                and title=#{title}
            </if>
            <if test="author != null">
                and author=#{author}
            </if>
        </where>
    </select>

 set标签去掉多余逗号

    <update id="updateBlog" parameterType="map">
        update blog
        <set>
            <if test="title != null">
                title=#{title},
            </if>
            <if test="author != null">
                author=#{author}
            </if>
        </set>
        where id =#{id}
    </update>

如果 where 元素和set元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
 ... 
</trim>
<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

4、SQL片段

 有些时候,抽取相同的sql代码段进行复用,会用到以下操作抽取:

    <!--抽取公共部分-->
    <sql id="if-if">
        <if test="title != null">
            and title=#{title}
        </if>
        <if test="author != null">
            and author=#{author}
        </if>
    </sql>

    <!--在需要的地方用include标签引用即可-->
    <select id="queryBlogIf" parameterType="map" resultType="blog">
        select * from blog
        <where>
           <include refid="if-if"></include>
        </where>
    </select>

类似于静态包含 

注意:

  • 最好基于单表定义SQL片段
  • 不要存在where标签

5、forEach 

    <select id="queryBlogForEach" parameterType="map" resultType="blog">
        select * from blog
#         我们传递一个万能的map,map中可以存在一个集合
        <where>
            <foreach collection="ids" item="id" open="(" separator="or" close=")">
                id=#{id}
            </foreach>
        </where>

    </select>

测试代码: 

 @Test
    public void testQueryBlogForEach(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        ArrayList<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        ids.add(4);
        hashMap.put("ids",ids);
        List<Blog> blogs = mapper.queryBlogForEach(hashMap);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }

十二、缓存

1、一级缓存

Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

缓存失效的情况:

1、查询不同的东西

2、增删改操作,可能会改变原来的数据,缓存必定刷新

    @Test
    public void testQueryUserById(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        mapper.updateUser(new User(1,"地龙人","555"));
        System.out.println("**********************************");
        User user1 = mapper.queryUserById(1);
        System.out.println(user1);
        System.out.println(user==user1);

    }

3、查询不同的Mapper.xml

4、手动清理缓存

    @Test
    public void testQueryUserById(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
//        mapper.updateUser(new User(1,"地龙人","555"));
        sqlSession.clearCache();
        System.out.println("**********************************");
        User user1 = mapper.queryUserById(1);
        System.out.println(user1);
        System.out.println(user==user1);

    }

小结:一级缓存默认是开启的,只在一段sqlSession中有效,也就是拿到连接到关闭连接这段时间

1、二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用于太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间对应一个二级缓存
  • 工作机制

*一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中

*如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中

*新的会话查询信息,就可以从二级缓存中获取内容

*不同的mapper查出的数据会放在自己对应的缓存(map)中

要启用全局二级缓存

步骤一

  • 开启全局缓存
<!--        开启全局缓存,默认为true,这里显式声明-->
        <setting name="cacheEnable" value="true"/>
  • 需要在SQL映射文件中添加一行:

<cache/ readOnly="true">

*关于readOnly属性

官方解释:

readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。速度上会慢一些,但是更安全,因此默认值是 false。
 

测试:

    @Test
    public void testQueryUserById2(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        SqlSession sqlSession1 = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);

        User user = mapper.queryUserById(1);
        sqlSession.close();
        User user1 = mapper1.queryUserById(1);
        sqlSession1.close();

        System.out.println(user);
        System.out.println(user1);
        System.out.println(user == user1);

    }

结果:

 

 问题:

我们需要将实体类序列化,否则就会报错,对应上文readOnly属性参数

小结:

  • 只要开启了二级缓存,在同一个mapper下有效
  • 所有数据都会先放在一级缓存中
  • 只有当会话提交,或者关闭,才会提交到二级缓存中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值