文章目录

  • 1、前言
  • 2、什么是通用mapper
  • 3、使用流程示例
  • 3.1 导入依赖
  • 3.2 编写实体类
  • 3.3 创建Mapper
  • 3.4 配置通用Mapper
  • 3.5 测试
  • 4、常用注解
  • 4.1 @Table
  • 4.2 @Column
  • 4.3 @Id
  • 4.4 @GeneratedValue
  • 4.5 @Transient
  • 5、常用方法
  • 5.1 selectOne
  • 5.2 xxxByPrimaryKey
  • 5.3 xxxSelective
  • 6、QBC查询
  • 7、MBG
  • 7.1 介绍
  • 7.2 使用方法
  • 7.2.1 导入依赖
  • 7.2.2 编写MBG配置文件
  • 7.3 配置Generator插件
  • 8、自定义Mapper
  • 8.1 通用Mapper继承关系
  • 8.2 自定义
  • 9、接口拓展
  • 9.1 导入依赖
  • 9.2 编写MapperTemplate子类
  • 9.3 自定义Mapper
  • 9.4 使用
  • 9.5 小结
  • 10、二级缓存
  • 11、类型处理器
  • 11.1 复杂类型
  • 11.1.1 使用场景
  • 11.1.2 定义类型处理器
  • 11.1.3 注册类型处理器
  • 11.2 枚举类型
  • 11.2.1 方法一
  • 11.2.2 方法二


1、前言

  Mybati虽然极大的提高了程序员对数据库的操作, 但还是存在以下痛点:
  1、mapper.xml文件里有大量的sql,当数据库表字段变动,配置文件就要修改;
  2、需要自己实现sql分页,select * from table where . . . limit 1,3;
  3、数据库可移植性差:如果项目更换数据库,比如oracle–>mysql,mapper.xml中的sql要重新写,因为Oracle的PLSQL 和mysql 支持的函数是不同的;
  4、生成的代码量过大;
  5、批量操作,批量插入,批量更新,需要自写。

2、什么是通用mapper

  通用mapper的作用就是自动生成我们常用的增删改查SQL语句。是中国程序员在 MBG 的基础上结合了部分 JPA 注解做出来的。
  Github地址:https://gitee.com/free/Mapper.git

3、使用流程示例

  先创建一个数据库用于案例测试:

CREATE TABLE `tabple_emp` (
`emp_id` int NOT NULL AUTO_INCREMENT ,
`emp_name` varchar(500) NULL ,
`emp_salary` double(15,5) NULL ,
`emp_age` int NULL ,
PRIMARY KEY (`emp_id`)
);

INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('tom', '1254.37', '27');
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('jerry', '6635.42', '38');
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('bob', '5560.11', '40');
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('kate', '2209.11', '22');
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('justin', '4203.15', '30');

3.1 导入依赖

<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper</artifactId>
    <version>最新版本</version>
</dependency>

  最新版本可以去maven中央仓库查看:

baseMapper获取最大值 basemapper的使用_baseMapper获取最大值

3.2 编写实体类

public class Employee {
    private Integer empId;
    private String empName;
    private Double empSalary;
    private Integer empAge;

	// ..有参构造、无参构造、set、get、toString
}

3.3 创建Mapper

import tk.mybatis.mapper.common.Mapper;

public interface EmployeeMapper extends Mapper<Employee> {
}

  这里继承了 tk.mybatis.mapper.common.Mapper 接口,在接口上指定了泛型类型 Employee。当你继承了 Mapper 接口后,此时就已经有了针对 Employee的大量方法,方法如下:

baseMapper获取最大值 basemapper的使用_数据库_02

3.4 配置通用Mapper

  为了让我们自己创建的Mapper成为通用Mapper,让项目在启动的时候,把上述方法都自动生成好,这样在运行时就可以使用上面所有的方法。
  根据不同的开发环境,需要不同的配置方式,完整的内容可以 在https://github.com/abel533/Mapper/wiki/1.integration中查看文档,我们这里以最常见的 Spring 和 MyBatis 集成为例。
  在集成 Spring 的环境中使用 MyBatis 接口方式时,需要配置 MapperScannerConfigurer,在这种情况下使用通用 Mapper,只需要修改spring配置文件如下:

<!-- 整合通用Mapper所需要做的配置修改: -->
<!-- 原始全类名:org.mybatis.spring.mapper.MapperScannerConfigurer -->
<!-- 通用Mapper使用:tk.mybatis.spring.mapper.MapperScannerConfigurer -->
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="cn.klb.mapper.mappers"/>
</bean>

  <property>的value为我们创建的Mapper的所在包。

3.5 测试

  编写测试方法来访问数据库:
  service:

@Service
public class EmployeeService {
    @Autowired
    public EmployeeMapper employeeMapper;

    public Employee getOne(Employee employeeQueryCondition) {
        return employeeMapper.selectOne(employeeQueryCondition);
    }
}
public class EmployeeMapperTest {
    private ApplicationContext iocContainer = new ClassPathXmlApplicationContext("spring-context.xml");
    private EmployeeService employeeService = iocContainer.getBean(EmployeeService.class);

    @Test
    public void testSelectOne() {

        //1.创建封装查询条件的实体类对象
        Employee employeeQueryCondition = new Employee(null, "bob", 5560.11, null);

        //2.执行查询
        Employee employeeQueryResult = employeeService.getOne(employeeQueryCondition);

        //3.打印
        System.out.println(employeeQueryResult);
    }
}

4、常用注解

4.1 @Table

  作用:建立实体类和数据库表之间的对应关系。

  默认规则:实体类类名首字母小写作为表名。Employee 类→employee 表。

  用法:在@Table 注解的 name 属性中指定目标数据库表的表名。

baseMapper获取最大值 basemapper的使用_java_03

4.2 @Column

  作用:建立实体类字段和数据库表字段之间的对应关系。

  默认规则:

    实体类字段:驼峰式命名

    数据库表字段:使用“_”区分各个单词

  用法:在@Column 注解的 name 属性中指定目标字段的字段名。

baseMapper获取最大值 basemapper的使用_mybatis_04

4.3 @Id

  通用 Mapper 在执行 xxxByPrimaryKey(key)方法时,有两种情况:
  情况 1:没有使用@Id 注解明确指定主键字段,生成的sql语句如下:

SELECT emp_id,emp_name,emp_salary_apple,emp_age FROM tabple_emp WHERE emp_id = ? AND emp_name = ? AND emp_salary_apple = ? AND emp_age = ?

  之所以会生成上面这样的 WHERE 子句是因为通用 Mapper 将实体类中的所有字段都拿来放在一起作为联合主键。

  情况 2:使用@Id 主键明确标记和数据库表中主键字段对应的实体类字段。

baseMapper获取最大值 basemapper的使用_mysql_05

4.4 @GeneratedValue

  作用:让通用 Mapper 在执行 insert 操作之后将数据库自动生成的主键值回写到实体类对象中。

  自增主键用法:

baseMapper获取最大值 basemapper的使用_baseMapper获取最大值_06


  序列主键用法:

baseMapper获取最大值 basemapper的使用_baseMapper获取最大值_07

4.5 @Transient

  用于标记不与数据库表字段对应的实体类字段。

@Transient
private String otherThings; //非数据库表中字段

5、常用方法

5.1 selectOne

  通用 Mapper 替我们自动生成的 SQL 语句情况:

baseMapper获取最大值 basemapper的使用_baseMapper获取最大值_08


  实体类封装查询条件生成 WHERE 子句的规则:

  1、使用非空的值生成 WHERE 子句;

  2、在条件表达式中使用“=”进行比较。

5.2 xxxByPrimaryKey

  需要使用@Id 主键明确标记和数据库表主键字段对应的实体类字段,否则通用Mapper 会将所有实体类字段作为联合主键。

5.3 xxxSelective

  非主键字段如果为 null 值,则不加入到 SQL 语句中。

6、QBC查询

  QBC全称为Query By Criteria,Criteria 是 Criterion 的复数形式。意思是:规则、标准、准则。在 SQL 语句中相当于查询条件。
  QBC 查询是将查询条件通过 Java 对象进行模块化封装。
  示例代码:

@Test
public void testSelectByExample() {
	//目标:WHERE (emp_salary>? AND emp_age<?) OR (emp_salary<? AND emp_age>?)
	//1.创建Example对象
    Example example = new Example(Employee.class);

    //***********************
    //i.设置排序信息
    example.orderBy("empSalary").asc().orderBy("empAge").desc();

    //ii.设置“去重”
    example.setDistinct(true);

    //iii.设置select字段
    example.selectProperties("empName","empSalary");
    //***********************

    //2.通过Example对象创建Criteria对象
    Example.Criteria criteria01 = example.createCriteria();
    Example.Criteria criteria02 = example.createCriteria();

    //3.在两个Criteria对象中分别设置查询条件
    //property参数:实体类的属性名
    //value参数:实体类的属性值
    criteria01.andGreaterThan("empSalary", 3000)
              .andLessThan("empAge", 25);

    criteria02.andLessThan("empSalary", 5000)
              .andGreaterThan("empAge", 30);

    //4.使用OR关键词组装两个Criteria对象
    example.or(criteria02);

    //5.执行查询
    List<Employee> empList = employeeService.getEmpListByExample(example);

    for (Employee employee : empList) {
        System.out.println(employee);
    }
}

7、MBG

7.1 介绍

  MBG全称为Mybatis Generator,用于根据数据表生成Mybatis所需的实体类、配置文件和Mapper接口。

baseMapper获取最大值 basemapper的使用_数据库_09


  通用 Mapper 专用代码生成器生成的 Model 会在原有基础上增加 @Table,@Id,@Column 等注解,方便自动会数据库字段进行映射。

  参考文档:https://github.com/abel533/Mapper/wiki/4.1.mappergenerator

7.2 使用方法

7.2.1 导入依赖

<!--MBG核心-->
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.3.6</version>
</dependency>

<!-- 通用 Mapper -->
<!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper</artifactId>
    <version>4.0.0</version>
</dependency>

<!-- 如果你只需要用到通用 Mapper 中的插件,可以只引入 mapper-generator -->
<!-- 注意,这个包不需要和上面的 mapper 同时引入,mapper 中包含 generator -->
<!-- https://mvnrepository.com/artifact/tk.mybatis/mapper-generator -->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-generator</artifactId>
    <version>1.0.0</version>
</dependency>

  同时在pom.xml文件中配置一些属性:

<properties>
    <!-- ${basedir}引用工程根目录 -->
    <!-- targetJavaProject:声明存放源码的目录位置 -->
    <targetJavaProject>${basedir}/src/main/java</targetJavaProject>

    <!-- targetMapperPackage:声明MBG生成XxxMapper接口后存放的package位置 -->
    <targetMapperPackage>cn.klb.shop.mappers</targetMapperPackage>

    <!-- targetModelPackage:声明MBG生成实体类后存放的package位置 -->
    <targetModelPackage>cn.klb.shop.entities</targetModelPackage>

    <!-- targetResourcesProject:声明存放资源文件和XML配置文件的目录位置 -->
    <targetResourcesProject>${basedir}/src/main/resources</targetResourcesProject>

    <!-- targetXMLPackage:声明存放具体XxxMapper.xml文件的目录位置 -->
    <targetXMLPackage>mappers</targetXMLPackage>

    <!-- 通用Mapper的版本号 -->
    <mapper.version>4.0.0-beta3</mapper.version>

    <!-- MySQL驱动版本号 -->
    <mysql.version>5.1.37</mysql.version>
</properties>

7.2.2 编写MBG配置文件

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

<!--suppress MybatisGenerateCustomPluginInspection -->
<generatorConfiguration>
    <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="beginningDelimiter" value="`" />
        <property name="endingDelimiter" value="`" />

        <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
            <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
            <property name="caseSensitive" value="true"/>
            <property name="forceAnnotation" value="true"/>
            <property name="beginningDelimiter" value="`"/>
            <property name="endingDelimiter" value="`"/>
        </plugin>

        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/common_mapper?useUnicode=true&characterEncoding=utf8"
                        userId="root"
                        password="root">
        </jdbcConnection>

        <!-- 配置Java实体类存放位置 -->
        <javaModelGenerator
                targetPackage="${targetModelPackage}"
                targetProject="${targetJavaProject}" />

        <!-- 配置XxxMapper.xml存放位置 -->
        <sqlMapGenerator
                targetPackage="${targetXMLPackage}"
                targetProject="${targetResourcesProject}" />

        <!-- 配置XxxMapper.java存放位置 -->
        <javaClientGenerator
                targetPackage="${targetMapperPackage}"
                targetProject="${targetJavaProject}"
                type="XMLMAPPER" />

        <table tableName="tabple_emp" domainObjectName="Employee">
            <!-- 配置主键生成策略 -->
            <generatedKey column="emp_id" sqlStatement="Mysql" identity="true" />
        </table>
    </context>
</generatorConfiguration>

7.3 配置Generator插件

  配置插件很简单,就是配置maven插件,在pom.xml文件中添加:

<build>
	<plugins>
		<plugin>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-maven-plugin</artifactId>
			<version>1.3.6</version>
			<configuration>
				<configurationFile>
					${basedir}/src/main/resources/generator/generatorConfig.xml
				</configurationFile>
				<overwrite>true</overwrite>
				<verbose>true</verbose>
			</configuration>
		<dependencies>
			<dependency>
				<groupId>mysql</groupId>
				<artifactId>mysql-connector-java</artifactId>
				<version>5.1.29</version>
			</dependency>
			<dependency>
				<groupId>tk.mybatis</groupId>
				<artifactId>mapper</artifactId>
				<version>4.0.0</version>
			</dependency>
		</dependencies>
		</plugin>
	</plugins>
</build>

8、自定义Mapper

8.1 通用Mapper继承关系

  我们可以根据开发的实际需要对 Mapper接口进行定制。

  下图是tk.mybatis.mapper.common.Mapper的继承图:

baseMapper获取最大值 basemapper的使用_mybatis_10


  有时候我们的业务不需要那么多预提供的方法,所以我们可以继承相应的父接口。

8.2 自定义

  创建一个目录专门存放自定义的Mapper:

baseMapper获取最大值 basemapper的使用_java_11

package cn.klb.mapper.mine_mappers;

import tk.mybatis.mapper.common.base.select.SelectAllMapper;
import tk.mybatis.mapper.common.example.SelectByExampleMapper;

public interface MyMapper<T> 
		extends SelectAllMapper<T>,SelectByExampleMapper<T> {

}

  使用自定义的Mapper:

package cn.klb.mapper.mappers;

import cn.klb.mapper.entities.Employee;
import cn.klb.mapper.mine_mappers.MyMapper;

public interface EmployeeMapper extends MyMapper<Employee> {

}

  spring的配置文件中:

<!-- 整合通用Mapper所需要做的配置修改: -->
<!-- 原始全类名:org.mybatis.spring.mapper.MapperScannerConfigurer -->
<!-- 通用Mapper使用:tk.mybatis.spring.mapper.MapperScannerConfigurer -->
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="cn.klb.mapper.mappers"/>
</bean>

  修改为:

<!-- 整合通用Mapper所需要做的配置修改: -->
<!-- 原始全类名:org.mybatis.spring.mapper.MapperScannerConfigurer -->
<!-- 通用Mapper使用:tk.mybatis.spring.mapper.MapperScannerConfigurer -->
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="cn.klb.mapper.mappers"/>
	<property name="properties">
		<value>
			mappers=cn.klb.mapper.mine_mappers.MyMapper
		</value>
	</property>
</bean>

9、接口拓展

  自定义Mapper是对已提供的方法进行重新组合了一下,不属于拓展。

  下面来自定义一个Mapper实现批量更新操作。

baseMapper获取最大值 basemapper的使用_mybatis_12


  拓展步骤如下:

9.1 导入依赖

<dependencies>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>4.0.0-beta3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>
    </dependencies>

9.2 编写MapperTemplate子类

  自定义一个类,继承tk.mybatis.mapper.mapperhelper.MapperTemplate

package cn.klb.mapper.mine_mappers;

import java.util.Set;

import org.apache.ibatis.mapping.MappedStatement;

import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.MapperTemplate;
import tk.mybatis.mapper.mapperhelper.SqlHelper;

public class MyBatchUpdateProvider extends MapperTemplate {

	public MyBatchUpdateProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
		super(mapperClass, mapperHelper);
	}

	public String batchUpdate(MappedStatement statement) {
		//1.创建StringBuilder用于拼接SQL语句的各个组成部分
		StringBuilder builder = new StringBuilder();
		
		//2.拼接foreach标签
		builder.append("<foreach collection=\"list\" item=\"record\" separator=\";\" >");
		
		//3.获取实体类对应的Class对象
		Class<?> entityClass = super.getEntityClass(statement);
		
		//4.获取实体类在数据库中对应的表名
		String tableName = super.tableName(entityClass);
		
		//5.生成update子句
		String updateClause = SqlHelper.updateTable(entityClass, tableName);
		
		builder.append(updateClause);
		
		builder.append("<set>");
		
		//6.获取所有字段信息
		Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);
		
		String idColumn = null;
		String idHolder = null;
		
		for (EntityColumn entityColumn : columns) {
			
			boolean isPrimaryKey = entityColumn.isId();
			
			//7.判断当前字段是否为主键
			if(isPrimaryKey) {
				
				//8.缓存主键的字段名和字段值
				idColumn = entityColumn.getColumn();
				
				//※返回格式如:#{record.age,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
				idHolder = entityColumn.getColumnHolder("record");
				
			}else {
				
				//9.使用非主键字段拼接SET子句
				String column = entityColumn.getColumn();
				String columnHolder = entityColumn.getColumnHolder("record");
				
				builder.append(column).append("=").append(columnHolder).append(",");
				
			}
			
		}
		
		builder.append("</set>");
		
		//10.使用前面缓存的主键名、主键值拼接where子句
		builder.append("where ").append(idColumn).append("=").append(idHolder);
		
		builder.append("</foreach>");
		
		//11.将拼接好的字符串返回
		return builder.toString();
	}
}

  其中最关键的就是batchUpdate方法,里面编写了批量更新的逻辑,其实就是以前的mapper.xml中的sql语句拼接。

9.3 自定义Mapper

  自定义一个Mapper,里面包含一个名字为batchUpdate的方法,并使用@UpdateProvider注解,属性type的值为第一步定义的类的类对象,method属性的值为固定值dynamicSQL

package cn.klb.mapper.mine_mappers;

import java.util.List;

import org.apache.ibatis.annotations.UpdateProvider;

public interface MyBatchUpdateMapper<T> {
	
	@UpdateProvider(type=MyBatchUpdateProvider.class, method="dynamicSQL")
	void batchUpdate(List<T> list);

}

9.4 使用

  上面一步写好的自定义Mapper后,就可以按照通用Mapper的方式来使用,首先是继承这个自定义的Mapper:

package cn.klb.mapper.mine_mappers;

import tk.mybatis.mapper.common.base.select.SelectAllMapper;
import tk.mybatis.mapper.common.example.SelectByExampleMapper;

public interface MyMapper<T> 
		extends SelectAllMapper<T>,SelectByExampleMapper<T>,MyBatchUpdateMapper<T> {
}

  然后使用MyMapper:

package cn.klb.mapper.mappers;

import cn.klb.mapper.entities.Employee;
import cn.klb.mapper.mine_mappers.MyMapper;

public interface EmployeeMapper extends MyMapper<Employee> {

}

  然后修改spring的配置文件:

<!-- 整合通用Mapper所需要做的配置修改: -->
<!-- 原始全类名:org.mybatis.spring.mapper.MapperScannerConfigurer -->
<!-- 通用Mapper使用:tk.mybatis.spring.mapper.MapperScannerConfigurer -->
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="cn.klb.mapper.mappers"/>
	<property name="properties">
		<value>
			mappers=cn.klb.mapper.mine_mappers.MyMapper
		</value>
	</property>
</bean>

  编写测试类:

@Test
public void testBatch(){
	ClassPathXmlApplicationContext iocContainer = new ClassPathXmlApplicationContext("spring-context.xml");
	
	EmployeeService employeeService = iocContainer.getBean(EmployeeService.class);
	
	List<Employee> empList = new ArrayList<>();
	
	empList.add(new Employee(9, "newName01", 111.11, 10));
	empList.add(new Employee(10, "newName02", 222.22, 20));
	empList.add(new Employee(11, "newName03", 333.33, 30));
	
	employeeService.batchUpdateEmp(empList);
	
	iocContainer.close();
}

9.5 小结

baseMapper获取最大值 basemapper的使用_数据库_13

10、二级缓存

  1、MyBatis 配置文件开启二级缓存功能

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

  2、 在 XxxMapper 接口上使用@CacheNamespace 注解:

@CacheNamespace
public interface EmployeeMapper extends MyMapper<Employee> {
}

11、类型处理器

11.1 复杂类型

11.1.1 使用场景

  如果我们的数据表对应的实体类是复杂类型:

@Table(name="table_user")
public class User {
	
	@Id
	private Integer userId;
	private String userName;
	private Address address;
	private SeasonEnum season;

	// set\get\toString...
}

  其中Address是复杂类型:

public class Address {
	
	private String province;
	private String city;
	private String street;
	// set\get\toString...
}

  通用 Mapper 默认情况下会忽略复杂类型,对复杂类型不进行“从类到表”的映射。也就是说,如果实体类存在复杂类型,会赋值失败。

  解决方法就是使用类型处理器。

baseMapper获取最大值 basemapper的使用_mybatis_14

11.1.2 定义类型处理器

  自定义的类型处理器需要继承org.apache.ibatis.type.BaseTypeHandler

package cn.klb.mapper.handlers;

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

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

import cn.klb.mapper.entities.Address;

public class AddressTypeHandler extends BaseTypeHandler<Address> {

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, Address address, JdbcType jdbcType) throws SQLException {
		
		//1.对address对象进行验证
		if(address == null) {
			return ;
		}
		
		//2.从address对象中取出具体数据
		String province = address.getProvince();
		String city = address.getCity();
		String street = address.getStreet();
		
		//3.拼装成一个字符串
		//规则:各个值之间使用“,”分开
		StringBuilder builder = new StringBuilder();
		builder.append(province).append(",").append(city).append(",").append(street);
		
		String parameterValue = builder.toString();
		
		//4.设置参数
		ps.setString(i, parameterValue);
	}

	@Override
	public Address getNullableResult(ResultSet rs, String columnName) throws SQLException {
		
		//1.根据字段名从rs对象中获取字段值
		String columnValue = rs.getString(columnName);
		
		//2.验证columnValue是否有效
		if(columnValue == null || columnValue.length() == 0 || !columnValue.contains(",")) {
			return null;
		}
		
		//3.根据“,”对columnValue进行拆分
		String[] split = columnValue.split(",");
		
		//4.从拆分结果数组中获取Address需要的具体数据
		String province = split[0];
		String city = split[1];
		String street = split[2];
		
		//5.根据具体对象组装一个Address对象
		Address address = new Address(province, city, street);
		
		return address;
	}

	@Override
	public Address getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		//1.根据字段名从rs对象中获取字段值
		String columnValue = rs.getString(columnIndex);
		
		//2.验证columnValue是否有效
		if(columnValue == null || columnValue.length() == 0 || !columnValue.contains(",")) {
			return null;
		}
		
		//3.根据“,”对columnValue进行拆分
		String[] split = columnValue.split(",");
		
		//4.从拆分结果数组中获取Address需要的具体数据
		String province = split[0];
		String city = split[1];
		String street = split[2];
		
		//5.根据具体对象组装一个Address对象
		Address address = new Address(province, city, street);
		
		return address;
	}

	@Override
	public Address getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		//1.根据字段名从rs对象中获取字段值
		String columnValue = cs.getString(columnIndex);
		
		//2.验证columnValue是否有效
		if(columnValue == null || columnValue.length() == 0 || !columnValue.contains(",")) {
			return null;
		}
		
		//3.根据“,”对columnValue进行拆分
		String[] split = columnValue.split(",");
		
		//4.从拆分结果数组中获取Address需要的具体数据
		String province = split[0];
		String city = split[1];
		String street = split[2];
		
		//5.根据具体对象组装一个Address对象
		Address address = new Address(province, city, street);
		
		return address;
	}

}

11.1.3 注册类型处理器

  方法一(字段级别):在对应复杂属性上加@ColumnType

@ColumnType(typeHandler=AddressTypeHandler.class)
private Address address;

  方法二(全局):在 MyBatis 配置文件中配置 typeHandlers:

<typeHandlers>
	<!-- handler属性:指定自定义类型转换器全类名 -->
	<!-- javaType属性:指定需要使用“自定义类型转换器”进行类型处理的实体类型 -->
	<typeHandler
		handler="cn.klb.mapper.handlers.AddressTypeHandler"
		javaType="cn.klb.mapper.entities.Address"/>
			
</typeHandlers>

11.2 枚举类型

11.2.1 方法一

  让通用 Mapper 把枚举类型作为简单类型处理,增加一个通用 Mapper 的配置项,在 Spring 配置文件中找到 MapperScannerConfigurer:

<!-- 整合通用Mapper所需要做的配置修改: -->
<!-- 原始全类名:org.mybatis.spring.mapper.MapperScannerConfigurer -->
<!-- 通用Mapper使用:tk.mybatis.spring.mapper.MapperScannerConfigurer -->
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="cn.klb.mapper.mappers"/>
	<property name="properties">
		<value>
			enumAsSimpleType=true
		</value>
	</property>
</bean>

  本质上就是使用了org.apache.ibatis.type.EnumTypeHandler<E>

11.2.2 方法二

  为枚举类型配置对应的类型处理器,和复杂类型一模一样操作。