Mybatis学习笔记

文章目录

  • 前言
  • 1. Mybatis是什么?
  • 2. 第一个Mybatis程序
    • 2.1 搭建环境
    • 2.2 创建模块
    • 2.3 编写代码
    • 2.4 测试
    • 2.5 遇到的问题
      • 2.5.1 没有在核心配置文件中注册mappers
      • 2.5.2 没有配置静态资源过滤
  • 3. CRUD
    • 3.1 xxxMapper.xml中namespace
    • 3.2 select
      • 3.2.1 编写接口
      • 3.2.2 编写对应的mapper中的sql语句
      • 3.2.3 测试
    • 3.3 Insert
    • 3.4 update
    • 3.5 delete
  • 4. 万能Map
  • 5. 模糊查询
  • 6. mybatis配置
    • 6.1 核心配置文件
    • 6.2 环境配置
    • 6.3 属性
    • 3.4 别名
  • 7. 映射器
  • 8. 生命周期和作用域
  • 9. 解决属性名和字段名不一样的问题
  • 10. 日志
    • 10.1 日志工厂
    • 10.2 STDOUT_LOGGING标准日志输出
    • 10.3 LOG4J
      • 10.3.1 导入LOG4J的包
      • 10.3.2 log4j配置文件
      • 10.3.3 在mybatis-config.xml中配置
      • 10.3.4 log4j的使用
  • 11. 分页
    • 11.1 使用SQL的limit分页
    • 11.2 RowBounds分页
    • 11.3 分页插件
  • 12. 使用注解开发
    • 12. 注解的CRUD
    • 12.2 关于@Param()注解
    • 12.3 #{} ${}区别
  • 13. 使用Lombok开发
    • 13.1 idea安装Lombok
    • 13.2 在pom.xml中导入依赖
  • 14. 多对一处理
  • 15.一对多
      • 小结
  • 16. 动态SQL
    • 16.1 IF
    • 16.2 choose (when, otherwise)
    • 16.3 trim (where, set)
    • 16.4 SQL片段
      • 16.4.1 使用SQL标签抽取公共的部分
      • 16.4.2 在使用的地方用include
    • 16.5 foreach
  • 17. 缓存
    • 17.1.什么是缓存[ Cache ]?
    • 17.2.为什么使用缓存?
    • 17.3.什么样的数据能使用缓存?
    • 17.4 Mybatis缓存
      • 17.4.1 一级缓存
      • 17.4.2 缓存失效的情况
      • 17.4.3 二级缓存
    • 17.5自定义缓存

前言

mybatis的学习笔记,看的是狂神的视频
mybatis


1. Mybatis是什么?

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。mybatis是一个优秀的基于java的持久层框架,设计目的就是让我们对执行SQL语句时对输入输出的数据管理更加方便
不用Mybatis也可以,更容易上手,技术没有高低之分

2. 第一个Mybatis程序

程序结构如下:
Mybatis学习笔记_第1张图片

2.1 搭建环境

  • 在pom.xml中导入依赖
<dependencies>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.24version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.6version>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
    dependencies>

2.2 创建模块

  • 编写mybatis-config.xml

DOCTYPE configuration
       PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
   <properties resource="db.properties">
           <property name="username" value="root"/>
           <property name="password" value="123456"/>
           properties>
   <typeAliases>
       <typeAlias type="com.jinx.pojo.User" alias="User"/>
       <package name="com.jinx.pojo"/>
   typeAliases>
   <environments default="development">
       <environment id="development">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <property name="driver" value="${driver}"/>
               <property name="url" value="${url}"/>
               <property name="username" value="${username}"/>
               <property name="password" value="${password}"/>
           dataSource>
       environment>
       <environment id="test">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
               <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&userUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8"/>
               <property name="username" value="root"/>
               <property name="password" value="123456"/>
           dataSource>
       environment>
   environments>
   <mappers>
       
       
       <package name="com.jinx.dao"/>
   mappers>
configuration>

mysql8.0及以上的driver需要改为com.mysql.cj.jdbc.Driver
amp;为转义字符

  • 编写mybatis的工具类
package com.jinx.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
public class MybatisUtils {
   private static SqlSessionFactory sqlSessionFactory;
   static {
       try {
           //使用Mybatis第一步:获取sqlSessionFactory对象
           String resource = "mybatis-config.xml";
           InputStream inputStream = Resources.getResourceAsStream(resource);
           sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
   //SqlSession完全包含了面向数据库执行SQL命令所需的所有方法
   public static SqlSession getSqlSession() {
       return sqlSessionFactory.openSession();
   }
}

2.3 编写代码

-实体类User

package com.jinx.pojo;

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

    public User() {
    }

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

    public int getId() {
        return id;
    }

    public void setId(int 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 + '\'' +
                '}';
    }
}
  • Dao接口UserMapper
public interface UserDao {
   List<User> getUserList();
}
  • 接口实现类UserMapper.xml

DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jinx.dao.UserDao">
   
   <select id="getUserList" resultType="com.jinx.pojo.User">
       select * from mybatis.user;
   select>
mapper>

2.4 测试

package com.jinx.dao;

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

import java.util.HashMap;
import java.util.List;

public class UserDaoTest {
   @Test
   public void test() {
       //第一步获得SqlSession对象
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       //方式一:getMapper
//        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//        List userList = mapper.getUserList();
       //方式二:
        List<User> userList = sqlSession.selectList("com.jinx.dao.UserMapper.getUserList");
       for (User user : userList) {
           System.out.println(user);
       }
       sqlSession.close();
   }
}

方式一与方式二均可以查出结果
但是建议使用方法一
Mybatis学习笔记_第2张图片

2.5 遇到的问题

2.5.1 没有在核心配置文件中注册mappers

没有在核心配置文件中注册mappers报错

  • 解决方法:注册mappers
    <mappers>
        
        
        <package name="com.jinx.dao"/>
    mappers>

注册mappers的两种方式

  • 注册类
    • resource具体写到xxxMapper.xml并且使用的是/
    • class是到xxxMapper使用的是.
  • 扫描包
    • 会自动扫描所在包下的类

2.5.2 没有配置静态资源过滤

  • 解决方法:在pom.xml中配置
<build>
    <resources>
        <resource>
            <directory>src/main/javadirectory>
            <includes>
                <include>**/*.xmlinclude>
                <include>**/*.propertiesinclude>
            includes>
        resource>
        <resource>
            <directory>src/main/resourcesdirectory>
            <includes>
                <include>**/*.xmlinclude>
                <include>**/*.propertiesinclude>
            includes>
        resource>
    resources>
build>

3. CRUD

3.1 xxxMapper.xml中namespace

namespace要和Dao/mapper接口的类名一致,从而绑定

<mapper namespace="com.jinx.dao.UserMapper">

Mybatis学习笔记_第3张图片

3.2 select

  • id:就是对应的namespace中的方法名
  • resultType:Sql语句执行的返回值
  • paramterType:参数类型

3.2.1 编写接口

User getUserById(@Param("id")int id);

@Param(“id”) 里面的id对应着xxxMapper.xml中sql语句的#{id}

3.2.2 编写对应的mapper中的sql语句

<select id="getUserById" parameterType="int" resultType="com.jinx.pojo.User">
    select * from mybatis.user where id = #{id};
select>

3.2.3 测试

@Test
public void getUserByID() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.getUserById(1);
    System.out.println(user);
    sqlSession.close();
}

在这里插入图片描述

3.3 Insert

<insert id="addUser" parameterType="com.jinx.pojo.User">
        insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd});
insert>

3.4 update

<update id="updateUser" parameterType="com.jinx.pojo.User" >
        update mybatis.user set name = #{name},pwd = #{pwd} where id = #{id};
update>

3.5 delete

<delete id="deleteUser" parameterType="int" >
        delete from mybatis.user where id = #{id};
delete>

增删改需要提交事务

  • 方法一:在测试类中加一句sqlSession.commit();
  • 方法二:在工具类中将openSession的值设为true就会自动提交事务
public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(true);
    }

4. 万能Map

  • xxxMapper接口
int addUser2(Map<String, Object> map);
  • xxxMapper.xml
<insert id="addUser2" parameterType="map">
        insert into mybatis.user(id, name, pwd) values (#{userid},#{userName},#{passWord});
insert>

此处的#{userid},#{userName},#{passWord}可以随便起名

  • 测试类
 public void addUser2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("userid",5);
        map.put("userName",5);
        map.put("passWord",5);
        mapper.addUser2(map);
        sqlSession.commit();
        sqlSession.close();
    }

只要测试类中put到map集合中的键值对的键名对应即可

Mybatis学习笔记_第4张图片
Map传递参数,直接在sql中取出key即可!【parameterType=“map”】
对象传递参数,直接在sql中取对象的属性即可【parameterType=“Object”】
只有一个基本类型参数情况下,可以不写parameterType
多个参数用map,或者注解

5. 模糊查询

  • 方法一:在java代码中加
List<User> userList = mapper.getUserLike("%张%");
  • 方法二:在sql拼接中使用通配符!
select * from mybatis.user where name like "%"#{value}"%";

6. mybatis配置

6.1 核心配置文件

  • mybatis-config.xml
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

6.2 环境配置

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

尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
mybatis默认的事务管理器是JDBC(2个),连接池:POOLED(3个)

6.3 属性

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

  • 编写db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&userUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username=root
password=123456
  • 在mybatis-config.xml中这样配置环境
<properties resource="db.properties">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    properties>
<environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            dataSource>
        environment>
  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 同一个字段,优先使用db.properties

3.4 别名

  • 类型别名是为java类型设置一个短的名字
  • 存在的意义仅在于用来减少类完全限定名的冗余
    在mybatis-config.xml中加入
<typeAliases>
    <typeAlias type="com.jinx.pojo.User" alias="User"/>
typeAliases>
  • 也可以指定一个包名,Mybatis会在包名下面搜索需要的Java Bean。
  • 如果扫描实体类的包,它的默认别名就为这个类的类名,首字母小写(写大写也可以运行)
<typeAliases>
    <package name="com.jinx.pojo"/>
typeAliases>

实体类少用第一种
实体类多用第二种
第一种可以diy别名,第二种不行
也可以在实体类上增加注解

@Alias("hello")
public class User {}

优先级:类型别名>注解别名>包别名
Mybatis学习笔记_第5张图片

7. 映射器

  • 方式一
<mappers>
    <mapper resource="com/jinx/dao/UserMapper.xml"/>
mappers>
  • 方式二
<mappers>
    <mapper class="com.jinx.dao.UserMapper"/>
mappers>

注意点

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的Mapper配置文件必须在同一个包下
  • 方式三
<mappers>
    <package name="com.jinx.dao"/>
mappers>

8. 生命周期和作用域

SqlSessionFactoryBuilder

  • SqlSessionFactoryBuilder
  • 局部变量

SqlSessionFactory

  • 可以理解为连接池
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域。
  • 最简单的就是使用单例模式或者静态单例模式。

SqlSession

  • 连接到连接池的一个请求
  • 用完之后关闭,否则资源被占用
  • 所以它的最佳的作用域是请求或方法作用域。

9. 解决属性名和字段名不一样的问题

  • 数据库字段
    Mybatis学习笔记_第6张图片
  • 属性名
public class User {
    private int id;
    private String name;
    private String password;
}
  • xxxMapper
public interface UserMapper {
    User getUserById(@Param("id") int id);
}
  • 解决方法
  1. 起别名
 <select id="getUserById" parameterType="int" resultType="user">
        select id,name,pwd as password from mybatis.user where id = #{id};
    select>
  1. resultMap 结果集映射
<resultMap id="UserMap" type="user">
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
resultMap>
<select id="getUserById" parameterType="int" resultMap="UserMap">
        select * from mybatis.user where id = #{id};
select>
  • 说明:
    column:数据库字段
    property:实体类属性名

result元素是MyBatis中最重要最强大的元素
ResultMap的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了
ResultMap 的优秀之处——你完全可以不用显式地配置它们。

如果世界总是这么简单就好了

10. 日志

10.1 日志工厂

  • SLF4
  • LOG4J【掌握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING【掌握】
  • NO_LOGGING

10.2 STDOUT_LOGGING标准日志输出

  • 在mybatis-config.xml中配置

    

10.3 LOG4J

10.3.1 导入LOG4J的包


<dependency>
    <groupId>org.apache.logging.log4jgroupId>
    <artifactId>log4j-coreartifactId>
    <version>2.17.1version>
dependency>

10.3.2 log4j配置文件

新建一个log4j.properties放到resources目录下

log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/jinx.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

10.3.3 在mybatis-config.xml中配置

<settings>
    <setting name="logImpl" value="LOG4J"/>
settings>

10.3.4 log4j的使用

  1. 在要使用的类中导入包import org.apache.log4j.Logger;

  2. 日志对象,参数为当前类的class

static Logger logger = Logger.getLogger(UserDaoTest.class);
  1. 日志级别
logger.info("info进入了testLog4j");
logger.debug("debug进入了testLog4j");
logger.error("error进入了testLog4j");

11. 分页

  • 为什么要分页?减少数据的处理量

11.1 使用SQL的limit分页

  • xxxMapper
List<User> getUserLimit(Map<String, Object> map);
  • xxxMapper.xml
<select id="getUserLimit" parameterType="map" resultType="User">
        select * from mybatis.user limit #{startIndex},#{pageSize};
select>
  • 测试
public void getUserByLimit() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("startIndex",0);
    map.put("pageSize",2);
    List<User> userList = mapper.getUserLimit(map);
    for (User user : userList) {
        System.out.println(user);
    }
  sqlSession.close();
}

11.2 RowBounds分页

  • xxxMapper
List<User> getUserRowBounds();
  • xxxMapper.xml
<select id="getUserRowBounds" resultType="User">
        select * from mybatis.user ;
select>
  • 测试
public void getUserByRowBounds() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    RowBounds rowBounds = new RowBounds(1, 2);
    List<User> userList = sqlSession.selectList("com.jinx.dao.UserMapper.getUserRowBounds",null,rowBounds);
    for (User user : userList) {
        System.out.println(user);
    }
    sqlSession.close();
}

11.3 分页插件

分页插件PageHelper
Mybatis学习笔记_第7张图片

12. 使用注解开发

  • 注解在接口上实现
@Select("select * from user")
List<User> getUsers();
  • 在核心配置中绑定接口
<mappers>
    <mapper class="com.jinx.dao.UserMapper"/>
mappers>
  • 测试
public void test() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.getUsers();
    for (User user : userList) {
        System.out.println(user);
    }
    sqlSession.close();
}

12. 注解的CRUD

@Select("select * from user")
List<User> getUsers();

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

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

@Update("update user set name = #{name},pwd=#{password} where id =#{id}")
int updateUser(User user);

@Delete("delete from user where id =#{uid}")
int deleteUser(@Param("uid") int id);

12.2 关于@Param()注解

  • 基本类型的参数或者String类型参数,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,建议加上
  • 我们在SQL中引用的就是@Param()中设定的属性名

12.3 #{} ${}区别

#{}不会被注入,安全

13. 使用Lombok开发

13.1 idea安装Lombok

Mybatis学习笔记_第8张图片

13.2 在pom.xml中导入依赖


    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <version>1.18.22version>
    dependency>

常用的注解

@Data//无参构造
@AllArgsConstructor//有参构造
@EqualsAndHashCode
@NoArgsConstructor//无参构造
@ToString
@Getter

14. 多对一处理

多个学生对应一个老师

  • stuent实体类
@Data
public class Student {
    private int id;
    private String name;
    //学生需要关联一个老师
    private Teacher teacher;
}
  • teacher实体类
@Data
public class Teacher {
    private int id;
    private String name;
}
  1. 方法一:按照查询嵌套处理

<select id="getStudent" resultMap="StudentTeacher">
    select * from mybatis.student;
select>
    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    resultMap>
<select id="getTeacher" resultType="Teacher">
    select * from mybatis.teacher where id =#{tid}
select>
  1. 方法二:按照结果嵌套处理
<select id="getStudent2" resultMap="StudentTeacher2">
    select s.tid stid ,s.id sid,s.name sname,t.name tname from mybatis.student s,mybatis.teacher t where s.tid = t.id;
select>
    <resultMap id="StudentTeacher2" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>

        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
            <result property="id" column="stid"/>
        association>
    resultMap>
注意stid 在teacher

方法二中不查stid的话,老师的的id则为0
Mybatis学习笔记_第9张图片

15.一对多

一个老师对应多个学生

  • student实体类
@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
  • teacher实体类
@Data
public class Teacher {
    private int id;
    private String name;
    private List<Student> students;
}
  1. 方法一:按照结果嵌套处理
<select id="getTeacher" resultMap="TeacherStudent">
    select s.id sid, s.name sname, t.name tname, t.id tid
    from mybatis.student s,
         mybatis.teacher t
    where s.tid = t.id and t.id = #{tid}
select>
<resultMap id="TeacherStudent" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    collection>
resultMap>
  1. 方法二:按照查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from mybatis.teacher where id = #{tid};
select>
<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id">collection>
resultMap>
<select id="getStudentByTeacherId" resultType="Student">
    select * from mybatis.student where tid = #{tid};
select>

小结

1.关联-association【多对一】

2.集合-collection【一对多】

3.javaType & ofType

  • javaType 实体类属性类型

  • ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

注意点:

  • 标准SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一属性名和字段的问题
  • 可以使用日志,建议Log4j

16. 动态SQL

  • 什么是动态SQL
    动态SQL就是指根据不同的条件生成不同的SQL语句

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

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

16.1 IF

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

16.2 choose (when, otherwise)

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

16.3 trim (where, set)

<select id="queryBlogIF" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <if test="title != null">
            title =#{title}
        if>
        <if test="author != null">
            and author = #{author}
        if>
    where>
select>  
<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>

所谓的动态SQL本质还是SQL语句,只是我们可以在SQL层面执行一些逻辑代码

16.4 SQL片段

16.4.1 使用SQL标签抽取公共的部分

<sql id="if1">
    <if test="title != null">
        title =#{title}
    if>
    <if test="author != null">
        and author = #{author}
    if>
sql>

16.4.2 在使用的地方用include

<select id="queryBlogIF" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <include refid="if1">include>
    where>
select>

注意事项

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

16.5 foreach

Mybatis学习笔记_第10张图片

  • xxxMapper
List<Blog> queryBlogForeach(Map map);
  • xxxMapper.xml
<select id="queryBlogForeach" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <foreach collection="ids" item="id" open="and (" separator="or" close=")">
           id =  #{id}
        foreach>
    where>
select>
  • 测试
public void queryBlogForeach() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap<>();

    ArrayList<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(2);
  //用map往进传list
    map.put("ids",ids);
    List<Blog> blogs = mapper.queryBlogForeach(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

动态sql就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议:先写SQL,然后再对应的修改成为动态SQL

17. 缓存

17.1.什么是缓存[ Cache ]?

  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

17.2.为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率。

17.3.什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据。【可以使用缓存】

17.4 Mybatis缓存

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
  • MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
    默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)。二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
  • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

17.4.1 一级缓存

SqlSession

  • 与数据库同一次会话期间查询到的数据会被放在本地缓存中
  • 以后如果需要获取相同的数据,直接从缓存中拿,不用再去查询数据库
  1. 开启日志
  2. 测试在一个SqlSession查询两次相同记录
    Mybatis学习笔记_第11张图片

17.4.2 缓存失效的情况

  1. 查询不同的东西
  2. 增删改操作可能会改变原来的数据,所以必定会刷新缓存
  3. 查询不同的Mapper.xml
  4. 手动清理缓存
    Mybatis学习笔记_第12张图片
    小结:
  • 一级缓存默认开启,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间

  • 一级缓存相当于一个map

17.4.3 二级缓存

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

工作机制

  • 一个会话查询一条数据, 这个数据就会被放在当前会话的一-级缓存中;
  • 如果当前会话关闭了,这个会话对应的一级缓存就没了;
  • 但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;新的会话查询信息,就可以从二级缓存中获取内容;
  1. 开启全局缓存
    显式开启全局缓存在config.xml
<setting name="cacheEnabled" value="true"/>
  1. 在要使用二级缓存的Mapper中开启
    在这里插入图片描述
    或者
<cache eviction="FIFO"
       flushInterval="60000"
       size="512"
       readOnly="true">
cache>

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓存中
  • 用户查询数据,先从二级缓存找,然后一级缓存,然后数据库
  • 数据先放到一级缓存中,再放到二级缓存中

17.5自定义缓存

  1. 在pom.xml中导入依赖

<dependency>
    <groupId>org.mybatis.cachesgroupId>
    <artifactId>mybatis-ehcacheartifactId>
    <version>1.2.1version>
dependency>
  1. 在mybatis-config.xml中配置
<cache type="org.mybatis.caches.ehcache.EhcacheCache">cache>
  1. ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="./tmpdir/Tmp_EhCache"/>
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            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"/>
ehcache>

君子慎独,不欺暗室,含章可贞,卑以自牧

你可能感兴趣的:(java)