MyBatis3——入门介绍

目录

  • 1.MyBatis简介
  • 2.MyBatis——入门案例
  • 3.MyBatis——全局配置文件常用标签
    • (1)properties属性
    • (2)settings设置
    • (3)typeAliases别名处理器
    • (4)typeHandlers类型处理器
    • (5)plugins插件
    • (6)environments环境
    • (7)databaseIdProvider环境
    • (7)mapper映射
  • 4.MyBatis——映射文件
    • (1)简单的增删改查
    • (2)获取自增主键的值
    • (3)获取非自增主键的值(Oracle)
    • (4)参数处理——单个参数
    • (5)参数处理——多个参数
    • (6)参数处理——命名参数
    • (7)参数处理——POJO & Map & TO
    • (8)参数处理——参数封装扩展思考
    • (9)参数处理——#与&取值的区别
    • (10)Select
      • ① 返回值类型为List
      • ② 记录封装map
      • ③ resultMap——自定义结果映射规则
      • ④ resultMap——关联查询_环境搭建
      • ⑤ resultMap——级联属性封装结果
      • ⑥ resultMap——association定义关联对象封装规则
      • ⑦ resultMap——association分步查询 & 延迟加载
      • ⑧ resultMap——collection定义关联集合封装规则
      • ⑨ resultMap——collection分步查询 & 延迟加载
      • ⑩ resultMap——discriminator鉴别器
  • 5.MyBatis——动态SQL
    • (1)简介 & 环境搭建
    • (2)动态SQL标签——if
    • (3)动态SQL标签——where
    • (3)动态SQL标签——trim
    • (4)动态SQL标签——choose
    • (5)动态SQL标签——set(与if结合的动态更新)
    • (6)动态SQL标签——foreach遍历集合
    • (7)动态SQL标签——mysql下foreach批量插入的两种方式
    • (8)动态SQL标签——内置参数_parameter和_databaseId
    • (9)动态SQL标签——bind绑定
    • (10)动态SQL标签——抽取可重用的sql片段
  • 6.MyBatis——缓存机制
    • (1)缓存介绍
      • ① 一级缓存
      • ② 二级缓存
    • (2)一级缓存体验
    • (3)一级失效的四种情况
    • (4)二级缓存的使用
    • (5)缓存有关的设置/属性
    • (6)缓存原理图示
    • (7)第三方缓存整合——ehcache
      • ① 导入ehcache适配包
      • ② 在config目录下添加ehcache.xml文件
      • ③ 在EmployeeMapper.xml文件中进行配置
      • ④ 测试
      • ⑤ 扩展——引用缓存
  • 7.MyBatis——SSM框架整合
    • (1)在IDEA中新建一个Java Web项目
    • (2)导入需要的jar包
    • (3)进行各种配置以及代码的编写
    • (4)测试
  • 8.MyBatis——逆向工程
    • (1)MyBatis Generator
    • (2)编写相应的配置文件及代码
  • 9.MyBatis——工作原理
    • (1)框架分层架构
    • (2)入门案例的运行流程
  • 10.MyBatis——插件开发
    • (1)插件原理
    • (2)编写插件
    • (3)多个插件运行流程
    • (4)开发插件
    • (5)PageHelper分页插件的使用
  • 11.Mybatis扩展
    • (1)批量操作
    • (2)自定义类型处理器——MyBatis中枚举类型的默认处理
    • (3)自定义类型处理器——使用自定义的类型处理器处理枚举类型

本文章的笔记整理来自尚硅谷视频https://www.bilibili.com/video/BV1mW411M737

1.MyBatis简介

(1)MyBatis历史
原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了Google Code,随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis ,代码于2013年11月迁移到Github。iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。
(2)MyBatis特点
① MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的半自动化持久层框架。
② MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
③ MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
(3)MyBatis与其它对应框架或组件的对比

MyBatis 半自动化的持久化层框架
JDBC ① SQL夹在Java代码块里,耦合度高导致硬编码内伤。② 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见。
Hibernate和JPA ① 长难复杂SQL,对于Hibernate而言处理也不容易内部自动生产的SQL,不容易做特殊优化。② 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难,这会导致数据库性能下降。

总之,对开发人员而言,核心sql还是需要自己来优化的。除此之外,如果sql代码和java代码分开,那么它们的功能边界就更加清晰,一个专注业务、一个专注数据。

(4)MyBatis地址为https://github.com/mybatis/mybatis-3/

2.MyBatis——入门案例

(1)创建测试表tbl_employee并添加一条测试数据,表结构及数据如下:

在这里插入图片描述
在这里插入图片描述

(2)在IDEA中创建一个Java项目,并在项目的根目录下创建lib目录(用于存放要导入的 jar 包)和config目录(用于存放配置文件),另外,需要右键点击config目录,找到Mark Directoy as并选择Resources Root。

MyBatis3——入门介绍_第1张图片
(3)导入相关的 jar 包并引入到项目中

MyBatis3——入门介绍_第2张图片
MyBatis3——入门介绍_第3张图片
(4)Mybatis入门案例项目的整体目录结构如下:

MyBatis3——入门介绍_第4张图片

各个部分的具体代码如下:
① 日志配置文件log4j.xml


DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 
 <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
   <param name="Encoding" value="UTF-8" />
   <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" />
   layout>
 appender>
 <logger name="java.sql">
   <level value="debug" />
 logger>
 <logger name="org.apache.ibatis">
   <level value="info" />
 logger>
 <root>
   <level value="debug" />
   <appender-ref ref="STDOUT" />
 root>
log4j:configuration>

② 与数据库中的表tbl_employee对应的实体类Employee.java

package com.atguigu.mybatis.bean;
import org.apache.ibatis.type.Alias;

//@Alias("别名"):单独为Employee起别名
//@Alias("emp")
public class Employee {
    //属性名称应该与对应数据库表(tbl_employee)中的字段一致
    private Integer id;
    private String last_name;
    private String email;
    private String gender;
    
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    
    public String getLast_name() {
        return last_name;
    }
    
    public void setLast_name(String last_name) {
        this.last_name = last_name;
    }
    
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    @Override
    public String toString() {
        return "Employee [id=" + id + ", lastName=" + last_name + ", email="
                + email + ", gender=" + gender + "]";
    }
}

③ Mapper接口EmployeeMapper.java

package com.atguigu.mybatis.dao;

import com.atguigu.mybatis.bean.Employee;

public interface EmployeeMapper {
    
    public Employee getEmpById(Integer id);
}

④ sql映射文件EmployeeMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">

	
    
    <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
		select * from tbl_employee where id = #{id}
	select>
mapper>

⑤ 数据库配置文件dbconfig.properties

jdbc.drive=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

⑥ mybatis的全局配置文件mybatis-config.xml


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <properties resource="dbconfig.properties">properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.drive}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            dataSource>
        environment>
    environments>
    
    
    <mappers>
        <mapper resource="EmployeeMapper.xml" />
    mappers>
configuration>

⑦ 测试代码

package com.atguigu.mybatis.test;

import com.atguigu.mybatis.bean.Employee;
import com.atguigu.mybatis.dao.EmployeeMapper;
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 org.junit.Test;

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

public class MyBatisTest {
    
    //根据全局配置文件mybatis-config.xml,利用SqlSessionFactoryBuilder创建SqlSessionFactory
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }
    
    /*
     * 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象,其包含数据源等一些运行环境信息
     * 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。
     * 3、将sql映射文件注册在全局配置文件中
     * 4、写代码:
     * 		1)、根据全局配置文件得到SqlSessionFactory;
     * 		2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查
     * 			一个sqlSession就是代表和数据库的一次会话,用完关闭
     * 		3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。
     *
     * @throws IOException
     */
     
    //旧版本常用方式
    @Test
    public void test01() throws IOException {
        // 获取sqlSession实例,能直接执行已经映射的sql语句
        // sql的唯一标识:statement Unique identifier matching the statement to use.
        // 执行sql要用的参数:parameter A parameter object to pass to the statement.
        
		//使用SqlSessionFactory获取sqlSession对象,一个SqlSession对象代表和数据库的一次会话
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        try {
            Employee employee = openSession.selectOne(
                    "com.atguigu.mybatis.dao.EmployeeMapper.getEmpById", 1);
            System.out.println(employee);
        } finally {
            openSession.close();
        }
    }
    
    //新版本常用的方式:接口式编程
    /*
     * 1、接口式编程
     * 	原生:		Dao		====>  DaoImpl
     * 	mybatis:	Mapper	====>  xxMapper.xml
     *
     * 2、SqlSession代表和数据库的一次会话;用完必须关闭;
     * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。
     * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
     * 		(将接口和xml进行绑定)
     * 		EmployeeMapper empMapper =	sqlSession.getMapper(EmployeeMapper.class);
     * 5、两个重要的配置文件:
     * 		mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
     * 		sql映射文件:保存了每一个sql语句的映射信息:将sql抽取出来。
     *
     */
    @Test
    public void test02() throws IOException {
        // 1、获取sqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        // 2、获取sqlSession对象
        SqlSession openSession = sqlSessionFactory.openSession();
        try {
            // 3、获取接口的实现类对象
            //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            Employee employee = mapper.getEmpById(1);
            System.out.println(mapper.getClass());
            System.out.println(employee);
        }finally{
            openSession.close();
        }
    }
}

结果如下:
MyBatis3——入门介绍_第5张图片

3.MyBatis——全局配置文件常用标签

(1)properties属性

MyBatis可以使用properties来引入外部properties配置文件的内容。

# 数据库配置文件dbconfig.properties
jdbc.drive=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

<properties resource="dbconfig.properties">properties>

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC" />
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.drive}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        dataSource>
    environment>
environments>

(2)settings设置

settings设置是MyBatis 中极为重要的调整设置,它们会改变MyBatis 运行时的行为。
MyBatis3——入门介绍_第6张图片
例如开启自动驼峰命名规则映射:

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

(3)typeAliases别名处理器

typeAliases:别名处理器,它可以为java类型起别名(别名不区分大小写)

<typeAliases>
    
    

    
    <package name="com.atguigu.mybatis.bean"/>

    
typeAliases>

除此之外,MyBatis已经为Java中一些常见的数据类型起好了别名,在开发时直接使用即可。
MyBatis3——入门介绍_第7张图片

(4)typeHandlers类型处理器

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
MyBatis3——入门介绍_第8张图片

(5)plugins插件

插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行。后面会有专门的章节来介绍mybatis运行原理以及插件。
• Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
• ParameterHandler (getParameterObject, setParameters)
• ResultSetHandler (handleResultSets, handleOutputParameters)
• StatementHandler (prepare, parameterize, batch, update, query)

(6)environments环境

MyBatis可以配置多种环境,例如开发、测试和生产环境需要有不同的配置。每种环境使用一个environment标签进行配置并指定唯一标识符。可以通过environments标签中的default属性指定一个环境的标识符来快速地切换环境。
① environment——指定具体的环境:

id 指定当前环境的唯一标识
transactionManager、dataSource 分别表示事务管理、数据源,必须存在于environment中
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC" />
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.drive}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        dataSource>
    environment>
environments>

② transactionManager——事务管理

type JDBC、MANAGED、自定义
JDBC 使用了 JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围
MANAGED 不提交或回滚一个连接、让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)
自定义 实现TransactionFactory接口,type=全类名/别名

③ dataSource——数据源

type UNPOOLED、POOLED、JNDI、自定义
UNPOOLED 不使用连接池
POOLED 使用连接池
JNDI 在EJB 或应用服务器这类容器中查找指定的数据源
自定义 实现DataSourceFactory接口,定义数据源的获取方式
注:在实际开发中,一般使用Spring管理数据源,并进行事务控制的配置来覆盖上述配置。

(7)databaseIdProvider环境

MyBatis 可以根据不同的数据库厂商执行不同的语句。


<databaseIdProvider type="DB_VENDOR">
    
    <property name="MySQL" value="mysql"/>
    <property name="Oracle" value="oracle"/>
    <property name="SQL Server" value="sqlserver"/>
databaseIdProvider>

在sql映射文件中编写具体的sql语句时指定需要操作的数据库(当然这需要提前导入相应的jar包以及配置好数据库环境、数据源信息等,这样才能顺利切换需要操作的数据库)。


<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql">
	select * from tbl_employee where id = #{id}
select>

MyBatis匹配规则如下:
① 如果没有配置databaseIdProvider标签,那么databaseId=null;
② 如果配置了databaseIdProvider标签,使用标签配置的name去匹配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为null;
③ 如果databaseId不为null,他只会找到配置databaseId的sql语句;
④ MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库databaseId 属性的所有语句。如果同时找到带有 databaseId 和不带databaseId 的相同语句,则后者会被舍弃;

(7)mapper映射

mappers将写好的sql映射文件注册到全局配置中。

<mappers>
    
    <mapper resource="EmployeeMapper.xml" />
    <mapper class="com.atguigu.mybatis.dao.EmployeeMapperAnnotation"/>
    
    
    <package name="com.atguigu.mybatis.dao"/>
mappers>

注:当使用mapper中的class属性来注册接口时,不需要映射文件并且sql语句利用注解写在接口上的例子如下:

package com.atguigu.mybatis.dao;

import com.atguigu.mybatis.bean.Employee;
import org.apache.ibatis.annotations.Select;

public interface EmployeeMapperAnnotation {
    
    //直接在注解中编写sql语句,不要sql映射文件
    @Select("select * from tbl_employee where id = #{id}")
    public Employee getEmpById(Integer id);
}

以上介绍了MyBatis中常用的标签,所有的标签如下图所示。不过在使用这些标签时也需要按照下图中从上到下规定的顺序(某个标签可以没有,但如果有则顺序不能颠倒,否则会报错!!!)
MyBatis3——入门介绍_第9张图片

4.MyBatis——映射文件

映射文件指导着MyBatis如何进行数据库增删改查,有着非常重要的意义。

(1)简单的增删改查

① 在接口EmployeeMapper中编写抽象的增删改查方法

package com.atguigu.mybatis.dao;

import com.atguigu.mybatis.bean.Employee;

public interface EmployeeMapper {    
    Employee getEmpById(Integer id);    
    void addEmp(Employee employee);    
    boolean updateEmp(Employee employee);
    void deleteEmpById(Integer id);
}

② 在对应的sql映射文件EmployeeMapper.xml中编写sql语句


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">

    
    <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql">
		select * from tbl_employee where id = #{id}
	select>

    
    <insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee">
        insert into tbl_employee(last_name,email,gender)
        values (#{last_name},#{email},#{gender})
    insert>

    <update id="updateEmp">
        update tbl_employee
        set last_name=#{last_name},email=#{email},gender=#{gender}
        where id=#{id}
    update>

    <delete id="deleteEmpById">
        delete from tbl_employee where id=#{id}
    delete>
mapper>

③ 测试

/*
     * 测试增删改
     * 1、mybatis允许增删改直接定义以下类型返回值
     * 		Integer、Long、Boolean、void
     * 2、我们需要手动提交数据
     * 		sqlSessionFactory.openSession();===》手动提交
     * 		sqlSessionFactory.openSession(true);===》自动提交
     */
    @Test
    public void test04() throws IOException {
        // 1、获取sqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        // 2、获取sqlSession对象
        SqlSession openSession = sqlSessionFactory.openSession();
        try {
            // 3、获取接口的实现类对象
            //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            
            //添加数据
            Employee employee1 = new Employee(null, "Jerry", "1","[email protected]");
            mapper.addEmp(employee1);
            
            //修改数据
            Employee employee2 = new Employee(2, "Hi", "1","[email protected]");
            //若修改影响的行数大于等于1,则返回true,否则返回false
            boolean flag = mapper.updateEmp(employee2);
            System.out.println(flag);
            
            //删除数据
            mapper.deleteEmpById(2);
            
            //手动提交数据
            openSession.commit();
        }finally{
            openSession.close();
        }
    }

除此之外,insert、update、delete标签中常见的属性如下:
MyBatis3——入门介绍_第10张图片

(2)获取自增主键的值


<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id">
    insert into tbl_employee(last_name,email,gender)
    values (#{last_name},#{email},#{gender})
insert>
//添加数据
Employee employee = new Employee(null, "Jerry", "1","[email protected]");
mapper.addEmp(employee);
//输出得到的自增主键的值
System.out.println(employee.getId());

(3)获取非自增主键的值(Oracle)


<insert id="addEmp" databaseId="oracle">
	
	<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
		
		
		select EMPLOYEES_SEQ.nextval from dual 
		
	selectKey>
	
	
	
	insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
	values(#{id},#{lastName},#{email}) 
	
insert>

selectKey标签的相关属性如下:
MyBatis3——入门介绍_第11张图片

(4)参数处理——单个参数

对于单个参数,mybatis不会做特殊处理,即按照 #{参数名/任意名} 就可以取出参数值


<delete id="deleteEmpById">
    delete from tbl_employee where id=#{id}
    
delete>

(5)参数处理——多个参数

对于多个参数,mybatis会做特殊处理,即多个参数会被封装成一个map,其中key为param1…paramN(或者参数的索引),value为传入的参数值,#{x}就等于从map中获取 key 为 x 的value的值。
① 定义含有2个参数的抽象方法:

Employee getEmpByIdAndLast_name(Integer id,String last_name);

② 错误示例:按照单个参数的方式进行取值

<select id="getEmpByIdAndLast_name" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee where id=#{id} and last_name=#{last_name}
select>
@Test
public void test05() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Employee employee = mapper.getEmpByIdAndLast_name(1, "Tom");
        System.out.println(employee);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

错误提示如下:

### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [0, 1, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [0, 1, param1, param2]

③ 正确示例

<select id="getEmpByIdAndLast_name" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee where id=#{param1} and last_name=#{param2}
    
select>

(6)参数处理——命名参数

对于多个参数的处理还有另外一种方法,即命名参数,使用注解@Param明确指定封装参数时map的key

Employee getEmpByIdAndLast_name(@Param("id") Integer id,@Param("last_name") String last_name);
<select id="getEmpByIdAndLast_name" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee where id=#{id} and last_name=#{last_name}
select>

(7)参数处理——POJO & Map & TO

① 如果多个参数正好是我们业务逻辑的数据模型,那么就可以直接传入对应的POJO(Plain Old Java Objects,普通的Java对象),然后按照 #{属性名} 的方式取出传入的POJO的属性值。

 boolean updateEmp(Employee employee);
<update id="updateEmp">
    update tbl_employee
    set last_name=#{last_name},email=#{email},gender=#{gender}
    where id=#{id}
update>

② 如果多个参数不是业务模型中的数据,没有对应的pojo,为了方便,可以传入map。

Employee getEmpByMap(Map<String,Object> map);
<select id="getEmpByMap" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee where id=#{id} and last_name=#{last_name}
select>
@Test
public void test05() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Map<String,Object> map = new HashMap<>();
        map.put("id",1);
        map.put("last_name","Tom");
        Employee employee = mapper.getEmpByMap(map);
        System.out.println(employee);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

③ 如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)来数据传输对象。
例如对于数据的分页处理,我们可以单独定义一个Page类,里面自定义需要的属性,其用法与POJO类似。

(8)参数处理——参数封装扩展思考

public Employee getEmp(@Param(“id”)Integer id,String last_name); 取值:id==>#{id/param1} last_name==>#{param2}
public Employee getEmp(Integer id, @Param(“e”)Employee emp); 取值:id==>#{param1} last_name===>#{param2.last_name/e.last_name}
如果是Collection(List、Set)类型或者是数组,也会特殊处理,也是把传入的list或者数组封装在map中 key:Collection(collection)
如果是List数组 使用这个key(list)数组(array)
public Employee getEmpById(List ids); 取值:取出第一个id的值: #{list[0]}

(9)参数处理——#与&取值的区别

#{ } 与 ${ }都可以获取map中的值或者pojo对象属性的值
② 在具体的细节上#{ } 与 ${ }有一些不同:

#{ } 是以预编译的形式,将参数设置到 sql 语句中,可以防止 sql 注入
${ } 取出的值直接拼装在 sql 语句中,可能会存在安全问题

MyBatis3——入门介绍_第12张图片
③ 在大多情况下,我们应该使用 #{ } 去取参数的值,但是在一些特殊情况下需要使用 ${ }:

# 在原生JDBC不支持占位符的地方,就可以使用${}进行取值,例如分表、排序等
select * from ${year}_salary where xxx;
select * from ${tbl_name} where id=${id} and last_name=#{last_name};

(10)Select

Select标签用来定义查询操作,常用的属性如下:

id 唯一标识符,用来引用这条语句,需要和接口的方法名一致
parameterType 参数类型,可以不传,MyBatis会根据TypeHandler自动推断
resultType 返回值类型,别名或者全类名,如果返回的是集合,定义集合中元素的类型,不能和resultMap同时使用
其余属性如下:
MyBatis3——入门介绍_第13张图片

① 返回值类型为List

List<Employee> getEmpsByLast_NameLike(String last_name);

<select id="getEmpsByLast_NameLike" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee where last_name like #{last_name}
select>
@Test
public void test06() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        //查询姓名中含有字母e的所有员工
        List<Employee> emps = mapper.getEmpsByLast_NameLike("%e%");
        System.out.println(emps);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

② 记录封装map

1)返回一条记录的map,key为列名,value为对应的值

Map<String,Object> getEmpByIdReturnMap(Integer id);
<select id="getEmpByIdReturnMap" resultType="map">
    select * from tbl_employee where id=#{id}
select>
@Test
public void test06() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Map<String, Object> map = mapper.getEmpByIdReturnMap(1);
        System.out.println(map);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

2)多条记录封装一个map:Map,键是这条记录的主键,值是记录封装后的javaBean

//@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key
@MapKey("id")
Map<String, Employee> getEmpByLast_NameLikeReturnMap(String last_name);
<select id="getEmpByLast_NameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee where last_name like #{last_name}
select>
@Test
public void test06() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Map<String, Employee> map = mapper.getEmpByLast_NameLikeReturnMap("%r%");
        System.out.println(map);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

③ resultMap——自定义结果映射规则

package com.atguigu.mybatis.dao;

import com.atguigu.mybatis.bean.Employee;

public interface EmployeeMapperPlus{

    Employee getEmpById(Integer id);
}

注:记得要在MyBatis全局配置文件(mybatis-config.xml)中注册新的sql映射文件!


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperPlus">
    
    <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmp">
        
        <id column="id" property="id"/>
        
        <result column="last_name" property="last_name"/>
        
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
    resultMap>

    
    <select id="getEmpById" resultMap="MyEmp">
        select  * from tbl_employee where id=#{id}
    select>
mapper>

④ resultMap——关联查询_环境搭建

1)创建一张新的表 tbl_dept

create table tbl_dept(
	id INT(11) primary key AUTO_INCREMENT,
	departmentName VARCHAR(255)
)

2)为表 tbl_employee 加上一列,用来存储员工所在的部门id

alter table tbl_employee add COLUMN d_id INT(11);

3)将表 tbl_employee 中的字段d_id(员工所在的部门id)设置为外键

ALTER TABLE tbl_employee add CONSTRAINT fk_emp_dept FOREIGN key(d_id) REFERENCES tbl_dept(id);

4)创建部门类Department

package com.atguigu.mybatis.bean;

public class Department {
    
    private Integer id;
    private String departmentName;
    
    public Integer getId() {
        return id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    
    public String getDepartmentName() {
        return departmentName;
    }
    
    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }
    
    @Override
    public String toString() {
        return "Department{" +
                "id=" + id +
                ", departmentName='" + departmentName + '\'' +
                '}';
    }
}

5)在Employee.java中添加新的属性(即员工所在的部门Department),并添加对应的 get/set 方法

private Department dept;

public Department getDept() {
    return dept;
}

public void setDept(Department dept) {
    this.dept = dept;
}

⑤ resultMap——级联属性封装结果

//EmployeeMapperPlus.java
Employee getEmpAndDept(Integer id);



<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp">
    <id column="id" property="id"/>
    <result column="last_name" property="last_name"/>
    <result column="gender" property="gender"/>
    <result column="email" property="email"/>
    <result column="did" property="dept.id"/>
    <result column="deptName" property="dept.deptName"/>
resultMap>

<select id="getEmpAndDept" resultMap="MyDifEmp">
    SELECT e.id id,e.last_name last_name,e.gender gender,e.email email,e.d_id d_id,
           d.id did,d.deptName deptName
    FROM tbl_employee e,tbl_dept d
    WHERE e.d_id=d.id AND e.id=#{id}
select>
@Test
public void test06() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class);
        Employee employee = mapper.getEmpAndDept(1);
        System.out.println(employee);
        System.out.println(employee.getDept());
        openSession.commit();
    }finally{
        openSession.close();
    }
}

⑥ resultMap——association定义关联对象封装规则


<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2">
    <id column="id" property="id"/>
    <result column="last_name" property="last_name"/>
    <result column="gender" property="gender"/>
    <result column="email" property="email"/>
    
    <association property="dept" javaType="com.atguigu.mybatis.bean.Department">
        <id column="did" property="id"/>
        <result column="deptName" property="deptName"/>
    association>
resultMap>

⑦ resultMap——association分步查询 & 延迟加载

1)新建DepartmentMapper.java,并定义抽象方法getDeptById()。

package com.atguigu.mybatis.dao;

import com.atguigu.mybatis.bean.Department;

public interface DepartmentMapper {
    //根据部门id查询部门信息
    Department getDeptById(Integer id);
}

2)新建对应的sql映射文件(记得要在MyBatis全局配置文件(mybatis-config.xml)中注册)。


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.dao.DepartmentMapper">

    
    <select id="getDeptById" resultType="com.atguigu.mybatis.bean.Department">
        select id,deptName from tbl_dept where id=#{id}
    select>
mapper>

3)在EmployeeMapperPlus.java中增加抽象方法getEmpByIdStep()。

//EmployeeMapperPlus.java
Employee getEmpByIdStep(Integer id);

4)在EmployeeMapperPlus.xml中编写对应的sql语句。




<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep">
    <id column="id" property="id"/>
    <result column="last_name" property="last_name"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
    
    <association property="dept"
                 select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
                 column="d_id">
    association>
resultMap>

<select id="getEmpByIdStep" resultMap="MyEmpByStep">
    select * from tbl_employee where id=#{id}
select>

5)测试

@Test
public void test06() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class);
        //分步查询
        Employee employee = mapper.getEmpByIdStep(1);
        System.out.println(employee);
        System.out.println(employee.getDept());
        openSession.commit();
    }finally{
        openSession.close();
    }
}

6)延迟加载——在MyBatis全局配置文件(mybatis-config.xml)中加上两个设置
MyBatis3——入门介绍_第14张图片

<settings>
    
    
    
    
    <setting name="lazyLoadingEnabled" value="true"/>
    
    <setting name="aggressiveLazyLoading" value="false"/>
    
    
settings>

⑧ resultMap——collection定义关联集合封装规则

1)在Department.java中添加属于该部门的所有员工的集合List,并添加相应的 get/set 方法。

package com.atguigu.mybatis.bean;

import java.util.List;

public class Department {
    
    private Integer id;
    private String deptName;
    private List<Employee> emps;
    
    public List<Employee> getEmps() {
        return emps;
    }
    
    public void setEmps(List<Employee> emps) {
        this.emps = emps;
    }
    
    public Integer getId() {
        return id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    
    
    public String getDeptName() {
        return deptName;
    }
    
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    
    @Override
    public String toString() {
        return "Department{" +
                "id=" + id +
                ", deptName='" + deptName + '\'' +
                '}';
    }
}

2)在EmployeeMapperPlus.java中添加抽象方法getDeptByIdPlus()。

//EmployeeMapperPlus.java
//通过部门id查询部门信息,以及属于该部门的所有员工的集合List
Department getDeptByIdPlus(Integer id);

3)在DepartmentMapper.xml中编写上述方法对应的sql语句。



<resultMap id="MyDept" type="com.atguigu.mybatis.bean.Department">
    <id column="did" property="id"/>
    <result column="deptName" property="deptName"/>
    
    <collection property="emps" ofType="com.atguigu.mybatis.bean.Employee">
        
        <id column="eid" property="id"/>
        <result column="last_name" property="last_name"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
    collection>
resultMap>

<select id="getDeptByIdPlus" resultMap="MyDept">
    select d.id did,d.deptName deptName,
           e.id eid,e.last_name last_name,e.email email,e.gender gender
    from tbl_dept d
    left join tbl_employee e
    on d.id=e.d_id
    where d.id=#{id};
select>

4)测试

 @Test
public void test07() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);
        //查询部门id为1的部门信息,以及属于该部门的所有员工信息(在list中)
        Department dept = mapper.getDeptByIdPlus(1);
        //输出部门信息
        System.out.println(dept);
        //输出属于该部门的所有员工信息
        System.out.println(dept.getEmps());
        openSession.commit();
    }finally{
        openSession.close();
    }
}

在这里插入图片描述

⑨ resultMap——collection分步查询 & 延迟加载

1)在EmployeeMapperPlus.java中添加抽象方法getEmpsByDeptId()。

//EmployeeMapperPlus.java
//根据部门id查询所有属于该部门的员工信息
List<Employee> getEmpsByDeptId(Integer deptId);

2)在EmployeeMapperPlus.xml中编写对应的sql语句。


<select id="getEmpsByDeptId" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee where d_id=#{deptId};
select>

3)在DepartmentMapper.java中添加抽象的分步查询方法getDeptByIdStep()。

//DepartmentMapper.java
//通过部门id查询部门信息,以及属于该部门的所有员工的集合List(分步查询)
Department getDeptByIdStep(Integer id);

4)在DepartmentMapper.xml中编写对应的sql语句。


<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDeptStep">
    <id column="id" property="id"/>
    <id column="deptName" property="deptName"/>
    <collection property="emps"
                select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
                column="id">collection>
resultMap>

<select id="getDeptByIdStep" resultMap="MyDeptStep">
    select id,deptName from tbl_dept where id=#{id}
select>

5)扩展——传递多列值
在collection分步查询时,其中column表示需要传递的参数,当只有一个参数时,直接写进去即可:
在这里插入图片描述
当需要传递多个参数时,选需要将多列的值封装在map中进行传递,column=“{key1=column1,key2=column2}”:
在这里插入图片描述
6)扩展——延迟加载
fetchType=“lazy”:表示使用延迟加载,fetchType=“eager”:表示使用立即加载。(该设置可以覆盖掉全局配置文件中的延迟加载)
测试代码:

@Test
public void test07() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);
        Department dept = mapper.getDeptByIdStep(1);
        System.out.println(dept.getDeptName());
        System.out.println(dept.getEmps());
        openSession.commit();
    }finally{
        openSession.close();
    }
}

测试对比:
MyBatis3——入门介绍_第15张图片
MyBatis3——入门介绍_第16张图片

⑩ resultMap——discriminator鉴别器

在EmployeeMapper.xml中添加鉴别器



<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis">
    <id column="id" property="id"/>
    <result column="last_name" property="last_name"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
    
    <discriminator javaType="string" column="gender">
        
        <case value="0" resultType="com.atguigu.mybatis.bean.Employee">
            <association property="dept"
                         select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
                         column="d_id">
            association>
        case>
        
        <case value="1" resultType="com.atguigu.mybatis.bean.Employee">
            <id column="id" property="id"/>
            <result column="last_name" property="last_name"/>
            <result column="last_name" property="email"/>
            <result column="gender" property="gender"/>
        case>
    discriminator>
resultMap>

5.MyBatis——动态SQL

(1)简介 & 环境搭建

① 动态 SQL是MyBatis强大特性之一,它极大地简化拼装SQL的操作,动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。此外,MyBatis 采用了功能强大的基于 OGNL 的表达式来简化操作。
② 环境搭建
新建EmployeeMapperDynamicSQL.java

package com.atguigu.mybatis.dao;

public interface EmployeeMapperDynamicSQL {

}

新建EmployeeMapperDynamicSQL.xml(记得要在全局配置文件中注册该sql映射文件!


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    
mapper>

(2)动态SQL标签——if

① 在EmployeeMapperDynamicSQL.java中添加抽象方法

//携带了哪个字段查询条件就带上这个字段的值
List<Employee> getEmpsByConditionIf(Employee employee);

② 在EmployeeMapperDynamicSQL.xml中编写对应的sql语句


<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee
    where 1=1
    
    <if test="id!=null">
        and id=#{id}
    if>
    <if test="last_name!=null and last_name!=''">
        and last_name like #{last_name}
    if>
    <if test="email!=null and email.trim()!=''">
        and email=#{email}
    if>
    
    <if test="gender==0 or gender==1">
        and gender=#{gender}
    if>
select>

③ 测试

@Test
public void testDynamicSQL() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
        Employee employee = new Employee(null,"%e%",null,null);
        List<Employee> emps = mapper.getEmpsByConditionIf(employee);
        System.out.println(emps);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

在这里插入图片描述

(3)动态SQL标签——where

查询的时候如果某些条件没带可能会出现sql拼装问题,现有以下两种解决方案:
① 给where后面加上1=1,以后的条件都是and xxx(上面(2)中的代码就是这样写的)。
② MyBatis使用 where 标签来将所有的查询条件包括在内。即在where标签拼装sql语句,并且会去掉多出来的and或者or,但是where只会去掉第一个多出来的and或者or


<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee
    <where>
        <if test="id!=null">
            id=#{id}
        if>
        <if test="last_name!=null and last_name!=''">
            and last_name like #{last_name}
        if>
        <if test="email!=null and email.trim()!=''">
            and email=#{email}
        if>
        
        <if test="gender==0 or gender==1">
            and gender=#{gender}
        if>
    where>
select>

(3)动态SQL标签——trim

① 在EmployeeMapperDynamicSQL.java中添加抽象方法

List<Employee> getEmpsByConditionTrim(Employee employee);

② 在EmployeeMapperDynamicSQL.xml中编写对应的sql语句


<select id="getEmpsByConditionTrim" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee
    
    
    <trim prefix="where" suffixOverrides="and">
        <if test="id!=null">
            id=#{id} and
        if>
        <if test="last_name!=null and last_name!=''">
            last_name like #{last_name} and
        if>
        <if test="email!=null and email.trim()!=''">
            email=#{email} and
        if>
        
        <if test="gender==0 or gender==1">
            gender=#{gender}
        if>
    trim>
select>

(4)动态SQL标签——choose

① 在EmployeeMapperDynamicSQL.java中添加抽象方法

//如果带了id就用id查,如果带了last_name就用last_name查,只会进入其中一个
List<Employee> getEmpsByConditionChoose(Employee employee);

② 在EmployeeMapperDynamicSQL.xml中编写对应的sql语句


<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee
    <where>
        
        <choose>
            <when test="id!=null">
                id=#{id}
            when>
            <when test="last_name!=null">
                last_name like #{last_name}
            when>
            <when test="email!=null">
                email = #{email}
            when>
            <otherwise>
                gender = 0
            otherwise>
        choose>
    where>
select>

(5)动态SQL标签——set(与if结合的动态更新)

① 在EmployeeMapperDynamicSQL.java中添加抽象方法

//更新employee中不为空的属性(列),即哪列有值就更新哪列(id主键必须有值)
void updateEmp(Employee employee);

② 在EmployeeMapperDynamicSQL.xml中编写对应的sql语句


<update id="updateEmp">
    update tbl_employee
    
    <set>
        <if test="last_name!=null">
            last_name=#{last_name},
        if>
        <if test="email!=null">
            email=#{email},
        if>
        <if test="gender!=null">
            gender=#{gender}
        if>
    set>
    where id=#{id}
update>

(6)动态SQL标签——foreach遍历集合

① 在EmployeeMapperDynamicSQL.java中添加抽象方法

//查询所有id在给定集合中的员工
List<Employee> getEmpsByConditionForeach(@Param("ids")List<Integer> ids);

② 在EmployeeMapperDynamicSQL.xml中编写对应的sql语句


<select id="getEmpsByConditionForeach" resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee
    
    <foreach collection="ids" item="item_id" separator=","
             open="where id in(" close=")">
        #{item_id}
    foreach>
select>

③ 测试

@Test
public void testDynamicSQL() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
        Employee employee = new Employee(null,null,null,null);
        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        ids.add(3);
        List<Employee> emps = mapper.getEmpsByConditionForeach(ids);
        for (Employee emp : emps) {
            System.out.println(emp);
        }
        openSession.commit();
    }finally{
        openSession.close();
    }
}

在这里插入图片描述

(7)动态SQL标签——mysql下foreach批量插入的两种方式

① 在EmployeeMapperDynamicSQL.java中添加抽象方法

//批量插入员工信息
void addEmps(@Param("emps")List<Employee> emps);

② 在EmployeeMapperDynamicSQL.xml中编写对应的sql语句

<!-- 
	批量保存 
	
-->

<insert id="addEmps">
	insert into tbl_employee(last_name, email, gender,d_id)
	values
	<foreach collection="emps" item="emp" separator=",">
	    (#{emp.last_name},#{emp.email},#{emp.gender},#{emp.dept.id})
	foreach>
insert>



<insert id="addEmps">
	<foreach collection="emps" item="emp" separator=";">
		insert into tbl_employee(last_name,email,gender,d_id)
		values(#{emp.last_name},#{emp.email},#{emp.gender},#{emp.dept.id})
	foreach>
insert>

③ 测试

@Test
public void testBatchSave() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
        List<Employee> emps = new ArrayList<>();
        emps.add(new Employee(null,"Smith","1","[email protected]",new Department(1)));
        emps.add(new Employee(null,"Smith2","1","[email protected]",new Department(2)));
       9 mapper.addEmps(emps);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

(8)动态SQL标签——内置参数_parameter和_databaseId

① 在EmployeeMapperDynamicSQL.java中添加抽象方法

List<Employee> getEmpsTestInnerParameter(Employee employee);

② 在EmployeeMapperDynamicSQL.xml中编写对应的sql语句


<select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
    <if test="_databaseId=='mysql'">
        select * from tbl_employee
        <if test="_parameter!=null">
            where last_name like #{_parameter.last_name}
        if>
    if>
    <if test="_databaseId=='oracle'">
        select * from tbl_employee
    if>
select>

(9)动态SQL标签——bind绑定

bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值。以上面的sql语句为例:


<select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
    
    <bind name="_lastName" value="'%'+last_name+'%'"/>
    <if test="_databaseId=='mysql'">
        select * from tbl_employee
        <if test="_parameter!=null">
            where last_name like #{_lastName}
        if>
    if>
    <if test="_databaseId=='oracle'">
        select * from tbl_employee
    if>
select>

测试代码如下:

@Test
public void testBind() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
        Employee employee = new Employee();
        employee.setLast_name("e");
        List<Employee> emps = mapper.getEmpsTestInnerParameter(employee);
        System.out.println(emps);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

(10)动态SQL标签——抽取可重用的sql片段

抽取可重用的sql片段,方便后面引用
① sql抽取:将经常要查询的列名,或者插入用的列名抽取出来,方便引用;
② 用include来引用已经抽取的sql;
③ 此外,include还可以自定义一些property,sql标签内部就能使用自定义的属性;include-property:正确的取值方式为${prop}

<sql id="insertColumn">
	<if test="_databaseId=='oracle'">
		employee_id,last_name,email
	if>
	<if test="_databaseId=='mysql'">
		last_name,email,gender,d_id
	if>
sql>
<insert id="addEmps">
	insert into tbl_employee(<include refid="insertColumn">include>) 
	values
	<foreach collection="emps" item="emp" separator=",">
		(#{emp.last_name},#{emp.email},#{emp.gender},#{emp.dept.id})
	foreach>
insert>

6.MyBatis——缓存机制

(1)缓存介绍

MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存极大地提升了查询效率。MyBatis中默认定义了两级缓存,即一级缓存和二级缓存。

① 一级缓存

一级缓存(local cache),即本地缓存,作用域默认为sqlSession。当 Session flush 或 close 后,该Session 中的所有 Cache 将被清空。除此之外,本地缓存不能被关闭,但是可以调用 clearCache() 来清空本地缓存,或者改变缓存的作用域。

② 二级缓存

二级缓存(second level cache),即全局作用域缓存,它是基于namespace级别的缓存,一个namespace对应一个二级缓存。二级缓存在默认情况下不开启,若要开启则需要手动配置。MyBatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口。
二级缓存的工作机制如下:
1)一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
2)如果会话关闭,一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;
3)不同namespace查出的数据会放在自己对应的缓存中(map)
4)查出的数据都会被默认先放在一级缓存中,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中,那么此时的效果就是数据会从二级缓存中获取。

(2)一级缓存体验

同一次会话期间只要查询过的数据都会保存在当前SqlSession的一个Map中。

@Test
public void testFirstLevelCache() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Employee emp01 = mapper.getEmpById(1);
        System.out.println(emp01);
        //xxx
        //再次调用getEmpById()方法
        Employee emp02 = mapper.getEmpById(1);
        System.out.println(emp02);
        //判断emp01和emp02是否为同一个对象
        System.out.println(emp01==emp02);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

MyBatis3——入门介绍_第17张图片

(3)一级失效的四种情况

① 不同的SqlSession对应不同的一级缓存
② 同一个SqlSession但是查询条件不同
③ 两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
④ 同一个SqlSession两次查询期间手动清空了缓存(openSession.clearCache())

(4)二级缓存的使用

① 在全局配置文件 mybatis-config.xml 中开启全局二级缓存配置:

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

② 去相应的mapper.xml(以EmployeeMapper.xml为例)中配置使用二级缓存:


<cache eviction="FIFO" flushInterval="" readOnly="false" size="1024">cache>

③ 相应的POJO(Employee.java、Department.java)需要实现序列化接口
在这里插入图片描述
在这里插入图片描述
④ 测试

@Test
public void testSecondLevelCache() throws IOException {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession openSession = sqlSessionFactory.openSession();
    SqlSession openSession2 = sqlSessionFactory.openSession();
    try {
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);

        Employee emp01 = mapper.getEmpById(1);
        System.out.println(emp01);
        //会话关闭,那么一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存中的内容
        openSession.close();

        //第二次查询是从二级缓存中拿到的数据,并没有发送新的sql
        Employee emp02 = mapper2.getEmpById(1);
        System.out.println(emp02);
        System.out.println(emp01==emp02);
        openSession.close();
        
    }finally{
    
    }
}

MyBatis3——入门介绍_第18张图片

(5)缓存有关的设置/属性

全局setting的cacheEnable 配置二级缓存的开关,true为打开,false为关闭(一级缓存一直是打开的)
全局setting的localCacheScope 值为SESSION时,当前会话的所有数据保存在会话缓存中;值为STATEMENT时,禁用一级缓存
select标签的useCache属性 配置这个select是否使用二级缓存,true为使用,false为不使用(一级缓存一直是使用的 )
sql标签的flushCache属性 在增删改标签中默认flushCache=true,即sql执行以后,会同时清空一级和二级缓存。在查询标签中则默认flushCache=false
sqlSession.clearCache() 只用来清除当前sqlSession一级缓存

(6)缓存原理图示

MyBatis3——入门介绍_第19张图片

(7)第三方缓存整合——ehcache

① 导入ehcache适配包

MyBatis3——入门介绍_第20张图片
MyBatis3——入门介绍_第21张图片

② 在config目录下添加ehcache.xml文件


<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
 
 <diskStore path="E:\ehcache" />
 
 <defaultCache 
   maxElementsInMemory="10000"
   maxElementsOnDisk="10000000"
   eternal="false" 
   overflowToDisk="true" 
   timeToIdleSeconds="120"
   timeToLiveSeconds="120" 
   diskExpiryThreadIntervalSeconds="120"
   memoryStoreEvictionPolicy="LRU">
 defaultCache>
ehcache>

③ 在EmployeeMapper.xml文件中进行配置

<cache type="org.mybatis.caches.ehcache.EhcacheCache">cache>

④ 测试

@Test
public void testSecondLevelCache() throws IOException {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession openSession = sqlSessionFactory.openSession();
    SqlSession openSession2 = sqlSessionFactory.openSession();
    try {
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);

        Employee emp01 = mapper.getEmpById(1);
        System.out.println(emp01);
        openSession.close();

        //第二次查询是从二级缓存中拿到的数据,并没有发送新的sql
        Employee emp02 = mapper2.getEmpById(1);
        System.out.println(emp02);
        System.out.println("emp01==emp02的结果为:"+(emp01==emp02));
        openSession.close();
    }finally{
    
    }
}

MyBatis3——入门介绍_第22张图片
MyBatis3——入门介绍_第23张图片

⑤ 扩展——引用缓存

在DepartmentMapper.xml中引用缓存


<cache-ref namespace="com.atguigu.mybatis.dao.EmployeeMapper"/>

7.MyBatis——SSM框架整合

此处的SSM框架整合未使用Maven等项目管理工具,若想看Maven版本的可以查看这篇文章。

(1)在IDEA中新建一个Java Web项目

MyBatis3——入门介绍_第24张图片
MyBatis3——入门介绍_第25张图片
MyBatis3——入门介绍_第26张图片

(2)导入需要的jar包

MyBatis3——入门介绍_第27张图片
右键lib,点击"Add as Library…",再点击OK即可。

(3)进行各种配置以及代码的编写

整体的项目结构如下:
MyBatis3——入门介绍_第28张图片
有需要的可以下载本项目的源代码(提取码:test)

(4)测试

MyBatis3——入门介绍_第29张图片
MyBatis3——入门介绍_第30张图片

8.MyBatis——逆向工程

(1)MyBatis Generator

MyBatis Generator简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件、接口、以及bean类等。它支持基本的增删改查,以及QBC风格的条件查询。但是表连接、存储过程等这些复杂sql的定义需要我们手工编写。

(2)编写相应的配置文件及代码

① 将之前Mybatis项目复制一份并改名为MyBatis_07_mbg,删除一些不用的文件,并导入Myabtis Generator的包:
MyBatis3——入门介绍_第31张图片
② 新建mbg.xml文件,放在src目录下(可以先从官网中复制过来,然后再根据实际情况进行修改)


DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>

    
    <context id="DB2Tables" targetRuntime="MyBatis3">
        
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true"
                        userId="root"
                        password="123456">
        jdbcConnection>

        
        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        javaTypeResolver>

        
        <javaModelGenerator targetPackage="com.atguigu.mybatis.bean"
                            targetProject=".\src">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        javaModelGenerator>

        
        <sqlMapGenerator targetPackage="com.atguigu.mybatis.dao"
                         targetProject=".\conf">
            <property name="enableSubPackages" value="true" />
        sqlMapGenerator>

        
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.dao"
                             targetProject=".\src">
            <property name="enableSubPackages" value="true" />
        javaClientGenerator>

        
        <table tableName="tbl_dept" domainObjectName="Department">table>
        <table tableName="tbl_employee" domainObjectName="Employee">table>
    context>
generatorConfiguration>

③ 使用MyBatis逆向工程生成相应的代码及配置,即运行下面官网提供的代码:

@Test
public void testMbg() throws Exception {
    List<String> warnings = new ArrayList<String>();
    boolean overwrite = true;
    File configFile = new File("mbg.xml");
    ConfigurationParser cp = new ConfigurationParser(warnings);
    Configuration config = cp.parseConfiguration(configFile);
    DefaultShellCallback callback = new DefaultShellCallback(overwrite);
    MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
            callback, warnings);
    myBatisGenerator.generate(null);
}

④ 测试

@Test
public void testMyBatis3() throws IOException{
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession openSession = sqlSessionFactory.openSession();
    try{
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        //xxxExample就是封装查询条件的
        //1、查询所有
        //List emps = mapper.selectByExample(null);
        //2、查询员工名字中有e字母的,和员工性别是1的
        //封装员工查询条件的example
        EmployeeExample example = new EmployeeExample();
        //创建一个Criteria,这个Criteria就是拼装查询条件
        //select id, last_name, email, gender, d_id from tbl_employee 
        //WHERE ( last_name like ? and gender = ? ) or email like "%e%"
        Criteria criteria = example.createCriteria();
        criteria.andLastNameLike("%e%");
        criteria.andGenderEqualTo("1");
        
        Criteria criteria2 = example.createCriteria();
        criteria2.andEmailLike("%e%");
        example.or(criteria2);
        
        List<Employee> list = mapper.selectByExample(example);
        for (Employee employee : list) {
            System.out.println(employee.getId());
        }
        
    }finally{
        openSession.close();
    }
}

9.MyBatis——工作原理

(1)框架分层架构

MyBatis3——入门介绍_第32张图片
MyBatis3——入门介绍_第33张图片

(2)入门案例的运行流程

MyBatis3——入门介绍_第34张图片
MyBatis3——入门介绍_第35张图片
MyBatis3——入门介绍_第36张图片
MyBatis3——入门介绍_第37张图片

10.MyBatis——插件开发

(1)插件原理

MyBatis在四大对象Executor、ParameterHandler、ResultSetHandler、StatementHandler的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。
① 每个创建出来的对象不是直接返回的,而是调用方法 interceptorChain.pluginAll(parameterHandler) 后返回。

public Object pluginAll(Object target) {
	for (Interceptor interceptor : interceptors) {
		target = interceptor.plugin(target);
	}
	return target;
}

② pluginAll() 方法获取到所有的Interceptor(拦截器,插件需要实现的接口)后,调用interceptor.plugin(target),即返回target包装后的对象。
③ 插件机制,我们可以使用插件为目标对象创建一个代理对象(即AOP,面向切面编程),我们的插件可以为四大对象创建出代理对象,代理对象就可以拦截到四大对象的每一个执行。

(2)编写插件

以入门案例的代码为基础来编写插件,其具体步骤如下:
① 编写Interceptor的实现类
② 使用@Intercepts注解完成插件签名

package com.atguigu.mybatis.dao;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;

import java.util.Properties;

//完成插件签名:告诉MyBatis当前插件用来拦截哪个对象的哪个方法
@Intercepts(
{
    @Signature(type= StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
})
public class MyFirstPlugin implements Interceptor {
    
    //intercept:拦截目标对象的目标方法的执行
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //执行目标方法
        Object proceed = invocation.proceed();
        //返回执行后的返回值
        return null;
    }
    
    //plugin:包装目标对象的,包装:为目标对象创建一个代理对象
    @Override
    public Object plugin(Object target) {
        //我们可以借助Plugin的wrap方法来使用当前Interceptor包装我们目标对象
        System.out.println("MyFirstPlugin...plugin:mybatis将要包装的对象"+target);
        Object wrap = Plugin.wrap(target, this);
        //返回为当前target创建的动态代理
        return wrap;
    }
    
    //setProperties:将插件注册时的property属性设置进来
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的信息:"+properties);
    }
}

③ 将写好的插件注册到全局配置文件mybatis-config中


<plugins>
    <plugin interceptor="com.atguigu.mybatis.dao.MyFirstPlugin">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    plugin>
plugins>

④ 运行任意一个测试方法

@Test
public void test02() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类对象
        //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Employee employee = mapper.getEmpById(1);
        System.out.println(mapper.getClass());
        System.out.println(employee);
    }finally{
        openSession.close();
    }
}

MyBatis3——入门介绍_第38张图片

(3)多个插件运行流程

① 编写第二个插件

package com.atguigu.mybatis.dao;

import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;

@Intercepts(
{
    @Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
})
public class MySecondPlugin implements Interceptor{
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MySecondPlugin...intercept:"+invocation.getMethod());
        return invocation.proceed();
    }
    
    @Override
    public Object plugin(Object target) {
        // TODO Auto-generated method stub
        System.out.println("MySecondPlugin...plugin:"+target);
        return Plugin.wrap(target, this);
    }
    
    @Override
    public void setProperties(Properties properties) {
        // TODO Auto-generated method stub
    }
}

② 注册插件


<plugins>
    <plugin interceptor="com.atguigu.mybatis.dao.MyFirstPlugin">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    plugin>
    <plugin interceptor="com.atguigu.mybatis.dao.MySecondPlugin">plugin>
plugins>

③ 测试运行
MyBatis3——入门介绍_第39张图片
MyBatis3——入门介绍_第40张图片

(4)开发插件

@Override
public Object intercept(Invocation invocation) throws Throwable {
	// TODO Auto-generated method stub
	System.out.println("MyFirstPlugin...intercept:"+invocation.getMethod());
	
	//动态的改变一下sql运行的参数:以前1号员工,实际从数据库查询3号员工
	
	Object target = invocation.getTarget();
	System.out.println("当前拦截到的对象:"+target);
	//拿到:StatementHandler==>ParameterHandler===>parameterObject
	//拿到target的元数据
	MetaObject metaObject = SystemMetaObject.forObject(target);
	Object value = metaObject.getValue("parameterHandler.parameterObject");
	System.out.println("sql语句用的参数是:"+value);
	//修改完sql语句要用的参数
	metaObject.setValue("parameterHandler.parameterObject", 3);
	//执行目标方法
	Object proceed = invocation.proceed();
	//返回执行后的返回值
	return proceed;
}

(5)PageHelper分页插件的使用

① PageHelper插件官网地址
② 以入门案例的代码为例,在其基础上使用PageHelper插件。
1)导入需要的 jar 包
MyBatis3——入门介绍_第41张图片
2)在全局配置文件mybatis-config中注册pageHelper插件


<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
plugins>

3)测试使用

@Test
public void testPageHelper01() throws IOException {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        //查询第1页的5条记录
        Page<Object> page = PageHelper.startPage(1, 5);
        List<Employee> emps = mapper.getEmps();
        for (Employee emp : emps) {
            System.out.println(emp);
        }
        System.out.println("当前页码:"+page.getPageNum());
        System.out.println("总记录数:"+page.getTotal());
        System.out.println("每页的记录数:"+page.getPageSize());
    }finally{
        openSession.close();
    }
}

MyBatis3——入门介绍_第42张图片

@Test
public void testPageHelper02() throws IOException {
    // 1、获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    // 2、获取sqlSession对象
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        //查询第5页的1条记录
        Page<Object> page = PageHelper.startPage(5, 1);
    
        List<Employee> emps = mapper.getEmps();
        //传入要连续显示多少页
        PageInfo<Employee> info = new PageInfo<>(emps, 5);
        for (Employee employee : emps) {
            System.out.println(employee);
        }
        System.out.println("当前页码:"+info.getPageNum());
        System.out.println("总记录数:"+info.getTotal());
        System.out.println("每页的记录数:"+info.getPageSize());
        System.out.println("总页码:"+info.getPages());
        System.out.println("是否第一页:"+info.isIsFirstPage());
        
        int[] nums = info.getNavigatepageNums();
        System.out.println("连续显示的页码:");
        //当前页码为第5页,在连续显示时,当前页码居中
        for (int i = 0; i < nums.length; i++) {
            System.out.println(nums[i]);
        }
    } finally {
        openSession.close();
    }
}

MyBatis3——入门介绍_第43张图片

11.Mybatis扩展

(1)批量操作

以入门案例的代码为例,在其基础上进行批量操作。
① 在EmployeeMapper.java中添加抽象方法

Long addEmp(Employee employee);

② 在EmployeeMapper.xml编写对应的sql语句


<insert id="addEmp">
    insert into tbl_employee(last_name, gender, email)
    values (#{last_name},#{gender},#{email})
insert>

③ 测试

@Test
public void testBatch() throws IOException {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    //可以执行批量操作的sqlSession
    SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    long start = System.currentTimeMillis();
    try{
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        //插入1000条数据
        for (int i = 0; i < 1000; i++) {
            String last_name = UUID.randomUUID().toString().substring(0, 5);
            mapper.addEmp(new Employee(last_name, last_name+"@163.com", "1"));
        }
        openSession.commit();
        long end = System.currentTimeMillis();
        //批量:(预编译sql一次==>设置参数===>10000次===>执行(1次))
        //Parameters: 616c1(String), [email protected](String), 1(String)==>4598
        //非批量:(预编译sql=设置参数=执行)==》10000    10200
        System.out.println("执行时长:"+(end-start)+"毫秒");
    }finally{
        openSession.close();
    }
}

MyBatis3——入门介绍_第44张图片
④ 与Spring整合中,推荐额外的配置一个可以专门用来执行批量操作的sqlSession


<bean id="sqlSession" class="org.mybatis.spring.sqLSessionTemplate">
	<constructor-arg name="sqLSessionFactory" ref= "sqLSessionFactoryBean">constructor-arg>
	<constructor-arg name="executorType" value="BATCH">constructor-arg>
bean>

需要用到批量操作的时候,可以注入配置的这个批量SqlSession,通过它获取到mapper映射器进行操作即可。

(2)自定义类型处理器——MyBatis中枚举类型的默认处理

① 创建枚举类EmpStatus,然后在Employee.java中将该类作为其属性并构建 get/set 方法。

package com.atguigu.mybatis.bean;

public enum EmpStatus {
    //员工状态
    LOGIN,LOGOUT,REMOVE
}
//员工状态
private EmpStatus empStatus=EmpStatus.LOGOUT;

② 在表tbl_employee中新增一列,表示员工状态,同时也需要改变aEmployeeMapper.xml中对应的sql语句

alter table tbl_employee add empStatus varchar(11)

<insert id="addEmp">
    insert into tbl_employee(last_name, gender, email,empStatus)
    values (#{last_name},#{gender},#{email},#{empStatus})
insert>

③ 测试

/*
 * 默认mybatis在处理枚举对象的时候保存的是枚举的名字:EnumTypeHandler
 * 改变使用:EnumOrdinalTypeHandler:
 */
@Test
public void testEnum() throws IOException{
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession openSession = sqlSessionFactory.openSession();
    try{
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Employee employee = new Employee("test_enum", "[email protected]","1");
        mapper.addEmp(employee);
        openSession.commit();
    }finally{
        openSession.close();
    }
}

在这里插入图片描述
在全局配置文件mybatis-config.xml添加如下配置之后,再次测试时便保存枚举的索引

<typeHandlers>
	<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.atguigu.mybatis.bean.EmpStatus"/>
typeHandlers>

在这里插入图片描述

(3)自定义类型处理器——使用自定义的类型处理器处理枚举类型

① 重新编写枚举EmpStatus类

package com.atguigu.mybatis.bean;

//希望数据库保存的是100,200这些状态码,而不是默认0,1或者枚举的名
public enum EmpStatus {
    LOGIN(100,"用户登录"),LOGOUT(200,"用户登出"),REMOVE(300,"用户不存在");
   
    private Integer code;
    private String msg;
    private EmpStatus(Integer code,String msg){
        this.code = code;
        this.msg = msg;
    }
    public Integer getCode() {
        return code;
    }
    
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    
    //按照状态码返回枚举对象
    public static EmpStatus getEmpStatusByCode(Integer code){
        switch (code) {
            case 100:
                return LOGIN;
            case 200:
                return LOGOUT;
            case 300:
                return REMOVE;
            default:
                return LOGOUT;
        }
    }
}

② 自定义TypeHandler类

package com.atguigu.mybatis.typehandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

import com.atguigu.mybatis.bean.EmpStatus;

//1、实现TypeHandler接口,或者继承BaseTypeHandler
public class MyEnumEmpStatusTypeHandler implements TypeHandler<EmpStatus> {
    
    //定义当前数据如何保存到数据库中
    @Override
    public void setParameter(PreparedStatement ps, int i, EmpStatus parameter,
                             JdbcType jdbcType) throws SQLException {
        // TODO Auto-generated method stub
        System.out.println("要保存的状态码:"+parameter.getCode());
        ps.setString(i, parameter.getCode().toString());
    }
    
    @Override
    public EmpStatus getResult(ResultSet rs, String columnName)
            throws SQLException {
        // TODO Auto-generated method stub
        //需要根据从数据库中拿到的枚举的状态码返回一个枚举对象
        int code = rs.getInt(columnName);
        System.out.println("从数据库中获取的状态码:"+code);
        EmpStatus status = EmpStatus.getEmpStatusByCode(code);
        return status;
    }
    
    @Override
    public EmpStatus getResult(ResultSet rs, int columnIndex)
            throws SQLException {
        // TODO Auto-generated method stub
        int code = rs.getInt(columnIndex);
        System.out.println("从数据库中获取的状态码:"+code);
        EmpStatus status = EmpStatus.getEmpStatusByCode(code);
        return status;
    }
    
    @Override
    public EmpStatus getResult(CallableStatement cs, int columnIndex)
            throws SQLException {
        // TODO Auto-generated method stub
        int code = cs.getInt(columnIndex);
        System.out.println("从数据库中获取的状态码:"+code);
        EmpStatus status = EmpStatus.getEmpStatusByCode(code);
        return status;
    }
}

③ 在全局配置文件mybatis-config.xml注册


<typeHandlers>
    
    <typeHandler handler="com.atguigu.mybatis.typehandler.MyEnumEmpStatusTypeHandler" javaType="com.atguigu.mybatis.bean.EmpStatus"/>
    
typeHandlers>

在这里插入图片描述

你可能感兴趣的:(Java,开发,MyBatis,Java,SQL)