Mybatis深入学习(一)

Mybatis深入学习

java日志处理框架

对于一个应用程序来说日志记录是必不可少的一部分。线上问题追踪,错误排查,基于 日志的业务逻辑统计分析等都离不日志。

Log4j 简介

Log For Java(Java 的日志) 是 Apache 提供的一个开源的 Java 主流的日志框架。

Log4j有8个日志级别
在 Log4j 中建议只使用 DEBUG、INFO、WARN、ERROR 四个日志级别。
ALL 最低等级的,用于打开所有日志记录。

DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打 印一些运行信息。

INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重 要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避 免打印过多的日志。

WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一 些提示。

ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息, 如果不想输出太多的日志,可以使用这个级别。

FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错 误,这种级别你可以直接停止程序了。

OFF 最高等级的,用于关闭所有日志记录。

log4j配置文件详解

Log4j配置文件名

og4j 配置文件名:log4j.properties Log4j
配值文件存放位置:项目的 src 的根目录中
在这里插入图片描述

log4j.rootLogger=debug,console,logfile
### appender.console输出到控制台 ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=<%d> %5p (%F:%L) [%t] (%c) - %m%n
log4j.appender.console.Target=System.out

### appender.logfile输出到日志文件 ###
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=SysLog.log
log4j.appender.logfile.MaxFileSize=500KB
log4j.appender.logfile.MaxBackupIndex=7
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=<%d> %p (%F:%L) [%t] %c - %m%n

配置根Logger

log4j.rootLogger = [level],appenderName,appenderName2,…

level 是日志记录的优先级,优先级从低到高分别是 DEBUG,INFO,WARN,ERROR。通过在 这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关,比如在这里定义了 INFO 级别,则应用程序中所有 DEBUG 级别的日志信息将不被打印出来。

appenderName 就是指定日志信息输出到哪个地方。可同时指定多个输出目的地。

Log4j 中的 appender

在这里插入图片描述

向控制台输出的 appender

### appender.console 输出到控制台 ### 
log4j.appender.console=org.apache.log4j.ConsoleAppender 
log4j.appender.console.layout=org.apache.log4j.PatternLayout 
log4j.appender.console.layout.ConversionPattern=<%d> %5p (%F:%L) [%t] (%c) - %m%n 
log4j.appender.console.Target=System.out

向文件输出的 appender

### appender.logfile 输出到日志文件 ###
 log4j.appender.logfile=org.apache.log4j.RollingFileAppender 
 log4j.appender.logfile.File=SysLog.log 
 log4j.appender.logfile.MaxFileSize=500KB 
 log4j.appender.logfile.MaxBackupIndex=7 
 log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
 log4j.appender.logfile.layout.ConversionPattern=<%d> %p (%F:%L) [%t] %c - %m%n

向数据库输出的 appender

log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender 
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout 
log4j.appender.logDB.Driver=com.mysql.jdbc.Driver 
log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/bjsxt 
log4j.appender.logDB.User=root log4j.appender.logDB.Password=root 
log4j.appender.logDB.Sql=INSERT INTO 
logs(project_name,create_date,level,category,file_name,thread_name,line,all_ category,message)values('logDemo','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','% t','%L','%l','%m')

通过包名控制日志输出级别

log4j.logger.org.apache=FATAL 
log4j.logger.org.apache.commons=ERROR 
log4j.logger.org.springframework=ERROR 
log4j.logger.com.bjsxt=ERROR

Log4j 的输出格式

Log4J 采用类似 C 语言中的 printf 函数的打印格式格式化日志信息,打印参数如下:

 %m 输出代码中指定的消息  
 %p 输出优先级,即 DEBUG,INFO,WARN,ERROR,FATAL 
 %r 输出自应用启动到输出该 log 信息耗费的毫秒数 
 %c 输出所属的类目,通常就是所在类的全名 
 %t 输出产生该日志事件的线程名 
 %n 输出一个回车换行符,Windows 平台为“\r\n”,Unix 平台为“\n”
  %d 输出日志时间点的日期或时间,默认格式为 ISO8601,也可以在其后指定格式 如:%d{yyyy 年 MM 月 dd 日 HH:mm:ss,SSS},输出类似:2020 年 05 月 01 日 22:10:28,921 
  %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数 如: Testlog.main(TestLog.java:10) %F 输出日志消息产生时所在的文件名称 
  %L 输出代码中的行号 
  %x 输出和当前线程相关联的 NDC(嵌套诊断环境),像 java servlets 多客户多线程的应用 中 
  %% 输出一个"%"字符 
  可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。 如:
  %5c: 输出 category 名称,最小宽度是 5,category<5,默认的情况下右对齐 
  %-5c:输出 category 名称,最小宽度是 5,category<5,"-"号指定左对齐,会有空格
   %.5c:输出 category 名称,最大宽度是 5,category>5,就会将左边多出的字符截掉,<5 不会有空格 
   %20.30c:category 名称<20 补空格,并且右对齐,>30 字符,就从左边交远销出的字符截
掉

Log4j 的使用方式

添加 jar 包:log4j.jar

添加配置文件:log4j.properties

通过 Log4j 的 API 完成日志

import org.apache.log4j.Logger; 
public class LogDemo {
    private final static Logger logger = Logger.getLogger(LogDemo.class);
    public static void main(String[]args){
        String str = "Bjsxt";
        logger.debug(str);
    }
}

在log4j.properties内:

log4j.rootLogger=debug,console,logfile

添加debug
在这里插入图片描述
所有的控制台输出的日志信息都被系统存放到SysLog.log文件内:
在这里插入图片描述
将log4j.properties内的debug改为info:

log4j.rootLogger=info,console,logfile
public class LogDemo {
    private final static Logger logger = Logger.getLogger(LogDemo.class);
    public static void main(String[]args){
        String str = "Bjsxt";
        logger.debug(str);
        try{
            String temp = null;
            temp.length();
        }catch (Exception e){

            logger.debug(e);
            logger.error(e);
        }
    }
}

只输出logger.error(e); 不输出logger.debug(e);
在这里插入图片描述

commons-logging + log4j(经常用到)

commons-logging 是 Apache 的 Commons 项目中提供的一个高层的日志框架,是门面模式的典型应用。
默认情况下,Commons Loggin 自动搜索并使用 Log4j,如果没有找到 Log4j,再使用 JDK Logging。

需要添加的jar包:
log4j.jar
commons-loggin.jar

我们将info改回为debug:

log4j.rootLogger=debug,console,logfile
public class CommonsDemo {

    private final static Log log = LogFactory.getLog(LogDemo.class);
    public static void main(String[]args){
        String str = "Bjsxt";
        log.debug(str);

    }
}

在这里插入图片描述

模拟一个空指针异常:

public class SessionsDemo {

    private final static Log log = LogFactory.getLog(LogDemo.class);
    public static void main(String[]args){
        try{
            //人工模拟一个空指针异常
            String str = null;
            str.length();
        }catch (Exception e){
            log.error("输出",e);
        }
    }
}

在这里插入图片描述

slf4j-api + slf4j-log4j + log4j

slf4j 对日志支持的操作更多,SLF4J 并不是具体 的日志框架,而是作为一个简单门面服务于各类日志框架,

slf4j-api.jar slf4j-log4j.jar log4j.jar
需要添加的jar包:
slf4j-api.jar

slf4j-log4j.jar

log4j.jar

log4j.rootLogger=debug,console,logfile
package com.bjsxt.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SLF4jDemo {
    private final static Logger logger = LoggerFactory.getLogger(SLF4jDemo.class);

    public static void main(String[] args) {
        logger.debug("SLF4J...");
        try{
            String str = null;
            str.length();
        }catch(Exception e){
            logger.error("aaaa",e);
        }
    }
}

在这里插入图片描述

Mybatis 配置的完善

Mybatis 的日志管理

Mybatis 的内置日志工厂(LogFactory)提供日志处理功能, MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具。
在这里插入图片描述

它会使用第一个查 找得到的工具(按上文列举的顺序查找)。如果一个都未找到,日志功能就会被禁用。也就是说在项目中把日志工具环境配置出来后,不用再 MyBatis 进行配置就可以让日志生效.
在这里插入图片描述
指定 SLF4J 作为日志处理器

settings标签必须添加到Properties标签下:

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

在这里插入图片描述
也就是说,我们在mybatis内处理日志的方式,等同于原来在slf4j内做的日志处理方式

使用别名 alias

Mybatis 中的别名配置它只和 XML 配置有关, 只用来减少类完全限定名的多余部分。注 意:别名都是大小写不敏感的。

在配置文件中为类的完整路径定义别名,可以采用两种方式:

使用typeAilas指定单个类的别名

<typeAliases> 
	<typeAlias type="com.bjsxt.pojo.Users" alias="u"/> 
</typeAliases>
 <select id="selectUsersById" parameterType="int" resultType="u">
 	select * from users where userid = #{suibian} 
 </select>

使用 package 指定某个包下所有类的默认别名:

<typeAliases> 
	<package name="com.bjsxt.pojo"/> 
</typeAliases>

引入别名后的映射文件

<select id="selectUsersById" parameterType="int" resultType="users"> 
	select * from users where userid = #{suibian} 
</select>
    <!--配置别名-->
    <typeAliases>
        <typeAlias type="com.bjsxt.pojo.Users" alias="u"/>
        //将包名作为别名
        <package name="com.bjsxt.pojo"/>
    </typeAliases>

SqlSession 对象下的常用 API

SqlSession 对象下的方法是用来执行定义在映射配置文件中的 SELECT,INSERT,UPDATE 和 DELETE 语句。通过 SqlSession 对象下的 API 向 SQL 语句传递参数时,参数可以是基本数 据类型、包装类类型 ,POJO 或 Map。但是参数的数量只能是一个。
SqlSession 对象下的方法需要 namespace + id 来定位需要执行的 SQL 语句。
namespace + id 的作用: 即:namespace 定位到唯一的 mapper 映射文件,id 定位到这 个 mapper 映射文件的指定的 sql 语句。

查询操作

  1. selectOne方法
    T selectOne(String namespace + id , Object parameter)
  2. selectMap方法
    <K,V> Map<K,V> selectMap(String namespace + id , Object parameter, String mapKey)

上一个mybatis示例里的预更新,使用的就是selectOne方法
在这里插入图片描述
在这里,我们在上一个示例项目的基础上,使用selectMap方法,实现根据用户名与用户性别查询用户

修改映射配置文件


    <!--根据用户名与用户性别查询用户-->
    <select id="selectUsersByNameAndSex" resultType="u">
        select * from users where username =#{name} and usersex = #{sex}
    </select>

修改UsersDao接口


    //根据用户名与用户性别查询用户
    Map<Integer,Users> selectUserByNameAndSex(String  username,String usersex);

修改UsersDaoImpl实现类


    //根据用户名与用户性别查询用户
    @Override
    public Map<Integer, Users> selectUserByNameAndSex(String username, String usersex) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        Map<String,String> param = new HashMap<>();
        param.put("name",username);
        param.put("sex",usersex);
        Map<Integer, Users> users = sqlSession.selectMap("com.bjsxt.mapper.UserMapper.selectUsersByNameAndSex", param, "userid");
        return users;
    }

修改UsersDaoServlet接口


    //根据用户名与用户性别查询用户的抽象方法
    Map<Integer,Users> findUsersByNameAndSex(String username, String usersex);

修改UsersDaoServletImpl接口实现类


    //根据用户名与用户性别查询用户
    @Override
    public Map<Integer, Users> findUsersByNameAndSex(String username, String usersex) {
        Map<Integer, Users> map = null;
        try{
            UsersDao usersDao = new UsersDaoImpl();
            map = usersDao.selectUserByNameAndSex(username,usersex);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            MybatisUtils.closeSqlSession();
        }

        return map;
    }

创建测试类

package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;

import java.util.Map;
import java.util.Set;

public class SelectMapTest {
    public static void main(String[] args) {
        UsersService usersService = new UsersServiceImpl();
        Map<Integer, Users> map = usersService.findUsersByNameAndSex("oldliu", "male");
        //获取到map的key
        Set<Integer> integers = map.keySet();
        for(Integer key:integers){
            Users users = map.get(key);
            //输出map的key值
            System.out.println(key);
            System.out.println(users.getUserid()+"\t"+users.getUsername()+"\t"+users.getUsersex());
        }
    }
}

在这里插入图片描述

DML(添加;修改;删除) 操作

在这里插入图片描述
我们在之前的实例内使用过:
在这里插入图片描述

Mapper 动态代理

基于 Mybatis 的 Dao 层设计

目前有两种,一种是不使用Mapper动态代理的方式,讲解如下:
不使用动态代理是指在 Dao 层需要我们自己来创建 Dao 层的接口与接口实现类。 在接口实现类的方法中我们自己通过调用 SqlSession 对象的方法完成数据库的操作。
目前我们的入门案例就是通过这种方式完成了对 users 表的 CRUD 操作。
但这样做,在SqlSession对象的常用方法内只可以向sql语句传递一个参数,如果要传递多个参数,则需要封装到pojo或者Map内。
同时在调用SqlSession对象的方法时会有硬编码的现象namespace+id。

我们最常用的还是在Dao层使用Mapper动态代理
既:Mapper 动态代理(或称为接口 绑定)的操作方式。这种方式下程序员只需要写 Dao 接口,不需要创建 Dao 的接口实现类, **Mybatis 会自动生成接口实现类的代理对象。在 Dao 层我们只要创建接口与映射配置文件即 可。**这种方式可以大大简化 Dao 层的代码结构,是在开发中最常见的使用方式。

Mapper动态代理规范

在这里插入图片描述

Mapper 动态代理的使用

搭建环境

创建项目
创建一个java项目,名为mapperDemo
添加jar包
在这里插入图片描述

创建实体类

package com.bjsxt.pojo; 

public class Users {
    private int userid;
    private String username;
    private String usersex;


    public int getUserid() {
        return userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsersex() {
        return usersex;
    }

    public void setUsersex(String usersex) {
        this.usersex = usersex;
    }
    @Override
    public String toString() {
        return "Users{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                ", usersex='" + usersex + '\'' +
                '}';
    }
}

创建Mybatis工具类

package com.bjsxt.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;

public class MybatisUtils {
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    private static SqlSessionFactory sqlSessionFactory = null;
    static{
        //创建SqlSessionFactory
        InputStream is = null;
        try{
            is = Resources.getResourceAsStream("mybatis-cfg.xml");
        }catch (IOException e){
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    }

    //获取SqlSession
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = threadLocal.get();
        if(sqlSession == null){
            sqlSession = sqlSessionFactory.openSession();
            threadLocal.set(sqlSession);
        }
        return sqlSession;
    }

    //关闭SqlSession
    public static void closeSqlSession(){
        SqlSession sqlSession = threadLocal.get();
        if(sqlSession != null){
            sqlSession.close();
            threadLocal.set(null);
        }
    }
}

配置Mybatis框架(使用动态代理)

添加db.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3307/sys?useSSL=false
jdbc.username=root
jdbc.password=1234567

添加log4j.properties文件

log4j.rootLogger=debug,console,logfile

### appender.console输出到控制台 ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=<%d> %5p (%F:%L) [%t] (%c) - %m%n
log4j.appender.console.Target=System.out

### appender.logfile输出到日志文件 ###
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=SysLog.log
log4j.appender.logfile.MaxFileSize=500KB
log4j.appender.logfile.MaxBackupIndex=7
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=<%d> %p (%F:%L) [%t] %c - %m%n

添加全局配置文件mybatis-cfg.xml:

<?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>
    <!--引入db.properties属性文件-->
    <properties resource="db.properties"/>

    <settings>
        <setting name="useGeneratedKeys" value="true"/>
    </settings>

    <!--配置别名-->
    <typeAliases>
        <package name="com.bjsxt.pojo"/>
    </typeAliases>

    <!--配置环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <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>

    <!--引入Mapper映射配置文件-->
    <mappers>
        <package name="com.bjsxt.mapper"/>
    </mappers>
</configuration>

添加 UsersMapper 接口

package com.bjsxt.mapper;

public interface UsersMapper {

}

添加UsersMapper映射配置文件

<?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.bjsxt.mapper.UsersMapper"> 

</mapper>

实现查询所有用户

修改映射配置文件

    <!--查询所有用户-->
    <select id="selectUsersAll" resultType="users">
         select * from users
    </select>

修改UsersMapper接口添加抽象方法


public interface UsersMapper {
	//这个抽象方法的方法名必须和它有关系的映射配置文件里对应的id一样
    List<Users> selectUsersAll();

}

创建业务层接口

public interface UsersService {
	//这个起名随意
    List<Users> findUsersAll();
}

创建业务层接口实现类

package com.bjsxt.serivce.impl;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.serivce.UsersService;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

/**
 * 通过mybatis动态代理的方式去操作数据库
 */
public class UsersServiceImpl implements UsersService {
    @Override
    public List<Users> findUsersAll() {
        List<Users> list = null;
        try{
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            //getMapper方法的作用是根据给定的接口的Class对象,生成该接口的接口实现类的代理对象
            UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
            list = mapper.selectUsersAll();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            MybatisUtils.closeSqlSession();
        }
        return list;
    }

}

创建测试类

package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.serivce.UsersService;
import com.bjsxt.serivce.impl.UsersServiceImpl;

import java.util.List;

public class SelectUsersAllTest {
    public static void main(String[] args) {
        UsersService usersService = new UsersServiceImpl();
        List<Users> list = usersService.findUsersAll();
        /**
         * 简化的循环,相当于将迭代之后的list赋值给了变量e 然后输出e
         * list.forEach(e -> System.out.println(e));
         *
         * 相当于
         *  for(Users e:list){
         *      System.out.println(e);
         *  }
         */
        list.forEach(System.out::println);
    }
}

在这里插入图片描述

实现根据用户 ID 查询用户

修改映射配置文件

    <!--根据用户ID查询用户-->
    <select id="selectUsersById" resultType="users">
         select * from users where userid = #{userid}
    </select>

修改UsersMapper接口


    Users selectUsersById(int userid);

修改业务层接口


    Users findUsersById(int userid);

修改业务层接口实现类


    @Override
    public Users findUsersById(int userid) {
        Users users = null;
        try{
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
            users = mapper.selectUsersById(userid);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            MybatisUtils.closeSqlSession();
        }
        return users;
    }

创建测试类

package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.serivce.UsersService;
import com.bjsxt.serivce.impl.UsersServiceImpl;

public class SelectUsersByIdTest {
    public static void main(String[] args) {
        UsersService usersService = new UsersServiceImpl();
        Users users = usersService.findUsersById(1);
        System.out.println(users);
    }
}

在这里插入图片描述

Mapper动态代理模式下的多参数处理

顺序传参法

在映射文件中,SQL 语句中的参数需要使用 arg0,arg1…或者 param1,param2…表示参 数的顺序。此方法可读性低,且要求参数的顺序不能出错,在开发中不建议使用。

    <!--根据用户姓名与性别查询用户,使用顺序传参法-->
    <select id="selectUsersOrderParam" resultType="users">
        select * from users where username = #{param1} and usersex= #{param2}
    </select> 

在UsersMapper接口内添加一个和上面的id有关的抽象方法:
selectUsersOrderParam方法

    List<Users> selectUsersOrderParam(String username,String usersex);

使用一个测试类进行测试:

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersOrderParamTest {

    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        List<Users> list = usersMapper.selectUsersOrderParam("oldliu","male");
        list.forEach(System.out::println);
        MybatisUtils.closeSqlSession();
    }
}

在这里插入图片描述

@Param 注解传参法

在接口方法的参数列表中通过@Param 注解来定义参数名称,在 SQL 语句中通过注解中 所定义的参数名称完成参数位置的指定。
此方式在参数不多的情况还是比较直观的,推荐使用。


    <!--根据用户姓名与性别查询用户,使用@Param注解传参法-->
    <select id="selectUsersAnnParam" resultType="users">
        select * from users where username = #{name} and usersex= #{sex}
    </select>

在UsersMapper接口内创建一个和映射配置文件内对应的 id有关的抽象方法


    List<Users> selectUsersAnnParam(@Param("name") String username,@Param("sex") String usersex);
package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersAnnParamTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        List<Users> list = usersMapper.selectUsersAnnParam("oldliu","male");
        list.forEach(System.out::println);
        MybatisUtils.closeSqlSession();
    }
}

在这里插入图片描述
根据这三条代码,我们可以看出,已将参数绑定到sql语句内,且查询出结果

POJO 传参法

在 Mapper 动态代理中也可以使用 POJO 作为传递参数的载体,在 SQL 语句中绑定参数 时使用 POJO 的属性名作为参数名即可。此方式推荐使用。
也就是使用实体类作为载体去传递参数


    <!--根据用户姓名与性别查询用户,使用POJO传参法-->
    <select id="selectUsersPOJOParam" resultType="users">
        select * from users where username = #{username} and usersex= #{usersex}
    </select>

    List<Users> selectUsersPOJOParam(Users users);
package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersPOJOParamTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = new Users();
        users.setUsername("oldliu");
        users.setUsersex("male");
        List<Users> list = usersMapper.selectUsersPOJOParam(users);
        list.forEach(System.out::println);
        MybatisUtils.closeSqlSession();
    }
}

Map传参法

在 Mapper 动态代理中也可以使用 Map 作为传递参数的载体,在 SQL 语句中绑定参数 时使用 Map 的 Key 作为参数名即可。此方法适合在传递多参数时,如果没有 POJO 能与参数 匹配,可以使用该方式传递参数。推荐使用。
MyBatis 传递 map 参数时,如果传递参数中没有对应的 key 值,在执行 sql 语句时默认 取的是 null。

    <!--根据用户姓名与性别查询用户,使用Map传参法-->
    <select id="selectUsersMapParam" resultType="users">
        select * from users where username = #{keyname} and usersex= #{keysex}
    </select>

    List<Users> selectUsersMapParam(Map<String,String> map);
package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

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

public class SelectUsersMapParamTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Map<String,String> map = new HashMap<>();
        map.put("keyname","oldliu");
        map.put("keysex","male");
        List<Users> list = usersMapper.selectUsersMapParam(map);
        list.forEach(System.out::println);
        MybatisUtils.closeSqlSession();
    }
}

在这里插入图片描述

映射配置文件中的特殊字符处理

在 Mybatis 的映射配置文件中不可以使用一些特殊字符,如:<,>。

使用符号实体

在这里插入图片描述


    <!--查询用户ID大于1的用户-->
    <select id="selectUsers" resultType="users">
        select * from users where userid &gt; #{userid}
    </select>

    List<Users> selectUsers(int userid);
package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        List<Users> list = usersMapper.selectUsers(1);
        list.forEach(System.out::println);
        MybatisUtils.closeSqlSession();
    }
}

在这里插入图片描述

CDATA区

CDATA:全称为 Character Data,以"<![CDATA[ "内容" ]]>",CDATA 中的内容不会被解析程 序解析。


    <!--查询用户ID大于1的用户-->
    <select id="selectUsers" resultType="users">
        select * from users where userid <![CDATA[ > ]]> #{userid}
    </select>

Mybatis 的分页查询

使用 RowBounds

RowBounds 是 Mybatis 提供的一个专门处理分页的对象。在 RowBounds 对象中有两个 成员变量:
offset:偏移量, 从 0 开始计数
limit:限制条数

使用 RowBounds 进行分页,非常方便,不需要在 SQL 语句中写 limit关键字,即可完成分页的功能。但是由于它是在 SQL 查询出所有结果的基础上截取数据的,所以在数据量大的 SQL 中并不适用它更适合在返回数据结果较少的查询中使用

修改映射配置文件

    <!--查询所有数据使用RowBounds实现分页处理-->
    <select id="selectUsersRowBounds" resultType="users">
        select * from users
    </select>

    List<Users> selectUsersRowBounds(RowBounds rowBounds);
package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersRowBoundsTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        //创建一个RowBounds对象 
        // (1,1) 第一个1是从第2个数据开始显示,第二个1是显示1条数据
        RowBounds rowBounds = new RowBounds(1,1);
        List<Users> list = usersMapper.selectUsersRowBounds(rowBounds);
        list.forEach(System.out::println);
        MybatisUtils.closeSqlSession();
    }
}

在这里插入图片描述
当显示两条数据时:

        // (1,1) 第一个1是从第2个数据开始显示,第二个2是显示2条数据
        RowBounds rowBounds = new RowBounds(1,2);

在这里插入图片描述

使用SQL语句分页

在分页查询时,如果返回的结果较多,那么需要使用特定的 SQL 语句来实现分页处理。 在 MySQL 数据库中我们可以使用 limit 实现分页

修改映射配置文件

    <!--查询所有数据使用limit实现分页处理-->
    <select id="selectUsersLimit" resultType="users">
        select * from users limit #{offset},#{limit}
    </select>

    List<Users> selectUsersLimit(@Param("offset") int offset,@Param("limit") int limit);
package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersLimitTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        List<Users> list = usersMapper.selectUsersLimit(1,1);
        list.forEach(System.out::println);
        MybatisUtils.closeSqlSession();
    }
}

在这里插入图片描述

Mapper 动态代理模式下的 DML 操作

实现添加用户的操作

修改映射配置文件

    <!--添加用户-->
    <insert id="insertUsers" >
        insert into users values(default ,#{username},#{usersex})
    </insert>

修改 UsersMapper 接口

    int insertUsers(Users users);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

public class InsertUsersTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = new Users();
        users.setUsername("itbz");
        users.setUsersex("male");
        int flag = usersMapper.insertUsers(users);
        sqlSession.commit();
        System.out.println(flag);
        MybatisUtils.closeSqlSession();
    }
}

在这里插入图片描述

主键值回填

应用场景:
有一个表older,它的主键是olderId,是自增的,使用这个表的主键作为订单号,在插入一个数据的同时应该返回一个订单号,像这种场景就会用到主键值回填。

在数据库中插入数据时,有时我们是需要获取新数据的主键值。在 Mybatis 中支持主键 值回填,可以让我们更够更方便的获取新添加数据的主键值
Mybatis 中支持两种方法获取主键:
获取自增主键的值。如:MySQL、SqlServer
获取非自增主键的值。如 Oracle

获取自增主键值

开启自动获取自增主键值

局部配置
映射配置文件
useGeneratedKeys="true"只对当前得到insert有作用

    <!--添加用户时获取主键值[自增]-->
    <insert id="insertUsersGetKey" useGeneratedKeys="true" keyProperty="userid">
        insert into users values(default ,#{username},#{usersex})
    </insert>

    void insertUsersGetKey(Users users);
package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

public class InsertUsersGetKeyTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = new Users();
        //设置插入的数据
        users.setUsername("itbz-sxt3");
        users.setUsersex("male");
        //调用方法,将数据通过方法放到sql语句内
        usersMapper.insertUsersGetKey(users);
        sqlSession.commit();
        System.out.println(users.getUserid());
        MybatisUtils.closeSqlSession();
    }
}

z
在这里插入图片描述

全局配置
全局配置文件


    <settings>
        <setting name="useGeneratedKeys" value="true"/>
    </settings>

省去useGeneratedKeys=“true”,使的这个效果产生在全局上
在这里插入图片描述
同时,我们的映射配置文件可以修改为:

<!--添加用户获取主键值[自增]--> 
<insert id="insertUsersGetKey" keyProperty="userid"> 
	insert into users values(default ,#{username},#{usersex})
 </insert>

获取非自增主键值

适用于数据库内不支持自增的数据表,也适用于支持自增的额数据表。

修改映射配置文件


    <!--添加用户获取主键值[非自增] oracle数据库用[order:Before] mysql数据库用[order:after]-->
    <insert id="insertUsersGetKey2">
        <selectKey order="AFTER" keyProperty="userid" resultType="int">
           <!--在MySQL数据库中获取插入数据的主键的值: SELECT LAST_INSERT_ID(),SELECT @@Identity 是SELECT LAST_INSERT_ID()的同义词。作用是相同的。 -->
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into users values(default ,#{username},#{usersex})
    </insert>

修改 UsersMapper 接口

void insertUsersGetKey2(Users users);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

public class InsertUserGetKey2Test {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = new Users();
        users.setUsername("itbz-sxt4");
        users.setUsersex("male");
        usersMapper.insertUsersGetKey2(users);
        sqlSession.commit();
        System.out.println(users.getUserid());
        MybatisUtils.closeSqlSession();
    }
}

在这里插入图片描述
下去可以详细了解下Mapper动态代理的原理是什么

动态SQL

在 MyBatis 中提供了动态 SQL 功能。将使用 Java 代码拼接 SQL 语句,改变为在 XML 映射文件中使用标签拼接 SQL 语句。
MyBatis 中动态 SQL 是编写在 mapper.xml 中的,其语法和 JSTL 类似,但是却是基于强大 的 OGNL 表达式实现的。

if 标签

if 标签单分支判断语句

修改映射配置文件


    <!-- if标签的使用 根据用户给定的条件进行查询 当id不为0,其他参数不为空时添加sql语句 -->
    <select id="selectUsersByProperty" resultType="users">
          select * from users where 1=1
          <if test="userid != 0">
            and userid = #{userid}
          </if>
          <if test="username != null and username != ''">
            and username = #{username}
          </if>
          <if test="usersex != null and usersex != ''">
              and usersex = #{usersex}
          </if>
    </select>

修改UsersMapper接口


    List<Users> selectUsersByProperty(Users users);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersByPropertyTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = new Users();
        users.setUsername("itbz-sxt4");
        users.setUserid(13);
        List<Users> list = usersMapper.selectUsersByProperty(users);
        list.forEach(System.out::println);
    }
}

在这里插入图片描述

choose,when,otherwise标签

从多个条件中选择一个使用

修改映射配置文件

    <!-- choose,when,otherwise标签的使用 多选一条件-->
    <select id="selectUsersByChoose"  resultType="users">
        select * from users where 1=1
        <choose>
            <when test="username != null and username != ''">
                and username = #{username}
            </when>
            <when test="usersex != null and usersex != ''">
                and usersex = #{usersex}
            </when>
            <otherwise>
                and userid = 1
            </otherwise>
        </choose>
    </select>

修改UsersMapper接口


    List<Users> selectUsersByChoose(Users users);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersByChooseTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = new Users();
        users.setUsername("itbz-sxt4");
        users.setUsersex("male");
        List<Users> list = usersMapper.selectUsersByChoose(users);
        list.forEach(System.out::println);
    }
}


在这里插入图片描述

where标签

使用 where 标签,就不需要提供 where 1=1 这样的条件了。如果判断条件不为空则自 动添加 where 关键字,并且会自动去掉第一个条件前面的 and 或 or。
修改映射配置文件


    <!-- where标签的使用 根据用户给定的条件进行查询使用where标签实现-->
    <select id="selectUsersByPropertyWhere" resultType="users">
        select * from users
        <where>
            <if test="userid != 0">
                and userid = #{userid}
            </if>
            <if test="username != null and username != ''">
                and username = #{username}
            </if>
            <if test="usersex != null and usersex != ''">
                and usersex = #{usersex}
            </if>
        </where>
    </select>

修改UsersMapper接口


    List<Users> selectUsersByPropertyWhere(Users users);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersByPropertyWhereTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = new Users();
        users.setUsername("itbz-sxt4");
        users.setUserid(6);
        List<Users> list = usersMapper.selectUsersByPropertyWhere(users);
        list.forEach(System.out::println);
    }
}

在这里插入图片描述

bind标签

bind 标签允许我们在 OGNL 表达式以外创建一个变量,并可以将其绑定到当前的 SQL 语句中。一般应用于模糊查询,通过 bind 绑定通配符和查询值。

修改映射配置文件

    <!-- bind标签 根据用户姓名模糊查询-->
    <select id="selectUsersByLikeName" resultType="users">
        <bind name="likeName" value="'%'+name+'%'"/>
        select * from users where username like #{likeName}
    </select>

修改UsersMapper接口


    List<Users> selectUsersByLikeName(String name);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class SelectUsersByLikeNameTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        List<Users> list = usersMapper.selectUsersByLikeName("a");
        list.forEach(System.out::println);
    }
}

在这里插入图片描述

set标签

set 标签用在 update 语句中。借助 if 标签,可以只对有具体值的字段进行更新。set 标 签会自动添加 set 关键字,自动去掉最后一个 if 语句的多余的逗号。

修改映射配置文件


   <!-- set标签的使用 选择更新-->
    <update id="usersUpdate">
        update users
        <set>
            <if test="username != null and username != ''">
                username = #{username},
            </if>
            <if test="usersex != null and usersex != ''">
                usersex = #{usersex},
            </if>
        </set>
        where userid = #{userid}
    </update>

修改UsersMapper接口


    void usersUpdate(Users users);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

public class UsersUpdateTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = new Users();
        users.setUsername("LiSi");
        users.setUsersex("male");
        users.setUserid(2);
        usersMapper.usersUpdate(users);
        sqlSession.commit();
    }
}

更新前:
在这里插入图片描述
更新后:
在这里插入图片描述
在这里插入图片描述

foreach标签

foreach 标签的功能非常强大,我们可以将任何可迭代对象如 List、Set 、Map 或者数 组对象作为集合参数传递给 foreach 标签进行遍历。它也允许我们指定开头与结尾的字符串 以及集合项迭代之间的分隔符。

迭代List,Set

  1. 类型:
collection=”collection”
  1. 名称:

修改映射配置文件

    <!--查询用户ID为1或者2的用户-->
    <select id="selectUsersByIdUseCollection" resultType="users">
        select * from users where userid in
        <foreach collection="collection" item="userid" open="(" separator="," close=")">
             #{userid}
        </foreach>
    </select>

修改UsersMapper接口

    List<Users> selectUsersByIdUseCollection(Collection collection);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.omg.PortableInterceptor.INACTIVE;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class SelectUsersByIdUseCollectionTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        /*List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);*/
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        List<Users> users = usersMapper.selectUsersByIdUseCollection(set);
        users.forEach(System.out::println);
    }
}

在这里插入图片描述

迭代数组

类型:collection=”array”

修改映射配置文件


    <!--查询用户ID为1或者2的用户使用数组传递参数-->
    <select id="selectUsersByIdUseArray" resultType="users">
        select * from users where userid in
        <foreach collection="array" item="userid" open="(" separator="," close=")">
            #{userid}
        </foreach>
    </select>

修改UsersMapper接口


    List<Users> selectUsersByIdUseArray(int[] arr);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class SelectUsersByIdUseArrayTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        int[] arr = new int[]{1,2};
        List<Users> users = usersMapper.selectUsersByIdUseArray(arr);
        users.forEach(System.out::println);
    }
}

在这里插入图片描述

迭代Map

类型:collection=”suibian”或者 collection=”suibian.entrySet()”

修改映射配置文件


    <!--根据给定的条件做计数处理-->
   <!-- select count(*) from users where username = 'itbz-sxt4' and usersex = 'male'-->
    <select id="selectUsersCount" resultType="int">
        select count(*) from users where
        <foreach collection="suibian" separator="and" item="value" index="key">
            ${key} = #{value}
        </foreach>
    </select>

修改UsersMapper接口


    int selectUsersCount(@Param("suibian") Map<String,String> map);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.HashMap;
import java.util.Map;

public class SelectUsersCountTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Map<String,String> map= new HashMap<>(); 
        map.put("usersex","male");
        int count = usersMapper.selectUsersCount(map);
        System.out.println(count);
    }
}

在这里插入图片描述

使用foreach标签完成批量添加

修改映射配置文件


    <!--批量添加用户-->
    <!--insert into users values(DEFAULT,'itbz-sxt5','male'),(DEFAULT,'itbz-sxt6','male')-->
    <insert id="insertUsersBatch" >
        insert into users values
        <foreach collection="collection" item="user" separator=",">
            (default ,#{user.username},#{user.usersex})
        </foreach>
    </insert>

修改UsersMapper接口


    int insertUsersBatch(List<Users> list);

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.ArrayList;
import java.util.List;

public class InsertUsersBatchTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        List<Users> list = new ArrayList<>();
        Users users = new Users();
        users.setUsername("sxt6");
        users.setUsersex("male");
        Users users1 = new Users();
        users1.setUsername("sxt7");
        users1.setUsersex("male");
        list.add(users);
        list.add(users1);
        int flag = usersMapper.insertUsersBatch(list);
        sqlSession.commit();
        System.out.println(flag);
    }
}

在这里插入图片描述

Mybatis缓存

缓存是一般的 ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力。

MyBatis 缓存方式分为一级缓存和二级缓存,同时也可配置关于缓存设置。
一级缓存是将结果缓存在 SqlSession 对象中,二级缓存是存储在 SqlSessionFactory 对象 中。默认情况下,MyBatis 开启一级缓存,没有开启二级缓存。

一级缓存的使用

一级缓存也叫本地缓存,MyBatis 的一级缓存是在会话(SqlSession)层面进行缓存的。 MyBatis 的一级缓存是默认开启的,不需要任何的配置。

一级缓存的生命周期

-  MyBatis 在开启一个数据库会话时,会创建一个新的 SqlSession 对象,SqlSession 对象中 会有一个新的 Executor 对象。Executor 对象中持有一个新的 PerpetualCache 对象;当会 话结束时,SqlSession 对象及其内部的 Executor 对象还有 PerpetualCache 对象也一并释 放掉。 
-  如果 SqlSession 调用了 close()方法,会释放掉一级缓存 PerpetualCache 对象,一级缓存 将不可用。 
-  如果 SqlSession 调用了 clearCache(),会清空 PerpetualCache 对象中的数据,但是该对象 仍可使用。 
-  SqlSession 中执行了任何一个 update 操作(update()delete()insert()) ,都会清空 PerpetualCache 对象的数据,但是该对象可以继续使用。

如何判断两次查询是完全相同的查询

Mybatis 认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同 的两次查询。

-  传入的 statementId。 
-  查询时要求的结果集中的结果范围。
-  这次查询所产生的最终要传递给 Preparedstatement 的 Sql 语句字符串。
-  传递的参数值

测试一级缓存示例

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

public class SelectUsersByIdCacheOneTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = usersMapper.selectUsersById(1);
        System.out.println(users);
        Users users2 = new Users();
        users2.setUsername("aaaa");
        users2.setUsersex("male");
        usersMapper.insertUsers(users);
        System.out.println("-----------------");
        Users users1 = usersMapper.selectUsersById(1);
        System.out.println(users1);
    }
}

当执行两次输出语句时,由于一级缓存的存在,只会调用一次sql查询语句。
在这里插入图片描述

在这里插入图片描述
输出整体结果:
在这里插入图片描述

二级缓存的使用

MyBatis 的二级缓存是 Application 级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。二级缓存是 SqlSessionFactory 上的缓存,可以是由一个 SqlSessionFactory 创 建的不同的 SqlSession 之间共享缓存数据。默认并不开启。
SqlSession 在执行 commit()或者 close()的时候将数据放入到二级缓存

Sqlsession 共享二级缓存
在这里插入图片描述

二级缓存的配置方式

实现二级缓存的时候,MyBatis 要求缓存的 POJO 必须 是可序列化的, 也就是要求实现 Serializable 接口。在映射配置文件中配置就可以 开启缓存了。

二级缓存特点

-  映射语句文件中的所有 select 语句将会被缓存。
-  映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。 
-  二级缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响 
-  如果在加入<cache/>标签的前提下让个别 select 元素不使用缓存,可以使用 useCache 属性,设置为 false-  缓存会使用默认的 Least Recently Used(LRU,最近最少使用的)算法来收回。 
-  根据时间表,比如 No Flush Interval,(CNFI 没有刷新间隔),缓存不会以任何时间顺序 来刷新。 
-  缓存会存储列表集合或对象(无论查询方法返回什么)1024 个引用 
-  缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以 安全的被调用者修改,不干扰其他调用者或线程所做的潜在修改。

二级缓存示例

在 mybatis-config.xml 文件中的标签配置开启二级缓存。cacheEnabled 的默认 值就是 true,所以这步的设置可以省略。

<settings> 
	<setting name="cacheEnabled" value="true"/>
</settings>

在映射配置文件中添加

<mapper namespace="com.bjsxt.mapper.UsersMapper"> 
	<cache/> 
</mapper>

在这里插入图片描述

JavaBean 对象必须实现序列化接口( implements Serializable )

package com.bjsxt.pojo;

import java.io.Serializable;

public class Users implements Serializable{
    private int userid;
    private String username;
    private String usersex;


    public int getUserid() {
        return userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsersex() {
        return usersex;
    }

    public void setUsersex(String usersex) {
        this.usersex = usersex;
    }
    @Override
    public String toString() {
        return "Users{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                ", usersex='" + usersex + '\'' +
                '}';
    }
}

创建测试类

package com.bjsxt.test;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

public class SelectUsersByIdCacheTwoTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Users users = usersMapper.selectUsersById(1);
        System.out.println(users);
        //第一次查询结束后关闭sqlSession
        MybatisUtils.closeSqlSession();
        System.out.println("-----------------------");
        //再创建一个新的sqlSession对象
        SqlSession sqlSession1 = MybatisUtils.getSqlSession();
        UsersMapper usersMapper1 = sqlSession1.getMapper(UsersMapper.class);
        //再次执行查询操作
        Users users1 = usersMapper1.selectUsersById(1);
        System.out.println(users1);
    }
}

我们可以从下图看出,第二次查询是直接从缓存调用的查询语句和查询结果,二级缓存使用有效。
在这里插入图片描述

如何区分一级缓存和二级缓存

跳转链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值