Mybatis 学习笔记

文章目录

  • 一、简介
  • 二、Mybatis配置
    • 1、数据准备
    • 2、Mybatis全局配置
    • 3、全局配置文件-properties外部引入
    • 4、配置文件常用配置
    • 5、测试类
  • 三、Mybatis 基础操作
    • 1、基础操作
    • 2、映射文件-参数处理
    • 3、流式查询
      • 3.1 简介
      • 3.2 流式查询接口
      • 3.3 流式查询接口--Cursor
      • 3.4 流式查询接口--Cursor实现
  • 四、Mybatis 高级操作(一对多、多对一)
    • 1、封装映射
      • 1.1 **map(select-记录封装**)
      • 1.2 **自定义结果映射规则**(**select-resultMap**)
    • 2、**关联查询**
      • 2.1 多对一处理
      • 2.2 一对多处理
    • 3、鉴别器
    • 4、动态sql
      • 4.1 简介
      • 4.2 **if判断**
      • 4.3 **trim-自定义字符串截取**
      • 4.4 **choose-分支选择**
      • 4.5 **foreach-遍历集合**
      • 4.6 **sql抽取可重用的sql片段**
  • 五、缓存
  • 六、Mybatis逆向工程
    • 1、逆向工程创建
    • 2、MBG相关类CURD
  • 七、分页插件
    • 1、插件配置
    • 2、插件使用
      • 2.1 直接输出
      • 2.2 使用PageInfo
    • 3、分页常用数据

一、简介

MyBatis是什么

  • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • MyBatis 可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO( Plain Old Java Objects,普通的Java对象)映射成数据库中的记录

Mabits官方文档

二、Mybatis配置

1、数据准备

在MySQL数据库创建一数据库实例learnmybatis,在其创建一张表

CREATE TABLE employee(
  id INT(11) PRIMARY KEY AUTO_INCREMENT,
  last_name VARCHAR(255),
  gender CHAR(1),
  email VARCHAR(255),
  did VARCHAR(255)
);

CREATE TABLE department(
  id INT(11) PRIMARY KEY AUTO_INCREMENT,
  department_name VARCHAR(255)
);

创建对应的JavaBean

public class Employee {
  
  private Integer id;
  private String lastName;
  private String email;
  private String gender;
  private Department department;
  
  //getter and setter and toString()
}


public class Department {
    private Integer id;
    private String departmentName;
    private List<Employee> emps;
    //getter and setter and toString()
}

pom.xml中引入依赖,注意引入最新版

<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.4.1version>
dependency>

<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>8.0.16version>
dependency>

2、Mybatis全局配置



<configuration>
  <settings>
      
      <setting name="mapUnderscoreToCamelCase" value="true"/>
      
      <setting name="logImpl" value="STDOUT_LOGGING" />
      
      <setting name="cacheEnabled" value="true"/>
  settings>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC" />
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/learnmybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai" />
        <property name="username" value="root" />
        <property name="password" value="root" />
      dataSource>
    environment>
  environments>
  
  <mappers>
     
    <mapper resource="mappers/EmployeeMapper.xml" />
    <mapper resource="mappers/DepartmentMapper.xml" />
    <mapper resource="mappers/EmployeeMapper1.xml" />
    
  mappers>
configuration>

MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置( settings)和属性( properties)信息。文档的顶层结构如下:

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

官方文档

3、全局配置文件-properties外部引入

<configuration>
  
  properties>

在resource下中创建dbconfig.properties文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/learnmybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root

4、配置文件常用配置

settings-运行时行为设置

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

类型更多设置

类型处理器

typeAliases-别名

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。可以在xml配置,也可以在类上加注解@Alias不过为了好排查,一般都写全类名。

enviroments-运行环境

  • id:指定当前环境的唯一标识
  • transactionManager、和dataSource都必须有
<environments default="dev_mysql">
  <environment id="dev_mysql">
    <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>
  ...

5、测试类

public class MybatisTest {

    public static void main(String[] args) throws IOException {
        // 加载mybatis框架主配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 读取解析配置文件内容,创建SqlSessionFacory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        // 执行数据库操作
        Employee empAndDepart = mapper.getEmpAndDepart(1);
        // List list = mapper.getEmp1();
        System.out.println(empAndDepart);
        sqlSession.commit();
        sqlSession.close();
    }
}

三、Mybatis 基础操作

1、基础操作

  • cache –命名空间的二级缓存配置
  • cache-ref – 其他命名空间缓存配置的引用。
  • resultMap – 自定义结果集映射
  • parameterMap – 已废弃!老式风格的参数映射
  • sql –抽取可重用语句块。
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

EmployeeMapper.java

public interface EmployeeMapper {
  
    //也可以通过注解方式
    //@Select("select * from employee where id = #{id}")
    // @Results({
    //         @Result(id=true,column="id",property="id")
    // )}
    // public Employee getEmpById(Integer id);
    
  public Employee getEmpById(Integer id);

  public Long addEmp(Employee employee);

  public boolean updateEmp(Employee employee);

  public void deleteEmpById(Integer id);
  
}

EmployeeMapper.xml





<mapper namespace="org.demo.mapper.EmployeeMapper">

   <select id="getEmpById" resultType="org.demo.po.Employee">
    select * from employee where id = #{id}
  select>

  
  <insert id="addEmp" parameterType="org.demo.po.Employee"
    useGeneratedKeys="true" keyProperty="id" >
    insert into employee(last_name,email,gender) 
    values(#{lastName},#{email},#{gender})
  insert>
  
  
  <update id="updateEmp">
    update employee 
    set last_name=#{lastName},email=#{email},gender=#{gender}
    where id=#{id}
  update>
  
  
  <delete id="deleteEmpById">
    delete from employee where id=#{id}
  delete>
  
mapper>
  • resultType:返回结果类型,可以做别名映射
  • parameterType:参数类型,可以省略,
  • 获取自增主键的值:
    • mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys();
    • useGeneratedKeys=“true”;使用自增主键获取主键值策略
    • keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性

2、映射文件-参数处理

4种映射文件,多个参数会被封装成 一个map

<mapper namespace="org.demo.mapper.EmployeeMapper">
  
  
   <select id="getEmpByIdAndLastName" resultType="org.demo.po.Employee">
     select * from tbl_employee where id = #{id} and last_name=#{lastName}
   select>
   <select id="getEmpByIdAndLastName2" resultType="org.demo.po.Employee">
     select * from employee where id = #{0} and last_name=#{1}
   select>
   <select id="getEmpByIdAndLastName3" resultType="org.demo.po.Employee">
     select * from employee where id = #{param1} and last_name=#{param2}
   select>
   <select id="getEmpByIdAndLastName4" resultType="org.demo.po.Employee">
     select * from employee where id = #{id} and last_name=#{lastName}
   select>
  ...
public interface EmployeeMapper {
    
  public Employee getEmpByIdAndLastName(Integer id, String name);
  public Employee getEmpByIdAndLastName2(Integer id, String name);
  public Employee getEmpByIdAndLastName3(Integer id, String name);
  public Employee getEmpByIdAndLastName4(@Param("id")Integer id,@Param("lastName")String name);
  ...

参数处理#{}与${}取值区别

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

3、流式查询

3.1 简介

流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低内存使用。如果没有流式查询,我们想要从数据库取 1000 万条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。

流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭

3.2 流式查询接口

EmployeeMapper创建mapper方法,这里提供两种方式

// MySQL 默认情况下,创建 prepareStatement 时,就已经是 ResultSet.TYPE_FORWARD_ONLY 和 ResultSet.CONCUR_READ_ONLY ,所以这两个参数可加可不加
// @Select("select * from employee")
// @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE)
// @ResultType(Employee.class)
void getEmpList(ResultHandler<Employee> resultHandler);

基于xml的方式





<select id="getEmpList" resultType="Employee" resultSetType="FORWARD_ONLY" fetchSize="-2147483648">
    select * from employee
select>

测试用例

// 执行数据库操作
AtomicInteger num = new AtomicInteger();
mapper.getEmpList(resultContext -> {
    //逐条返回
    Employee employee = resultContext.getResultObject();
    /**
    * 业务代码
    */
    num.getAndIncrement();
    System.out.println("第" + num + "次查询," + employee.toString());
});

3.3 流式查询接口–Cursor

MyBatis 提供了一个叫 org.apache.ibatis.cursor.Cursor 的接口类用于流式查询,这个接口继承了 java.io.Closeablejava.lang.Iterable 接口,由此可知:

  • Cursor 是可关闭的,实际上当关闭 Cursor 时,也一并将数据库连接关闭了;

  • Cursor 是可遍历的

除此之外,Cursor 还提供了三个方法:

  • isOpen():用于在取数据之前判断 Cursor 对象是否是打开状态。只有当打开时 Cursor 才能取数据;
  • isConsumed():用于判断查询结果是否全部取完;
  • getCurrentIndex():返回已经获取了多少条数据。

因为 Cursor 实现了迭代器接口,因此在实际使用当中,从 Cursor 取数据非常简单:

try(Cursor cursor = mapper.querySomeData()) {
    cursor.forEach(rowObject -> {
        // ...
    });
}

使用 try-resource 方式可以令 Cursor 自动关闭。

3.4 流式查询接口–Cursor实现

首先定义好mapper方法

@Select("select * from employee limit #{limit}")
Cursor<Employee> scan(@Param("limit") int limit);

因为Cursor在取数据的过程中需要保持数据库连接,而 Mapper 方法通常在执行完后连接就关闭了,因此 Cusor 也一并关闭了,这里可能会报错,所以在spring整合的时候,有三种方法可以选择

  • SqlSessionFactory

    用 SqlSessionFactory 来手工打开数据库连接。

    @GetMapping("scan/1/{limit}")
    public void scanFoo1(@PathVariable("limit") int limit) throws Exception {
        try (
            SqlSession sqlSession = sqlSessionFactory.openSession();  // 1
            Cursor<Employee> cursor = 
                  sqlSession.getMapper(EmployeeMapper.class).scan(limit)   // 2
        ) {
            cursor.forEach(e -> { });
        }
    }
    

    上述代码中,1 处我们开启了一个 SqlSession (实际上也代表了一个数据库连接),并保证它最后能关闭;2 处我们使用 SqlSession 来获得 Mapper 对象。这样才能保证得到的 Cursor 对象是打开状态的

  • TransactionTemplate

    在 Spring 中,我们可以用 TransactionTemplate 来执行一个数据库事务,这个过程中数据库连接同样是打开的

    @GetMapping("scan/2/{limit}")
    public void scanFoo2(@PathVariable("limit") int limit) throws Exception {
        TransactionTemplate transactionTemplate = 
                new TransactionTemplate(transactionManager);  // 1
    
        transactionTemplate.execute(status -> {               // 2
            try (Cursor<Employee> cursor = EmployeeMapper.scan(limit)) {
                cursor.forEach(e -> { });
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        });
    }
    

    上面的代码中,1 处我们创建了一个 TransactionTemplate 对象(此处 transactionManager 是怎么来的不用多解释,本文假设读者对 Spring 数据库事务的使用比较熟悉了),2 处执行数据库事务,而数据库事务的内容则是调用 Mapper 对象的流式查询。注意这里的 Mapper 对象无需通过 SqlSession 创建。

  • @Transactional 注解

    @GetMapping("scan/3/{limit}")
    @Transactional
    public void scanFoo3(@PathVariable("limit") int limit) throws Exception {
        try (Cursor<Employee> cursor = EmployeeMapper.scan(limit)) {
            cursor.forEach(e -> { });
        }
    }
    

    本质上和方案二,只在外部调用时生效。在当前类中调用这个方法,依旧会报错。

四、Mybatis 高级操作(一对多、多对一)

1、封装映射

1.1 map(select-记录封装)

public interface EmployeeMapper {

  //多条记录封装一个map:Map:键是这条记录的主键,值是记录封装后的javaBean
  //@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key
  @MapKey("lastName")
  public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);
  
  //返回一条记录的map;key就是列名,值就是对应的值
  public Map<String, Object> getEmpByIdReturnMap(Integer id);
  ...

1.2 自定义结果映射规则(select-resultMap)

<mapper namespace="org.demo.mapper.EmployeeMapper">

  
  <resultMap id="MySimpleEmp" type="org.demo.po.Employee">
    
    <id column="id" property="id"/>
    
    <result column="last_name" property="lastName"/>
    
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
  resultMap>
  
  
  
  <select id="getEmpByIdWithResultMap"  resultMap="MySimpleEmp">
    select * from employee where id=#{id}
  select>

2、关联查询

实体类和数据库如上述配置

2.1 多对一处理

创建EmployeeMapper接口文件

public interface EmployeeMapper {

    Employee getEmpAndDepart(Integer id);

    List<Employee> getEmpAndDepart1();

    List<Employee> getEmpAndDepart2();

    @Select("select * from employee where id = #{id}")
    @Options
    Employee getEmpById(@Param("id") Integer id);
}

mapper.xml文件(多对一或一对一)这里有三种查询方式

  • 联合查询
  • 指定联合的javaBean对象查询
  • 分步查询

<mapper namespace="org.demo.mapper.EmployeeMapper">

    
    <resultMap id="MyEmployee" type="org.demo.po.Employee">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="id" property="department.id"/>
        <result column="department_name" property="department.departmentName"/>
    resultMap>

    
    <resultMap id="MyEmployee1" type="org.demo.po.Employee">
        <result column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>
        
        <association property="department" javaType="Department">
            <id column="id" property="id"/>
            <result column="department_name" property="departmentName"/>
        association>
    resultMap>

    
    
    <resultMap id="MyEmployee2" type="org.demo.po.Employee">
        <result column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>
        
        <association column="did" property="department" javaType="Department" select="getDepart">
            <id column="id" property="id"/>
            <result column="department_name" property="departmentName"/>
        association>
    resultMap>
    
    
    <select id="getEmpAndDepart" resultMap="MyEmployee">
        SELECT *
        FROM employee e, department d
        WHERE e.did=d.id AND e.id=#{id}
    select>


    <select id="getEmpAndDepart1" resultMap="MyEmployee">
        select * from employee e, department d WHERE e.did =d.id
    select>

    <select id="getEmpAndDepart2" resultMap="MyEmployee">
        select * from employee
    select>

    <select id="getDepart" resultType="Department">
        select * from department where id = #{did}
    select>
    
mapper>

延迟加载

我们每次查询Employee对象的时候,都将一起查询出来。部门信息在我们使用的时候再去查询;分段查询的基础之上加上两个配置:在全局配置文件中配置,实现懒加载


  ...
  
    ...
    
    
    
  

2.2 一对多处理

创建DepartmentMapper.xml,一对多关联查询-collection,有两种

  • 联合查询
  • 分步查询

<mapper namespace="org.demo.mapper.DepartmentMapper">

    
    <resultMap type="org.demo.po.Department" id="MyDeptWithEmps">
        <id column="id" property="id"/>
        <result column="department_name" property="departmentName"/>
        
        <collection property="emps" ofType="org.demo.po.Employee" javaType="java.util.List">
            
            <id column="e_id" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="email" property="email"/>
            <result column="gender" property="gender"/>
        collection>
    resultMap>

    
    <resultMap type="org.demo.po.Department" id="MyDeptStep">
        <id column="id" property="id"/>
        <id column="department_name" property="departmentName"/>
        
        <collection property="emps"
                    select="getEmpByDid"
                    column="id">
        collection>
    resultMap>

    
    
    <select id="MyDept" resultMap="MyDeptWithEmps">
        SELECT d.*, e.*,e.id as e_id
        FROM department d LEFT JOIN employee e ON d.id=e.did
        WHERE d.id=#{id}
    select>

    
    <select id="getDeptStep" resultMap="MyDeptStep">
        select * from department
        where id = #{id}
    select>

    <select id="getEmpByDid" resultType="org.demo.po.Employee">
        select * from employee where did = #{id}
    select>
mapper>

3、鉴别器

discriminator鉴别器,创建EmployeeMapper1.xml


<mapper namespace="org.demo.mapper.EmployeeMapper1">

    
    
    <resultMap type="org.demo.po.Employee" id="MyEmpDis">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        
        <discriminator javaType="string" column="gender">
            
            <case value="0" resultType="org.demo.po.Employee">
                <association property="department"
                             select="getDeptById"
                             column="did" fetchType="eager" >
                association>
            case>
            
            <case value="1" resultType="org.demo.po.Employee">
                <id column="id" property="id"/>
                <result column="last_name" property="lastName"/>
                <result column="last_name" property="email"/>
                <result column="gender" property="gender"/>
            case>
        discriminator>
    resultMap>

    
    <select id="getEmpsWithDiscriminator" resultMap="MyEmpDis">
        select * from employee
    select>

    <select id="getDeptById" resultType="org.demo.po.Department">
        select * from department where id = #{did}
    select>
mapper>

4、动态sql

4.1 简介

MyBatis采用功能强大的基于 OGNL 的表达式来简化操作。

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

严格来说,在XML中只有”<”和”&”是非法的,需要转义,其中转义字符

< <
> >
& &
'
" "

4.2 if判断


<mapper namespace="org.demo.mapper.DynamicSQLMapper">

    
    
    <select id="getEmpsByConditionIf" resultType="org.demo.po.Employee">
        select * from employee where 1=1
        
        <if test="id!=null">
            and id=#{id}
        if>
        <if test="lastName!=null && lastName!=""">
            and last_name like #{lastName}
        if>
        <if test="email!=null and email.trim()!=""">
            and email=#{email}
        if>
        
        <if test="gender==0 or gender==1">
            and gender=#{gender}
        if>
    select>
    
    <select id="getEmpsByConditionIfWithWhere" resultType="org.demo.po.Employee">
        select * from employee
        <where>
            <if test="id!=null">
                id=#{id}
            if>
            <if test="lastName!=null and lastName!=""">
                and last_name like #{lastName}
            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>

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

mapper>

4.3 trim-自定义字符串截取

SQL语句前面或后面多出的and或者**or **where标签不能解决

  • prefix="":前缀:trim标签体中是整个字符串拼串后的结果。
    • prefix给拼串后的整个字符串加一个前缀
  • prefixOverrides=""
    • 前缀覆盖: 去掉整个字符串前面多余的字符
  • suffix="":后缀
    • suffix给拼串后的整个字符串加一个后缀
  • suffixOverrides=""
    • 后缀覆盖:去掉整个字符串后面多余的字符

<select id="getEmpsByConditionTrim" resultType="org.demo.po.Employee">
    select * from employee
    
    <trim prefix="where" suffixOverrides="and">
        <if test="id!=null">
            id=#{id} and
        if>
        <if test="lastName!=null && lastName!=""">
            last_name like #{lastName} and
        if>
        <if test="email!=null and email.trim()!=""">
            email=#{email} and
        if>
        
        <if test="gender==0 or gender==1">
            gender=#{gender} and
        if>
    trim>
select>

4.4 choose-分支选择

<mapper namespace="com.lun.c04.dynamicsql.DynamicSQLMapper">


    <select id="getEmpsByConditionChoose" resultType="org.demo.po.Employee">
        select * from employee
        <where>
            
            <choose>
                <when test="id!=null">
                    id=#{id}
                when>
                <when test="lastName!=null">
                    last_name like #{lastName}
                when>
                <when test="email!=null">
                    email = #{email}
                when>
                <otherwise>
                    gender = 0
                otherwise>
            choose>
        where>
    select>
mapper>

4.5 foreach-遍历集合

  • collection:指定要遍历的集合:
    • list类型的参数会特殊处理封装在map中,map的key就叫list
  • item:将当前遍历出的元素赋值给指定的变量
  • separator:每个元素之间的分隔符
  • open:遍历出所有结果拼接一个开始的字符
  • close:遍历出所有结果拼接一个结束的字符
  • index:索引。遍历list的时候是index就是索引,item就是当前值
    • 遍历map的时候index表示的就是map的key,item就是map的值
  • #{变量名}就能取出变量的值也就是当前遍历出的元素

<select id="getEmpsByConditionForeach" resultType="org.demo.po.Employee">
    select * from employee
    <foreach collection="ids" item="item_id" separator=","
             open="where id in(" close=")">
        #{item_id}
    foreach>
select>


<select id="selectEmp" parameterType="map" resultType="org.demo.po.Employee">
    select * from employee
    <where>
        <foreach collection="list" item="id" open="(" separator="or" close=")">
            id = #{id}
        foreach>
    where>
select>


<select id="selectEmp1" parameterType="map" resultType="org.demo.po.Employee">
    select * from employee
    <where>
        id in
        <foreach collection="list" item="id" open="(" separator="," close=")">
            #{id}
        foreach>
    where>
select>




<insert id="addEmps">
    insert into employee(last_name,email,gender,did)
    values
    <foreach collection="emps" item="emp" separator=",">
        (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
    foreach>
insert>


<insert id="addEmps2">
    <foreach collection="emps" item="emp" separator=";">
        insert into employee(last_name,email,gender,did)
        values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
    foreach>
insert>

4.6 sql抽取可重用的sql片段

抽取可重用的sql片段,方便后面引用:

  1. sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用
  2. include来引用已经抽取的sql:
  3. include还可以自定义一些property,sql标签内部就能使用自定义的属性
    • include-property:取值的正确方式${prop},
    • 不能使用#{},而使用${}

<mapper namespace="org.demo.mapper.DynamicSQLMapper">
    <sql id="employColumns">${alias}.id,${alias}.last_name,${alias}.gender,${alias}.email sql>

    <select id="selectEmployeeBySql" resultType="org.demo.po.Employee">
        select
        <include refid="employColumns"><property name="alias" value="t1"/>include>
        from employee t1
    select>

    <sql id="insertColumn">
        <if test="_databaseId=='oracle'">
            last_name,email,gender,did
        if>
        <if test="_databaseId=='mysql'">
            last_name,email,gender,did
        if>
    sql>

    <insert id="addEmps3">
        insert into employee(
        <include refid="insertColumn">include>
        )
        values
        <foreach collection="emps" item="emp" separator=",">
            (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
        foreach>
    insert>
mapper>

五、缓存

MyBatis官方文档

MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。

MyBatis系统中默认定义了两级缓存,一级缓存和二级缓存。

  1. 默认情况下,只有一级缓存( SqlSession级别的缓存,也称为本地缓存)开启。
  2. 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
  3. 为了提高扩展性。 MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
  4. 对于Mabtis查询,查询过程默认是二级缓存->一级缓存->数据库

六、Mybatis逆向工程

1、逆向工程创建

pom.xml中引入逆向工程MBG依赖

<dependencies>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.11version>
        <scope>testscope>
    dependency>

    <dependency>
        <groupId>org.mybatisgroupId>
        <artifactId>mybatisartifactId>
        <version>3.4.1version>
    dependency>

    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>8.0.16version>
    dependency>

    <dependency>
        <groupId>org.mybatis.generatorgroupId>
        <artifactId>mybatis-generator-coreartifactId>
        <version>1.3.7version>
    dependency>
dependencies>

<build>
    
    <plugins>
        
        <plugin>
            <groupId>org.mybatis.generatorgroupId>
            <artifactId>mybatis-generator-maven-pluginartifactId>
            <version>1.3.7version>
            
            <dependencies>
                
                <dependency>
                    <groupId>org.mybatis.generatorgroupId>
                    <artifactId>mybatis-generator-coreartifactId>
                    <version>1.3.7version>
                dependency>
                
                <dependency>
                    <groupId>com.mchangegroupId>
                    <artifactId>c3p0artifactId>
                    <version>0.9.2version>
                dependency>
                
                <dependency>
                    <groupId>mysqlgroupId>
                    <artifactId>mysql-connector-javaartifactId>
                    <version>8.0.16version>
                dependency>
            dependencies>
        plugin>
    plugins>
build>

在项目的resources目录下创建generatorConfig.xml,修改部分内容,最后执行插件generate目标即可



<generatorConfiguration>
    
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/learnmybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"
                        userId="root"
                        password="root">
        jdbcConnection>
        
        <javaModelGenerator targetPackage="org.demo.pojo" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        javaModelGenerator>
        
        <sqlMapGenerator targetPackage="mappers"
                         targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        sqlMapGenerator>
        
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="org.demo.mapper" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        javaClientGenerator>
        
        
        
        <table tableName="department" domainObjectName="Department"/>
        <table tableName="employee" domainObjectName="Employee"/>
    context>
generatorConfiguration>

2、MBG相关类CURD

  • selectByExample

    按条件查询,需要传入一个example对象或者null;如果传入一个null,则表示没有条件,也就是查询所有数据

  • example.createCriteria().xxx

    创建条件对象,通过andXXX方法为SQL添加查询添加,每个条件之间是and关系

  • example.or().xxx

    将之前添加的条件通过or拼接其他条件

  • updateByPrimaryKey

    通过主键进行数据修改,如果某一个值为null,也会将对应的字段改为null

  • updateByPrimaryKeySelective()

    通过主键进行选择性数据修改,如果某个值为null,则不修改这个字段

七、分页插件

1、插件配置

首先在pom.xml中引入相关依赖


<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelperartifactId>
    <version>5.2.0version>
dependency>

mybatis-config.xml设置分页插件

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

2、插件使用

2.1 直接输出

在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能

  • pageNum:当前页的页码
  • pageSize:每页显示的条数
//访问第一页,每页四条数据
Page<Object> page = PageHelper.startPage(1, 4);
List<Emp> emps = mapper.selectByExample(null);
//在查询到List集合后,打印分页数据
System.out.println(page);

2.2 使用PageInfo

在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, intnavigatePages)获取分页相关数据

  • list:分页之后的数据
  • navigatePages:导航分页的页码数
PageHelper.startPage(1, 4);
List<Emp> emps = mapper.selectByExample(null);
PageInfo<Emp> page = new PageInfo<>(emps,5);
System.out.println(page);

3、分页常用数据

  • pageNum:当前页的页码
  • pageSize:每页显示的条数
  • size:当前页显示的真实条数
  • total:总记录数
  • pages:总页数
  • prePage:上一页的页码
  • nextPage:下一页的页码
  • isFirstPage/isLastPage:是否为第一页/最后一页
  • hasPreviousPage/hasNextPage:是否存在上一页/下一页
  • navigatePages:导航分页的页码数
  • navigatepageNums:导航分页的页码,[1,2,3,4,5]

参考资料与其他文章

源码仓库

具体源码分析

你可能感兴趣的:(#,Mybatis,java)