Mybatis的简单使用

目录

  • 概述
  • HelloWorld
    • 接口式编程
    • 小结
  • mapper.xml文件位置
  • 全局配置文件
    • properties引入外部配置文件
    • settings运行时行为设置
    • typeAliases别名
      • 批量取别名
    • typeHandlers类型处理器
    • plugins插件
    • enviroments运行环境
    • databaseIdProvider多数据库支持
    • mappers sql映射注册
      • class
      • 批量注册
  • Mapper.xml
    • 增删改
    • insert获取自增主键ID
      • 支持自增主键的数据库如:Mysql
      • 不支持自增主键的数据库实现如:Oracle
    • 参数处理
      • $和#
      • #{}相关规则
    • 返回处理
      • 返回List
      • 返回map
      • resultMap自定义结果映射
        • 关联查询-单个对象的级联属性
          • association指定联合单个对象
          • association分布查询
        • collection关联集合封装
          • 分步查询
          • 分步查询传递多列参数
          • fetchType:定义加载时机eager|lazy
          • discriminator鉴别器
    • 动态SQL
      • if
      • where
      • trim
      • choose
      • set
      • foreach
        • 查询
        • 批量插入
          • mysql
          • Oracle
      • 内置参数
      • bind
      • sql与include
  • 缓存
    • 一级缓存
      • 缓存失效的情况
    • 二级缓存
      • 机制
      • 配置
      • 获取数据顺序
    • 三方缓存
  • 与Spring整合
    • 导入相关依赖
    • 数据库连接properties配置
    • web.xml配置文件
    • SpringMVC配置文件
    • Spring配置文件
    • Mybatis全局配置文件
    • 类和方法
  • 插件
    • 编写插件
    • 多个插件运行流程
    • 功能修改
  • 分页插件PageHelper
    • 引入依赖
    • 配置
    • 简单使用
      • pageInfo内的内容
      • Page内的内容
  • 批量BatchExecutor
    • Spring中使用批量SqlSession
  • Oracle的存储过程
  • 枚举类型
    • 自定义枚举类型处理器

概述

  • Mybatis是一个半自动化的持久化层框架
    为什么要用Mybatis?
    1.原生JDBC的SQL代码夹杂在Java代码里面,维护成本高,代码耦合度高
    2.Hibernate和JPA处理复杂SQL难度较大,内部自动生成的SQL开发人员无法做特殊优化,基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难,导致数据库性能下降;
    3.对于开发人员,SQL和java编码分开,功能边界清洗;

HelloWorld

  • 相关表
CREATE TABLE `emp` (
  `id` int NOT NULL AUTO_INCREMENT,
  `emp_name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  `emp_gender` char(1) COLLATE utf8mb4_bin DEFAULT NULL,
  `emp_email` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
  • 创建对应实体类
public class Employee {

    private Integer id;
    private String empName;
    private String empGender;
    private String empEmail;

    public Integer getId() {
        return id;
    }

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

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getEmpGender() {
        return empGender;
    }

    public void setEmpGender(String empGender) {
        this.empGender = empGender;
    }

    public String getEmpEmail() {
        return empEmail;
    }

    public void setEmpEmail(String empEmail) {
        this.empEmail = empEmail;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", empName='" + empName + '\'' +
                ", empGender='" + empGender + '\'' +
                ", empEmail='" + empEmail + '\'' +
                '}';
    }
}
  • 导入相关依赖
<dependencies>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.4.1version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.28version>
        dependency>
        
        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.17version>
        dependency>
    dependencies>
  • 编写mybatis全局配置文件

DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&characterEncoding=utf-8&serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            dataSource>
        environment>
    environments>

    
    <mappers>
        <mapper resource="EmployeeMapper.xml"/>
    mappers>
configuration>
  • 编写sql映射文件

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

<mapper namespace="per.xgt.mapper.EmployeeMapper">

    <select id="selectEmp" resultType="per.xgt.entity.Employee">
        select * from emp where id = #{id}
    select>
mapper>
  • 测试类
public class testMybatis {

    /**
     * 1.根据xml配置文件创建一个sqlSessionFactory对象
     * 2.获取sqlSession实例,能直接执行已经映射的sql语句
     * @throws IOException
     */
    @Test
    public void test1() throws IOException {
        // 根据xml配置文件创建一个sqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 获取sqlSession实例
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Employee employee = sqlSession.selectOne("per.xgt.mapper.EmployeeMapper.selectEmp", 1);
        System.out.println(employee);
        sqlSession.close();
    }
}
  • 执行结果
DEBUG 07-26 15:17:45,204 ==>  Preparing: select * from emp where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 07-26 15:17:45,230 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 07-26 15:17:45,293 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=1, empName='null', empGender='null', empEmail='null'}
  • 字段为null
    查询的字段列要与类属性一致,如果不一致需要取别名

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

<mapper namespace="per.xgt.mapper.EmployeeMapper">

    <select id="selectEmp" resultType="per.xgt.entity.Employee">
        select id,emp_name empName,emp_gender empGender,emp_email empEmail from emp where id = #{id}
    select>
mapper>

接口式编程

  • 编写接口
public interface EmployeeMapper {
    
    public Employee getEmpById(Integer id);
    
}
  • sql映射文件的namespace为接口的全类名
namespace="per.xgt.mapper.EmployeeMapper"
  • sql的id为接口的方法名
<select id="getEmpById" resultType="per.xgt.entity.Employee">
        select id,emp_name empName,emp_gender empGender,emp_email empEmail from emp where id = #{id}
    select>

mybatis会为接口自动的创建一个代理对象,代理对象去执行增删改查方法

  • 测试
@Test
    public void test2() throws IOException {
        SqlSessionFactory sqlSessionFactory = get();
        SqlSession sqlSession = sqlSessionFactory.openSession();

        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee emp = mapper.getEmpById(1);
        System.out.println(emp);
        sqlSession.close();
    }

小结

  • sqlSession和connection一样都是现成非安全的,代表个数据库的一次回话,用完必须关闭,每次使用都应该去获取新的对象
  • Mapper接口没有实现类,但是mybatis会为这个借口生成一个代理对象,将接口和xml进行绑定
  • 两个配置文件:mybatis的全局配置文件,包含数据库连接池信息,事务管理器信息等系统运行环境;sql映射文件,包含了每一个sql语句的映射信息

mapper.xml文件位置

如果mapper文件在resource目录下,编译时可以直接找到,如果mapper文件在java目录下,则需要在pom文件中添加以下内容说明需要编译java文件下的mapper文件

<build>
        <resources>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>falsefiltering>
            resource>
            <resource>
                <directory>src/main/resourcesdirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>falsefiltering>
            resource>
        resources>
    build>

全局配置文件

properties引入外部配置文件


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

settings运行时行为设置

完整的settings配置

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
settings>
  • 举例:驼峰命名

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

运行结果

DEBUG 07-26 16:15:37,186 ==>  Preparing: select * from emp where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 07-26 16:15:37,213 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 07-26 16:15:37,275 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=1, empName='tom', empGender='0', empEmail='tom@163.com'}

typeAliases别名

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写


    <typeAliases>
        
        <typeAlias type="per.xgt.entity.Employee" alias="emp"/>
    typeAliases>

mapper文件使用别名

<select id="getEmpById" resultType="emp">
        select * from emp where id = #{id}
    select>

批量取别名


    <typeAliases>
        
        <typeAlias type="per.xgt.entity.Employee" alias="emp"/>
        
        <package name="per.xgt.entity"/>
    typeAliases>
@Alias("emp")
public class Employee

typeHandlers类型处理器

MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型

plugins插件

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)
    这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心。
  • 通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

enviroments运行环境


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

databaseIdProvider多数据库支持


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

为sql指定数据库厂商

<select id="getEmpById" resultType="EMP" databaseId="mysql">
        select * from emp where id = #{id}
    select>

mappers sql映射注册


class

<mappers>
        <mapper resource="EmployeeMapper.xml"/>
        <mapper class="per.xgt.mapper.EmployeeMapperAnnotation"/>
    mappers>
@Select("select * from emp where id = #{id}")
    public Employee getEmpById(Integer id);

批量注册

<mappers>
        <mapper resource="EmployeeMapper.xml"/>
        <mapper class="per.xgt.mapper.EmployeeMapperAnnotation"/>
        <package name="per.xgt.mapper"/>
    mappers>

package标签 name属性,映射该包下所有的sql映射文件 ,这种方式能够批量注册,并且每一对接口和xml名称必须相同

package per.xgt.mapper;

import per.xgt.entity.Employee;

/**
 * @author gentao9527
 * @version 1.0
 * @date 2022/7/26 15:01
 * @description
 */
public interface EmpMapper {
    public Employee getEmpById(int id);

}

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="per.xgt.mapper.EmpMapper">
    <select id="getEmpById" resultType="per.xgt.entity.Employee">
        select * from emp where id = #{id}
    select>
mapper>

Mapper.xml

增删改


  • 使用insert标签,parameterType标识参数类型,返回值为影响行数
public int insertEmp(Employee employee);
<insert id="insertEmp" parameterType="per.xgt.entity.Employee">
        insert into emp values(null,#{empName},#{empGender},#{empEmail})
    insert>

手动提交回滚测试代码

@Test
    public void test2() throws IOException {
        // 根据xml配置文件创建一个sqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 获取sqlSession实例,或渠道的SQLSession不会自动提交数据
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Employee employee = new Employee();
        employee.setEmpEmail("[email protected]");
        employee.setEmpGender("1");
        employee.setEmpName("xgt");
        int insert = sqlSession.insert("per.xgt.mapper.EmployeeMapper.insertEmp", employee);
        System.out.println(insert);
        // 提交数据
        sqlSession.commit();
        // 回滚数据
        sqlSession.rollback();
        sqlSession.close();
    }

sqlSessionFactory.openSession(true);里面参数true|false代表是否自动提交
如果有自增ID 新增执行SQL后不提交或者回滚,自增ID会有id不连续的问题

  • 删除和修改
    删除和修改与新增类似,只是标签不同
    删除:
    修改:
  • 返回值问题
    在增删改时,返回值可以为boolean类型(只要被影响行超过0,就会返回true),或者Integer或者Long类型(返回具体影响行数);

insert获取自增主键ID

支持自增主键的数据库如:Mysql

useGeneratedKeys:使用自增主键获取主键策略
keyProperty:指定对应的主键属性,也就是mybatis获取到主键值后,将封装给bean的哪个属性;

<insert id="insertEmpAndGetKey" parameterType="per.xgt.entity.Employee" useGeneratedKeys="true" keyProperty="id">
        insert into emp values(null,#{empName},#{empGender},#{empEmail})
    insert>
@Test
    public void test3() throws IOException {
        // 根据xml配置文件创建一个sqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 获取sqlSession实例,或渠道的SQLSession不会自动提交数据
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        Employee employee = new Employee();
        employee.setEmpEmail("[email protected]");
        employee.setEmpGender("1");
        employee.setEmpName("wp");
        int insert = sqlSession.insert("per.xgt.mapper.EmployeeMapper.insertEmpAndGetKey", employee);
        System.out.println(employee);
        sqlSession.close();
    }

获取到的主键ID会自动封装到bean的主键属性

DEBUG 07-27 10:13:56,288 ==>  Preparing: insert into emp values(null,?,?,?)   (BaseJdbcLogger.java:145) 
DEBUG 07-27 10:13:56,316 ==> Parameters: wp(String), 1(String), wp@163.com(String)  (BaseJdbcLogger.java:145) 
DEBUG 07-27 10:13:56,403 <==    Updates: 1  (BaseJdbcLogger.java:145) 
Employee{id=7, empName='wp', empGender='1', empEmail='wp@163.com'}

不支持自增主键的数据库实现如:Oracle

Oracle不支持自增自增,Oracle可以使用序列模拟自增;每次插入数据主键是从序列中拿到的值;

  • 拿到下一个序列值
select SEQ.nextval from dual;
  • 拿到当前序列值
select SEQ.currval from dual;
  • mybatis获取
<insert id="insertEmpAndGetKey" parameterType="per.xgt.entity.Employee" databaseId="oracle">
        /*插入时的主键是从序列中拿到的
        keyProperty:查询出的主键封装给bean的哪个属性
        order:before当前sql在插入sql之前运行,after当前sql在插入之后运行
        resultType:查处的数据的返回值类型
          */
        <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
            select EMPLOYEE_SEQ.NEXTVAL FROM DUAL
        selectKey>
        insert into emp values(#{id},#{empName},#{empGender},#{empEmail})
    insert>
  • 或者sql直接获取序列插入
<insert id="insertEmpAndGetKey" parameterType="per.xgt.entity.Employee" databaseId="oracle">
        /*插入时的主键是从序列中拿到的
        keyProperty:查询出的主键封装给bean的哪个属性
        order:before当前sql在插入sql之前运行,after当前sql在插入之后运行
        resultType:查处的数据的返回值类型
        */
        <selectKey keyProperty="id" order="AFTER" resultType="Integer">
            select EMPLOYEE_SEQ.currval FROM DUAL
        selectKey>
        insert into emp values(EMPLOYEE_SEQ.NEXTVAL,#{empName},#{empGender},#{empEmail})
    insert>

参数处理

  • 单个参数
    mybatis不会做特殊处理,#{参数名}直接取出;
  • 多个参数
    mybatis会做特殊处理,多个参数会被封装成一个map,key为param1,param2…,#{}就是从map中获取指定的key值。
    取值可以根据参数索引获取
public Employee getEmp(int id,String name);
<select id="getEmp" resultType="per.xgt.entity.Employee">
        select * from emp where id = #{param1} and empName = #{param2}
    select>

可以使用全局配置,useActualParamName(jdk1.8),name=参数名

  • 命名参数
    明确指定封装参数时的key
public Employee getEmp(@Param("id") int id, 
@Param("name")String name);
<select id="getEmp" resultType="per.xgt.entity.Employee">
        select * from emp where id = #{id} and empName = #{name}
    select>
  • POJO参数
    如果多个参数,可以封装成一个实体类传参,#{属性名},直接取出传入的pojo属性值。
public int insertEmp(Employee employee);
<insert id="insertEmp" parameterType="per.xgt.entity.Employee">
        insert into emp values(null,#{empName},#{empGender},#{empEmail})
    insert>
  • Map
    如果多个参数不是业务模型中的数据,没有对应的POJO,为了方便也可以传入map。#{key},直接取出传入的map的对应value值。
public int insertEmpByMap(Map<String,Object> map);
<insert id="insertEmpByMap" parameterType="java.util.Map">
        insert into emp values(null,#{empName},#{empGender},#{empEmail})
    insert>

$和#

#{}:可以获取mao中的值,或者pojo对象属性的值;
${}:效果和#{}一样

  • ${}
DEBUG 07-27 11:21:33,179 ==>  Preparing: select * from emp where id = 1   (BaseJdbcLogger.java:145) 
DEBUG 07-27 11:21:33,210 ==> Parameters:   (BaseJdbcLogger.java:145) 
DEBUG 07-27 11:21:33,273 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=1, empName='tom', empGender='0', empEmail='[email protected]'}
  • #{}
DEBUG 07-27 11:22:34,662 ==>  Preparing: select * from emp where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 07-27 11:22:34,687 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 07-27 11:22:34,775 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=1, empName='tom', empGender='0', empEmail='[email protected]'}
  • 区别
    #{}:是以预编译的形式,将参数设置到sql语句中,PreparedStatement,防止sql注入;
    ${}:取出的值直接拼装在sql语句中,会有安全问题;
  • 注意
    》#{}会在参数上会带着单引号,而单引号会被识别为字符串;
    》大多数情况下,我们取参数的值都应该使用#{};
    》原生JDBC不支持占位符的地方,就可以使用${}取值

#{}相关规则

  • 规则参数的一些规则:
    》javaType:java
    》jdbcType:通常需要在某种特定的条件下被设置;在数据为null的时候,有些数据库可能不能识别mybatis堆null的默认处理jdbc other,比如Oracle;
<insert id="insertEmp" parameterType="per.xgt.entity.Employee">
        insert into emp values(null,#{empName},#{empGender,jdbcType=NULL},#{empEmail})
    insert>

还可以全局配置:jdbcTypeForNull=NULL;
》mode:存储过程
》numericScale:
》resultMap:
》typeHandler:
》jdbcTypeName:

返回处理

返回List

public List<Employee> getAllEmployee();
<select id="getAllEmployee" resultType="per.xgt.entity.Employee">
        select * from emp
    select>

返回map

  • 单条记录封装map
    返回一条记录的map,key就是列名,值就是value;
public Map<String,Object> getOneEmployeeByMap(int id);
<select id="getOneEmployeeByMap" resultType="java.util.Map">
        select * from emp where id = #{id}
    select>
  • 多条记录封装成一个map,key是id,value是一个实体类
    在接口方法声明上用@MapKey(“empName”)注解告诉mybatis封装时map的key用哪个属性;
@MapKey("empName")
    public Map<String,Object> getOneEmployeeByMaps();
<select id="getOneEmployeeByMaps" resultType="per.xgt.entity.Employee">
        select * from emp
    select>

resultMap自定义结果映射

  • 自动映射:
    全局设置:autoMapptinBenavior默认是PARTIAL,开启自动映射,要求是列名和bean的属性名一致,设置为null则会取消自动映射;
  • resultType和resultMap只能二选一

    <resultMap id="myEmp" type="per.xgt.entity.Employee">
        
        <id column="id" property="id"/>
        
        <result column="empName" property="emp_name"/>
        <result column="empGender" property="emp_gender"/>
        <result column="empEmail" property="emp_email"/>
    resultMap>
    <select id="findOneById" resultMap="myEmp">
        select * from emp where id = #{id}
    select>

关联查询-单个对象的级联属性

public class Employee {
    private Integer id;
    private String empName;
    private String empGender;
    private String empEmail;
    private Department dept;
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", empName='" + empName + '\'' +
                ", empGender='" + empGender + '\'' +
                ", empEmail='" + empEmail + '\'' +
                ", dept=" + dept +
                '}';
    }
    public Department getDept() {
        return dept;
    }
    public void setDept(Department dept) {
        this.dept = dept;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public String getEmpGender() {
        return empGender;
    }
    public void setEmpGender(String empGender) {
        this.empGender = empGender;
    }
    public String getEmpEmail() {
        return empEmail;
    }
    public void setEmpEmail(String empEmail) {
        this.empEmail = empEmail;
    }
}
public class Department {

    private Integer id;
    private String deptName;

    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 + '\'' +
                '}';
    }
}
public Employee findOneAndDeptById(int id);

使用属性.属性赋值


    <resultMap id="findOneAndDeptByIdMap" type="per.xgt.entity.Employee">
        <id column="id" property="id"/>
        <result column="empName" property="empName"/>
        <result column="empGender" property="empGender"/>
        <result column="empEmail" property="empEmail"/>
        <result column="dId" property="dept.id"/>
        <result column="deptName" property="dept.deptName"/>
    resultMap>
    <select id="findOneAndDeptById" resultMap="findOneAndDeptByIdMap">
        SELECT e.id id,
               e.emp_gender empGender,
               e.emp_name empName,
               e.emp_email empEmail,
               d.id dId,
               d.dept_name deptName
        from emp e,dept d
        where e.dept_id = d.id
          and e.id = #{id};
    select>
association指定联合单个对象
<resultMap id="findOneAndDeptByIdMapAssociation" type="per.xgt.entity.Employee">
        <id column="id" property="id"/>
        <result column="empName" property="empName"/>
        <result column="empGender" property="empGender"/>
        <result column="empEmail" property="empEmail"/>
        
        <association property="dept" javaType="per.xgt.entity.Department">
            <id column="dId" property="id"/>
            <result column="deptName" property="deptName"/>
        association>
    resultMap>
    <select id="findOneAndDeptById" resultMap="findOneAndDeptByIdMapAssociation">
        SELECT e.id id,
               e.emp_gender empGender,
               e.emp_name empName,
               e.emp_email empEmail,
               d.id dId,
               d.dept_name deptName
        from emp e,dept d
        where e.dept_id = d.id
          and e.id = #{id};
    select>
association分布查询

    <resultMap id="findOneByStepAndIdMap" type="per.xgt.entity.Employee">
        <id column="id" property="id"/>
        <result column="empName" property="emp_name"/>
        <result column="empGender" property="emp_gender"/>
        <result column="empEmail" property="emp_email"/>
        
        <association property="dept" select="per.xgt.mapper.DepartmentMapper.findOneById" column="dept_id">
        association>
    resultMap>
    <select id="findOneByStepAndId" resultMap="findOneByStepAndIdMap">
        select * from emp where id = #{id}
    select>
  • 延迟加载
    全局配置:
    》lazyLoadingEnable=true|false;开启时,只有真正使用数据的时候才发起查询,不用的时候不查询关联的数据
    》aggressiveLazyLoading=true|false;开启会一次性全部加载

collection关联集合封装

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 + '\'' +
                ", emps=" + emps +
                '}';
    }

}
public Department findEmployeesByDept(Integer id);
<resultMap id="findEmployeesByDeptMap" type="per.xgt.entity.Department">
        <id column="id" property="id"/>
        <result column="deptName" property="deptName"/>
        
        <collection property="emps" ofType="per.xgt.entity.Employee">
            
            <id column="empId" property="id"/>
            <result column="empName" property="empName"/>
            <result column="empGender" property="empGender"/>
            <result column="empEmail" property="empEmail"/>
        collection>
    resultMap>
    <select id="findEmployeesByDept" resultMap="findEmployeesByDeptMap">
        select d.id id,
               d.dept_name deptName,
               e.id empId,
               e.emp_name empName,
               e.emp_gender empGender,
               e.emp_email empEmail
        from dept d
            left join emp e
                on d.id = e.dept_id
        where d.id = #{id}
    select>
分步查询
<resultMap id="findOneByStepAndIdMap" type="per.xgt.entity.Department">
        <id column="id" property="id"/>
        <result column="deptName" property="deptName"/>
        <collection property="emps" select="per.xgt.mapper.EmployeeMapper.findAllByDeptId" column="id">
        collection>
    resultMap>
    <select id="findOneByStepAndId" resultMap="findOneByStepAndIdMap">
        select * from dept where id = #{id}
    select>
分步查询传递多列参数

将多列的值封装map传递

<resultMap id="findOneByStepAndIdMap" type="per.xgt.entity.Department">
        <id column="id" property="id"/>
        <result column="deptName" property="deptName"/>
        <collection property="emps"
                    select="per.xgt.mapper.EmployeeMapper.findAllByDeptId"
                    column="{id=id}">
        collection>
    resultMap>
    <select id="findOneByStepAndId" resultMap="findOneByStepAndIdMap">
        select * from dept where id = #{id}
    select>

column=“{key1=column1,key2=column2}”

fetchType:定义加载时机eager|lazy
<resultMap id="findOneByStepAndIdMap" type="per.xgt.entity.Department">
        <id column="id" property="id"/>
        <result column="deptName" property="deptName"/>
        <collection property="emps"
                    select="per.xgt.mapper.EmployeeMapper.findAllByDeptId"
                    column="{id=id}" fetchType="lazy">
        collection>
    resultMap>
discriminator鉴别器

判断某列的值,改变封装行为;

<resultMap id="findOneByStepAndIdMapMore" type="per.xgt.entity.Employee">
        <id column="id" property="id"/>
        <result column="empName" property="emp_name"/>
        <result column="empGender" property="emp_gender"/>
        <result column="empEmail" property="emp_email"/>
        
        <discriminator javaType="string" column="emp_gender">
            
            <case value="0" resultType="per.xgt.entity.Employee">
                <association property="dept" select="per.xgt.mapper.DepartmentMapper.findOneById" column="dept_id">
                association>
            case>
            <case value="1" resultType="per.xgt.entity.Employee">
                <id column="id" property="id"/>
                <result column="empName" property="emp_name"/>
                <result column="empGender" property="emp_gender"/>
                <result column="empEmail" property="emp_name"/>
            case>
        discriminator>
    resultMap>
    <select id="findOneByStepAndId" resultMap="findOneByStepAndIdMapMore">
        select * from emp where id = #{id}
    select>

动态SQL

if

<select id="findEmpsByIf" parameterType="per.xgt.entity.Employee" resultType="per.xgt.entity.Employee">
        select *
        from emp
        where 1 = 1
        /*if test,判断表达式 OGNL
            从参数中取值进行判断;
          遇见特殊符号比如双引号,应该写转义字符;
          */
        <if test="id != null">
            and id = #{id}
        if>
        <if test="empName != null and empName != ''">
            and emp_name = #{empName}
        if>
        /*OGNL会进行字符串与数字的转换判断*/
        <if test="empGender == '0' or empGender == '1'">
            and emp_gender = #{empGender}
        if>
        <if test="empEmail != null and empEmail.trim() != ''">
            and emp_email = #{empEmail}
        if>
    select>

注意:
如果id == null,那么where后面直接就是 and emp_name = #{empName},所以需要在后面添上1=1;

where

解决上面if标签的问题,可以使用where标签来将所有的查询条件包括在内,会自动去掉第一个and或者or

<select id="findEmpsByIf" parameterType="per.xgt.entity.Employee" resultType="per.xgt.entity.Employee">
        select *
        from emp
        <where>
            <if test="id != null">
                and id = #{id}
            if>
            <if test="empName != null and empName != ''">
                and emp_name = #{empName}
            if>
            <if test="empGender == '0' or empGender == '1'">
                and emp_gender = #{empGender}
            if>
            <if test="empEmail != null and empEmail.trim() != ''">
                and emp_email = #{empEmail}
            if>
        where>
    select>

trim

**自定义字符串截取:**可以解决前面where标签的问题

<select id="findEmpsByTrim" resultType="per.xgt.entity.Employee">
        select *
        from emp
              /*后面多出的and或者or where标签不能解决
                prefix="":前缀,给整个拼接后的字符串添加一个前缀
                prefixOverrides="":前缀覆盖,去掉整个前面多余的字符
                suffix=“”:还给整个拼接后的字符串添加后缀
                suffixOverrides="":后缀覆盖
                */
        <trim prefix="where" suffixOverrides="and">
            <if test="id != null">
                id = #{id} and
            if>
            <if test="empName != null and empName != ''">
                emp_name = #{empName} and
            if>
            <if test="empGender == '0' or empGender == '1'">
                emp_gender = #{empGender} and
            if>
            <if test="empEmail != null and empEmail.trim() != ''">
                emp_email = #{empEmail}
            if>
        trim>
    select>

choose

分支选择:

<select id="findEmpsByChoose" resultType="per.xgt.entity.Employee">
        select * from emp
        <where>
            <choose>
                <when test="id != null">
                    id = #{id}
                when>
                <when test="empName != null">
                    emp_name = #{empName}
                when>
                <when test="empGender != null">
                    emp_gender = #{empGender}
                when>
                <otherwise>
                    where 1 = 1
                otherwise>
            choose>
        where>
    select>

set

封装修改条件
问题:根据条件更新的时候,有可能会多出末尾的逗号","

<update id="updateEmpBySet" parameterType="per.xgt.entity.Employee">
        update emp
        set
        <if test="empName != null">
            emp_name = #{empName} ,
        if>
        <if test="empGender != null">
            emp_gender = #{empGender} ,
        if>
        <if test="empEmail != null">
            emp_email = #{empEmail}
        if>
        where id = #{id}
    update>

解决:更新操作放在set标签

<update id="updateEmpBySet" parameterType="per.xgt.entity.Employee">
        update emp
        <set>
            <if test="empName != null">
                emp_name = #{empName} ,
            if>
            <if test="empGender != null">
                emp_gender = #{empGender} ,
            if>
            <if test="empEmail != null">
                emp_email = #{empEmail}
            if>
        set>
        where id = #{id}
    update>

也可以用trim解决问题:

<update id="updateEmpBySet" parameterType="per.xgt.entity.Employee">
        update emp
        <trim prefix="set" suffixOverrides=",">
            <if test="empName != null">
                emp_name = #{empName} ,
            if>
            <if test="empGender != null">
                emp_gender = #{empGender} ,
            if>
            <if test="empEmail != null">
                emp_email = #{empEmail}
            if>
        trim>
        where id = #{id}
    update>

但是如果所有条件都不满足,还是会报错;

  • 推荐使用set

foreach

遍历集合

查询

public List<Employee> findEmpsByList(List<Integer> list);

    <select id="findEmpsByList" resultType="per.xgt.entity.Employee">
        select * from emp where id in
        /*collection:指定要遍历的集合
        list类型的参数会特殊处理封装在map中:map的key就是list
        item:遍历出的元素赋值给指定的变量;
        separator:每个元素之间的分隔符;
        open:遍历的所有结果拼接出一个开始的字符;
        open:遍历的所有结果拼接出一个结束的字符;
        index:遍历list的时候是索引,遍历map的时候是map的key,item就是map的value
        */
        <foreach collection="list" item="id" separator="," open="(" close=")" index="">
            #{id}
        foreach>
    select>

批量插入

mysql
  • 方法一
public int addEmps(List<Employee> emps);
<insert id="addEmps" parameterType="java.util.List">
        insert into emp (emp_name,emp_gender,emp_email,dept_id) values
        <foreach collection="list" item="emp" separator=",">
            (#{emp.empName},#{emp.empGender},#{emp.empEmail},#{emp.dept.id})
        foreach>
    insert>

注意点


1. 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list    
2. 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array    
3. 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可

也可以指定参数名

public int addEmps(@Param("emps") List<Employee> emps);
<insert id="addEmps" parameterType="java.util.List">
        insert into emp (emp_name,emp_gender,emp_email,dept_id) values
        <foreach collection="emps" item="emp" separator=",">
            (#{emp.empName},#{emp.empGender},#{emp.empEmail},#{emp.dept.id})
        foreach>
    insert>
  • 方法二
    一次执行多条sql,需要先允许使用“;”分割多条SQL来执行:allowMultiQueries
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&characterEncoding=utf-8&serverTimezone=UTC&allowMultiQueries=true
jdbc.username=root
jdbc.password=root
<insert id="addEmps" parameterType="java.util.List">
        <foreach collection="emps" item="emp" separator=";">
            insert into emp (emp_name,emp_gender,emp_email,dept_id) values
            (#{emp.empName},#{emp.empGender},#{emp.empEmail},#{emp.dept.id})
        foreach>
    insert>
Oracle
  • 方法一
    多个insert放在begin end内;
<insert id="addEmpsOracle1" parameterType="java.util.List">
        <foreach collection="emps" item="emp" open="begin" close="end;">
            insert into emp (id,emp_name,emp_gender,emp_email,dept_id) values
            (employee_seq,nextval,#{emp.empName},#{emp.empGender},#{emp.empEmail},#{emp.dept.id});
        foreach>
    insert>
  • 方法二
    利用中间表
<insert id="addEmpsOracle2" parameterType="java.util.List">
        insert into emp (id,emp_name,emp_gender,emp_email,dept_id)
        select employees_seq.nextval,emp_name,emp_gender,emp_email,dept_id
        from 
        <foreach collection="emps" item="emp" separator="union" open="(" close=")">
            select #{emp.empName} emp_name,
                   #{emp.empGender} emp_gender,
                   #{empempEmail} emp_email,
                   #{emp.dept.id} dept_id
            from dual
        foreach>
    insert>

内置参数

不只是方法参数传递的参数可以判断,mybatis默认还有两个内置参数;

  • _parameter:代表整个参数
    单个参数: _parameter就是这个参数;
    多个参数:参数会被封装为一个map, _parameter就代表这个map;
  • _databaseId:如果配置了databaseIdProvider标签, _databaseId就是代表当前数据库的别名;

bind

可以将OGNL表达式的值绑定到一个变量中,方便后面引用

<select id="getEmpByLikeBind" resultType="per.xgt.entity.Employee">
        <bind name="_name" value="'%' + empName + '%'"/>
        select *
        from emp
        where id = #{value}
        and emp_name like #{_name}
    select>

sql与include

sql:抽取可重用的sql片段
include:引用一斤股抽取的sql

  • include可以自定义一些property,sql便签内部就能使用这些自定义的属性property,使用${name}
<sql id="insertColumn">
        <if test="_databaseId == 'mysql'">
            (id,emp_name,emp_gender,emp_email,${aa})
        if>
       <if test="_databaseId == 'oracle'">
           (emp_name,emp_gender,emp_email)
       if>
    sql>
    <insert id="addOne">
        insert into emp
        /*引用抽出的sql片段*/
        <include refid="insertColumn">
            <property name="aa" value="vvv"/>
        include>
        <if test="_databaseId == 'mysql'">
            values (null,'tom','0','[email protected]')
        if>
        <if test="_databaseId == 'oracle'">
            values ('tom','0','[email protected]')
        if>

    insert>

缓存

mybatis系统中默认定义了两级缓存

  • 默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启;
  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
  • 为了提高扩展性,mybatis定义了缓存接口Cache,可以实现Cache接口自定义二级缓存

一级缓存

本地缓存:与数据库同一次会话期间查询到的数据会被放在本地缓存中,以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据;

缓存失效的情况

  • SqlSession不同;
  • SqlSession相同,查询条件不同且当前一级缓存还没有这个数据;
  • SqlSession相同,多次查询期间执行了增删改操作;
  • SqlSession相同,手动清除了一级缓存;
sqlSession.clearCache();

二级缓存

全局缓存:基于namespace级别的缓存,一个namespace对应一个二级缓存;

机制

》一个会话查询一条数据,这条数据就会被放在当前会话的一级缓存中;
》如果会话关闭,一级缓存的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存的内容;
》如果SqlSesison使用了多个namespace,不同namespace查询出的数据会放到自己对应的缓存中;

  • 二级缓存默认是不开启的,需要手动开启二级缓存,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的
public class Employee implements Serializable

配置

  • 开启全局配置

        <setting name="cacheEnabled" value="true"/>
  • 在mapper.xml中配置使用二级缓存

    <cache eviction="LRU" flushInterval="1000*60*5" readOnly="false" size="1024" blocking="">cache>

查询的数据会从二级缓存中获取,但是查出的数据会被默认先放在一级缓存中,只有会话提交或者关闭后,一级缓存的数据才会转移到二级缓存

  • select标签里面的useCache标签,也可以启用二级缓存
<select id="getEmpById" resultType="per.xgt.entity.Employee" useCache="true">
        select *
        from emp
        where id = #{value}
    select>
  • 查询和更新操作的标签:flushCache=“true”,执行完后会清除一级和二级缓存;

  • 全局配置:mybatis3.3后->localCacheScope:本地缓存作用域,SESSION|STATEMENT,STATEMENT代表不共享当前数据,可以禁用掉一级缓存;

获取数据顺序

二级缓存》一级缓存》数据库

三方缓存

  • 引入依赖

<dependency>
    <groupId>org.mybatis.cachesgroupId>
    <artifactId>mybatis-ehcacheartifactId>
    <version>1.0.3version>
dependency>
  • 编写ehcache配置文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    />

    
ehcache>
  • mapper文件中启用ehcache

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

    cache>
  • 其他mapper可以声明和哪个namespace使用的缓存一样

    <cache-ref namespace="per.xgt.mapper.DepartmentMapper"/>

与Spring整合

导入相关依赖



<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>

  <groupId>per.xgtgroupId>
  <artifactId>mybatis-04-ssmartifactId>
  <version>1.0-SNAPSHOTversion>
  <packaging>warpackaging>

  <name>mybatis-04-ssm Maven Webappname>

  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    <maven.compiler.source>1.8maven.compiler.source>
    <maven.compiler.target>1.8maven.compiler.target>
  properties>

  <dependencies>
    
    <dependency>
      <groupId>net.sourceforge.cglibgroupId>
      <artifactId>com.springsource.net.sf.cglibartifactId>
      <version>2.2.0version>
    dependency>
    
    <dependency>
      <groupId>org.aopalliancegroupId>
      <artifactId>com.springsource.org.aopallianceartifactId>
      <version>1.0.0version>
    dependency>
    
    <dependency>
      <groupId>org.aspectjgroupId>
      <artifactId>com.springsource.org.aspectj.weaverartifactId>
      <version>1.7.2.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-aopartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>

    
    <dependency>
      <groupId>commons-logginggroupId>
      <artifactId>commons-loggingartifactId>
      <version>1.1.3version>
    dependency>

    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-contextartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-coreartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-beansartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-expressionartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>

    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-jdbcartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <version>8.0.29version>
    dependency>
    
    <dependency>
      <groupId>c3p0groupId>
      <artifactId>c3p0artifactId>
      <version>0.9.1.2version>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-ormartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-txartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>

    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-webartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-webmvcartifactId>
      <version>4.0.0.RELEASEversion>
    dependency>

    
    <dependency>
      <groupId>org.apache.taglibsgroupId>
      <artifactId>taglibs-standard-implartifactId>
      <version>1.2.1version>
      <scope>runtimescope>
    dependency>
    
    <dependency>
      <groupId>org.apache.taglibsgroupId>
      <artifactId>taglibs-standard-specartifactId>
      <version>1.2.1version>
    dependency>

    
    <dependency>
      <groupId>org.mybatisgroupId>
      <artifactId>mybatisartifactId>
      <version>3.4.1version>
    dependency>
    
    <dependency>
      <groupId>org.mybatisgroupId>
      <artifactId>mybatis-springartifactId>
      <version>1.3.0version>
    dependency>

  dependencies>

  <build>
    <resources>
      <resource>
        <directory>src/main/javadirectory>
        <includes>
          <include>**/*.propertiesinclude>
          <include>**/*.xmlinclude>
        includes>
        <filtering>falsefiltering>
      resource>
      <resource>
        <directory>src/main/resourcesdirectory>
        <includes>
          <include>**/*.propertiesinclude>
          <include>**/*.xmlinclude>
        includes>
        <filtering>falsefiltering>
      resource>
    resources>
  build>

project>

数据库连接properties配置

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&characterEncoding=utf-8&serverTimezone=UTC&allowMultiQueries=true
jdbc.username=root
jdbc.password=root

web.xml配置文件

DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>SSMdisplay-name>

  
  <context-param>
    <param-name>contextConfigLocationparam-name>
    <param-value>classpath:applicationContext.xmlparam-value>
  context-param>

  
  <filter>
    <filter-name>characterEncodingFilterfilter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
    <init-param>
      <param-name>encodingparam-name>
      <param-value>UTF-8param-value>
    init-param>
    <init-param>
      <param-name>forceResponseEncodingparam-name>
      <param-value>trueparam-value>
    init-param>
    <init-param>
      <param-name>forceRequestEncodingparam-name>
      <param-value>trueparam-value>
    init-param>
  filter>
  <filter-mapping>
    <filter-name>characterEncodingFilterfilter-name>
    <url-pattern>/*url-pattern>
  filter-mapping>


  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
  listener>

  
  <servlet>
    <servlet-name>dispatcherServletservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    
    <init-param>
      <param-name>contextConfigLocationparam-name>
      <param-value>classpath:springmvc.xmlparam-value>
    init-param>
    
    <load-on-startup>1load-on-startup>
  servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServletservlet-name>
    <url-pattern>/url-pattern>
  servlet-mapping>

web-app>

SpringMVC配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    
    <context:component-scan base-package="per.xgt" use-default-filters="true">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>

    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        
        <property name="prefix" value="/WEB-INF/pages/">property>
        
        <property name="suffix" value=".jsp">property>
    bean>

    
    <mvc:default-servlet-handler/>
    
    <mvc:annotation-driven>mvc:annotation-driven>

beans>

Spring配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">

    
    <context:component-scan base-package="per.xgt">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>

    
    <context:property-placeholder location="classpath:jdbc.properties" />
    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}">property>
        <property name="jdbcUrl" value="${jdbc.url}">property>
        <property name="user" value="${jdbc.username}">property>
        <property name="password" value="${jdbc.password}">property>
    bean>

    
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource">property>
    bean>

    
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource">property>
        
        <property name="configLocation" value="classpath:mybatis-config.xml">property>
        
        <property name="mapperLocations" value="classpath*:per/xgt/dao/*.xml">property>
    bean>

    



    
    <mybatis-spring:scan base-package="per.xgt.dao" />

    
    <tx:annotation-driven />


beans>

Mybatis全局配置文件


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

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

configuration>

类和方法

  • POJO
public class Employee {

    private Integer id;
    private String empName;
    private String empGender;
    private String empEmail;

    public Employee(Integer id, String empName, String empGender, String empEmail) {
        this.id = id;
        this.empName = empName;
        this.empGender = empGender;
        this.empEmail = empEmail;
    }

    public Employee() {
    }

    public Integer getId() {
        return id;
    }

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

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getEmpGender() {
        return empGender;
    }

    public void setEmpGender(String empGender) {
        this.empGender = empGender;
    }

    public String getEmpEmail() {
        return empEmail;
    }

    public void setEmpEmail(String empEmail) {
        this.empEmail = empEmail;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", empName='" + empName + '\'' +
                ", empGender='" + empGender + '\'' +
                ", empEmail='" + empEmail + '\'' +
                '}';
    }

}
  • DAO
public interface EmployeeMapper {

    public Employee findOneById(Integer id);

    public List<Employee> findAllEmps();

}
  • Mapper.xml

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

    <select id="findOneById" resultType="per.xgt.entity.Employee">
        select * from emp where id = #{id}
    select>

    <select id="findAllEmps" resultType="per.xgt.entity.Employee">
        select * from emp
    select>

mapper>
  • Service接口
public interface EmployeeService {

    public List<Employee> findAllEmps();

}
  • ServiceImpl
@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    @Override
    public List<Employee> findAllEmps() {
        List<Employee> emps = employeeMapper.findAllEmps();
        return emps;
    }

}
  • Controller
@Controller
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @RequestMapping("findAllEmps")
    public String emps(Map<String,Object> map){
        List<Employee> emps = employeeService.findAllEmps();
        for (Employee emp : emps) {
            System.out.println(emp);
        }
        map.put("emps", emps);
        return "list";
    }

}

  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<h2>Hello World!h2>
<a href="findAllEmps">查询所有员工a>
body>
html>
  • list.jsp
<%--
  Created by IntelliJ IDEA.
  User: Valen
  Date: 2022/7/28
  Time: 16:53
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Titletitle>
head>
<body>
    <table>
        <tr>
            <td>idtd>
            <td>empNametd>
            <td>empGendertd>
            <td>empEmailtd>
        tr>
        <c:forEach items="${emps}" var="emp">
            <tr>
                <td>${emp.id}td>
                <td>${emp.empName}td>
                <td>${emp.empGender}td>
                <td>${emp.empEmail}td>
            tr>
        c:forEach>
    table>
body>
html>

插件

所有mybatis对象,都会通过下面封装后返回

parameterHandler = 
(ParameterHandler)this.interceptorChain.pluginAll(parameterHandler);

方法内部:获取所有的Interceprot(插件实现接口)(拦截器)

public Object pluginAll(Object target) {
        Interceptor interceptor;
        for(Iterator i$ = this.interceptors.iterator(); i$.hasNext(); target = interceptor.plugin(target)) {
            interceptor = (Interceptor)i$.next();
        }

        return target;
    }
// 返回target对象
target = interceptor.plugin(target))

插件机制:创建代理对象,通过增强拦截每一个方法执行,然后在方法前后执行增强方法

编写插件

  • 编写Interceptor实现类
public class MyPluginA implements Interceptor {
    /**
     * 拦截目标对象的目标方法的执行;
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 执行目标方法
        Object proceed = invocation.proceed();
        // 返回执行后的返回值
        return proceed;
    }

    /**
     * 包装梅花表对象,为目标对象创建一个代理对象
     * @param o
     * @return
     */
    @Override
    public Object plugin(Object o) {
        // 接住Plugin类的wrap方法来使用当前Interceptor包装目标对象
        Object wrap = Plugin.wrap(o, this);
        // 返回动态代理对象
        return wrap;
    }

    /**
     * 将插件注册时的property属性设置进来
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的信息:" + properties);
    }
}
  • 使用@Intercepts注解完成插件签名
// 完成插件签名,告诉mybatis当前插件用来拦截哪个对象的哪个方法;
@Intercepts({
        @Signature(type = StatementHandler.class,method = "parameterize",args = java.sql.Statement.class)
})
  • 将写好的插件注册到配置文件当中
<plugins>
        <plugin interceptor="per.xgt.config.MyPluginA">
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        plugin>
    plugins>

多个插件运行流程

创建动态代理的时候,是按照插件配置顺序创建层层代理对象,执行目标方法的之后,按照逆向顺序执行;

功能修改

// 完成插件签名,告诉mybatis当前插件用来拦截哪个对象的哪个方法;
@Intercepts({
        @Signature(type = StatementHandler.class,method = "parameterize",args = java.sql.Statement.class)
})
public class MyPluginA implements Interceptor {
    /**
     * 拦截目标对象的目标方法的执行;
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("intercept===:"+invocation.getMethod());
        // 改变方法参数
        System.out.println("当前拦截的目标对象:"+invocation.getTarget());
        Object target = invocation.getTarget();
        // 拿到target的源数据
        MetaObject metaObject = SystemMetaObject.forObject(target);
        Object value = metaObject.getValue("parameterHandler.parameterObject");
        System.out.println("所有参数:"+value);
        // 修改完要用的参数
        metaObject.setValue("parameterHandler.parameterObject",10);
        // 执行目标方法
        Object proceed = invocation.proceed();
        // 返回执行后的返回值
        return proceed;
    }

    /**
     * 包装梅花表对象,为目标对象创建一个代理对象
     * @param o
     * @return
     */
    @Override
    public Object plugin(Object o) {
        System.out.println("plugin===:" + o);
        // 接住Plugin类的wrap方法来使用当前Interceptor包装目标对象
        Object wrap = Plugin.wrap(o, this);
        // 返回动态代理对象
        return wrap;
    }

    /**
     * 将插件注册时的property属性设置进来
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的信息===:" + properties);
    }
}

分页插件PageHelper

引入依赖


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

配置

  • 没有Spring直接配置在mybatis配置文件中
<configuration>

    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    settings>
    
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    plugins>

configuration>
  • 和Spring整合配置
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource">property>
        
        <property name="configLocation" value="classpath:mybatis-config.xml">property>
        
        <property name="mapperLocations" value="classpath*:per/xgt/dao/*.xml">property>
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <props>
                            <prop key="helperDialect">mysqlprop>
                        props>
                    property>
                bean>
            array>
        property>
    bean>
  • PageHelper参数

分页插件可选参数如下:

  • dialect:默认情况下会使用 PageHelper 方式进行分页,如果想要实现自己的分页逻辑,可以实现 Dialect(com.github.pagehelper.Dialect) 接口,然后配置该属性为实现类的全限定名称。

下面几个参数都是针对默认 dialect 情况下的参数。使用自定义 dialect 实现时,下面的参数没有任何作用。

  • helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。
    配置时,可以使用下面的缩写值:oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
    特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
    你也可以实现 AbstractHelperDialect,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。
  • offsetAsPageNum:默认值为 false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。
  • rowBoundsWithCount:默认值为false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。
  • pageSizeZero:默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
  • reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
  • params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值;
    可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值;
    默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
  • supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest。
  • autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver),用法和注意事项参考下面的场景五。
  • closeConn:默认值为 true。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为 false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。

重要提示:当 offsetAsPageNum=false 的时候,由于 PageNum 问题,RowBounds查询的时候 reasonable 会强制为 false。使用 PageHelper.startPage 方法不受影响。

简单使用

@RequestMapping("findAllEmps")
    public String emps(Map<String,Object> map){
        PageHelper.startPage(1, 5);
        List<Employee> emps = employeeService.findAllEmps();
        System.out.println("======");
        for (Employee emp : emps) {
            System.out.println(emp);
        }
        System.out.println("======");
        PageInfo<Employee> list = new PageInfo<Employee>(emps);
        map.put("pageInfo", list);
        System.out.println(list);
        List<Employee> employees = list.getList();
        for (Employee employee : employees) {
            System.out.println(employee);
        }
        return "list";
    }

注意:

  • 一定要在查询方法的前一步使用PageHelper.startPage(首页,页面大小);
  • 想要使用页面的信息时使用pageInfo;
  • PageInfo<实体类> pageInfo = new PageInfo<>(数据库中获取到的信息);

pageInfo内的内容

public class PageInfo<T> implements Serializable {
private static final long serialVersionUID = 1L;
//当前页
private int pageNum;
//每页的数量
private int pageSize;
//当前页的数量
private int size;
//由于startRow 和endRow 不常用,这里说个具体的用法
//可以在页面中"显示startRow 到endRow 共size 条数据"
//当前页面第一个元素在数据库中的行号
private int startRow;
//当前页面最后一个元素在数据库中的行号
private int endRow;
//总记录数
private long total;
//总页数
private int pages;
//结果集
private List<T> list;
//前一页
private int prePage;
//下一页
private int nextPage;
//是否为第一页
private boolean isFirstPage = false;
//是否为最后一页
private boolean isLastPage = false;
//是否有前一页
private boolean hasPreviousPage = false;
//是否有下一页
private boolean hasNextPage = false;
//导航页码数
private int navigatePages;
//所有导航页号
private int[] navigatepageNums;
//导航条上的第一页
private int navigateFirstPage;
//导航条上的最后一页
private int navigateLastPage;
}

Page内的内容

public class Page<E> extends ArrayList<E> {
    private static final long serialVersionUID = 1L;
    //当前页码
    private int pageNum;
    //每一页记录数
    private int pageSize;
    //当前页面第一个元素在数据库中的行号
    private int startRow;
    //当前页面最后一个元素在数据库中的行号
    private int endRow;
    //总记录数
    private long total;
    //总页码
    private int pages;
    //
    private boolean count;
    //
    private Boolean reasonable;
    //
    private Boolean pageSizeZero;
}

批量BatchExecutor

@Test
    public void test18() throws IOException {
        SqlSessionFactory sqlSessionFactory = get();
        // 可以执行批量操作的SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        long start = System.currentTimeMillis();
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee employee = new Employee();
        for (int i = 0; i < 10000; i++) {
            employee.setEmpGender(i%2==0?"0":"1");
            employee.setEmpName("批量"+(i+1));
            employee.setEmpEmail(employee.getEmpName() + "@163.com");
            int batch = mapper.addEmpsBatch(employee);
        }
        sqlSession.commit();
        long end = System.currentTimeMillis();
        sqlSession.close();
        System.out.println("执行时长:" + (end - start));
    }

Spring中使用批量SqlSession

  • spring配置文件

    <bean class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean">constructor-arg>
        <constructor-arg name="executorType" value="BATCH">constructor-arg>
    bean>
  • 使用
@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private SqlSession sqlSession;

    @Override
    public List<Employee> findAllEmps() {
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        // 执行批量操作
        /*
        * xxxxxx
        * */

        List<Employee> emps = employeeMapper.findAllEmps();
        return emps;
    }

}

Oracle的存储过程

使用游标返回数据列表

  • 结果集对象
public class Page {

    private int start;
    private int end;
    private int count;
    private List<Employee> emps;

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getEnd() {
        return end;
    }

    public void setEnd(int end) {
        this.end = end;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public List<Employee> getEmps() {
        return emps;
    }

    public void setEmps(List<Employee> emps) {
        this.emps = emps;
    }
}
  • 调用存储过程

    <select id="getPageByProcedure" statementType="CALLABLE" databaseId="oracle">
        {
            call emp_getpage(
                #{start,mode=IN,jdbcType=INTEGER},
                #{end,mode=IN,jdbcType=INTEGER},
                #{count,mode=OUT,jdbcType=INTEGER},
                #{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=pageEmp}
            )
        }
    select>
    <resultMap id="pageEmp" type="per.xgt.entity.Employee">
        <id column="id" property="id" />
        <result column="emp_name" property="empName" />
        <result column="emp_email" property="empEmail" />
        <result column="emp_gender" property="empGender" />
    resultMap>

枚举类型

mybatis 处理枚举类型默认是存储枚举的名字,可以改为存储枚举的索引

<typeHandlers>
        
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="per.xgt.entity.EmpStatus"/>
    typeHandlers>
public enum EmpStatus {

    LOGIN,LOGOUT,REMOVE

}
public class Employee implements Serializable {

    private Integer id;
    private String empName;
    private String empGender;
    private String empEmail;

    private Department dept;

    // 员工状态
    private EmpStatus empStatus = EmpStatus.LOGOUT;

    public EmpStatus getEmpStatus() {
        return empStatus;
    }

    public void setEmpStatus(EmpStatus empStatus) {
        this.empStatus = empStatus;
    }

    public Employee(Integer id, String empName, String empGender, String empEmail, EmpStatus empStatus) {
        this.id = id;
        this.empName = empName;
        this.empGender = empGender;
        this.empEmail = empEmail;
        this.empStatus = empStatus;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", empName='" + empName + '\'' +
                ", empGender='" + empGender + '\'' +
                ", empEmail='" + empEmail + '\'' +
                ", dept=" + dept +
                ", empStatus=" + empStatus +
                '}';
    }

    public Employee() {
    }

    public Employee(Integer id, String empName, String empGender, String empEmail, Department dept) {
        this.id = id;
        this.empName = empName;
        this.empGender = empGender;
        this.empEmail = empEmail;
        this.dept = dept;
    }

    public Employee(Integer id, String empName, String empGender, String empEmail) {
        this.id = id;
        this.empName = empName;
        this.empGender = empGender;
        this.empEmail = empEmail;
    }

    public Department getDept() {
        return dept;
    }

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

    public Integer getId() {
        return id;
    }

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

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getEmpGender() {
        return empGender;
    }

    public void setEmpGender(String empGender) {
        this.empGender = empGender;
    }

    public String getEmpEmail() {
        return empEmail;
    }

    public void setEmpEmail(String empEmail) {
        this.empEmail = empEmail;
    }



}
public int insertEmpByEnum(Employee employee);
<insert id="insertEmpByEnum" parameterType="per.xgt.entity.Employee" useGeneratedKeys="true" keyProperty="id">
        insert into emp (emp_name,emp_gender,emp_email,emp_status)
        values (#{empName},#{empGender},#{empEmail},#{empStatus})
    insert>

测试

@Test
    public void test19() throws IOException {
        SqlSessionFactory sqlSessionFactory = get();
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee employee = new Employee(null, "enum", "1", "[email protected]");
        mapper.insertEmpByEnum(employee);
        System.out.println(employee.getId());
        sqlSession.close();
    }

自定义枚举类型处理器

  • 枚举类
public enum EmpStatus {

    LOGIN(1001,"已登录"),
    LOGOUT(1002,"已登出"),
    REMOVE(1003,"不存在");

    private Integer code;
    private String msg;

    private EmpStatus(int 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 1001:return LOGIN;
            case 1002:return LOGOUT;
            case 1003:return REMOVE;
            default:return LOGOUT;
        }
    }

}

  • mybatis配置
<typeHandlers>
        <typeHandler handler="per.xgt.config.MyEnumHandler" javaType="per.xgt.entity.EmpStatus"/>
    typeHandlers>
  • 标签内指定使用类型处理器
#{empStatus,typeHandler=per.xgt.config.MyEnumHandler}

如果是查询可以在resultMap中指定

<result column="empName" property="emp_name" typeHandler="per.xgt.config.MyEnumHandler"/>

你可能感兴趣的:(JAVA框架,mybatis,java,数据库)