概述

通用mapper可以替我们生成常用增删改查操作的 SQL 语句。

代码官方发布地址:

  • https://gitee.com/free
  • https://gitee.com/free/Mapper/wikis/1.1-java?parent=1.integration

快速入门

创建测试数据

1) SQL

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');

2) Java实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name="tabple_emp")
public class Employee {
    private Integer empId;
    private String empName;
    private Double empSalary;
    private Integer empAge;
}

搭建 MyBatis+Spring 开发环境

mybatis-config.xml spring-context.xml jdbc.properties

集成 Mapper

1)加入Maven依赖信息

<dependency>
		<groupId>tk.mybatis</groupId>
		<artifactId>mapper</artifactId>
		<version>4.0.0-beta3</version>
</dependency>

2)修改Spring配置文件

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

3)创建mapper 和 services

cn.silince.mapper.services;

/**
* 具体操作数据库的 Mapper 接口,需要继承通用 Mapper 提供的核心接口:Mapper<Employee>
* 泛型类型就是实体类的类型 
*/
public interface EmployeeMapper extends Mapper<Employee> {
}

package cn.silince.mapper.services;

@Service
public class EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    public Employee getOne(Employee employeeQueryCondition) {
        return employeeMapper.selectOne(employeeQueryCondition);
    }
}

测试

public class EmployeeMapperTest extends Object {
    private ApplicationContext iocContainer = new ClassPathXmlApplicationContext("spring-context.xml");
    private EmployeeService employeeService = iocContainer.getBean(EmployeeService.class);

    @Test
    public void selectOne() {
        // 1. 创建封装查询条件的实体类对象
        Employee employeeQueryCondition = new Employee(null, "bob", 5560.11, null);
        // 2. 执行可查询条件
        Employee employeeQueryResult =employeeService.getOne(employeeQueryCondition);
        System.out.println(employeeQueryResult);
    }
}

常用注解

@Table 注解

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

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

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

@Data
@Table(name="tabple_emp")
public class Employee {
    private Integer empId;
    private String empName;
    private Double empSalary;
    private Integer empAge;
}

@Column 注解

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

默认规则:

  • 实体类字段:驼峰式命名
  • 数据库表字段:使用“_”区分各个单词

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

@Column(name="emp_salary_apple")
private Double empSalary;

@Id 注解

通用 Mapper 在执行 xxxByPrimaryKey(key)方法时,有两种情况。

  • 情况 1:没有使用@Id 注解明确指定主键字段
   -- 之所以会生成上面这样的 WHERE 子句是因为通用 Mapper 将实体类中的所有字段都拿来放在一起作为联合主键
  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 = ?
  • 情况 2:使用@Id 主键明确标记和数据库表中主键字段对应的实体类字段。

    @Id
    private Integer empId;
    

@GeneratedValue 注解

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

自增主键用法:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer empId;

序列主键用法(oracle):

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY,
                generator = "select SEQ_ID.nextval from dual")
private Integer empId;

@Transient 主键

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

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

常用方法

selectOne

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

  • 使用非空的值生成WHERE子句
  • 在条件表达式中使用“=”进行比较

要求必须返回一个实体类结果,如果有多个,则会抛出异常

xxxByPrimaryKey

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

xxxSelective

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

SelectByRowBounds

分页,查询时还是查询全部,在内存中做的分页。真正做分页还是使用pagehelper。

QBC查询

Query By Criteria在 SQL 语句中相当 于查询条件。QBC 查询是将查询条件通过 Java 对象进行模块化封装。

示例代码:

//目标: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 对象
Criteria criteria01 = example.createCriteria(); 
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);
}

逆向工程

原生 MyBatis 逆向工程和通用 Mapper 逆向工程对比

image-20201025150119942

使用 Maven 执行MBG

文档

code Pro02MapperMBG

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>

    <groupId>cn.silince.mapper.mbg</groupId>
    <artifactId>Pro02MapperMBG</artifactId>
    <version>1.0-SNAPSHOT</version>

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

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

        <!-- targetModelPackage:声明MBG生成实体类后存放的package位置 -->
        <targetModelPackage>cn.silince.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>8.0.11</mysql.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>4.0.0-beta3</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.8</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>

                <!-- 配置generatorConfig.xml配置文件的路径 -->
                <configuration>
                    <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>

                <!-- MBG插件的依赖信息 -->
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>${mysql.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>tk.mybatis</groupId>
                        <artifactId>mapper</artifactId>
                        <version>${mapper.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

</project>

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
	<!-- 引入外部属性文件 -->
	<properties resource="config.properties" />

	<context id="Mysql" targetRuntime="MyBatis3Simple"
		defaultModelType="flat">
		<property name="beginningDelimiter" value="`" />
		<property name="endingDelimiter" value="`" />

		<!-- 配置通用Mapper的MBG插件相关信息 -->
		<plugin type="${mapper.plugin}">
			<property name="mappers" value="${mapper.Mapper}" />
		</plugin>

		<!-- 配置连接数据库的基本信息 -->
		<jdbcConnection
			driverClass="${jdbc.driverClass}"
			connectionURL="${jdbc.url}"
			userId="${jdbc.user}"
			password="${jdbc.password}">
		</jdbcConnection>

		<!-- 配置Java实体类存放位置  targetModelPackage是pom文件中的属性-->
		<javaModelGenerator
			targetPackage="${targetModelPackage}"
			targetProject="${targetJavaProject}" />

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

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

		<!-- 根据数据库表生成Java文件的相关规则 -->
		<!-- tableName="%"表示数据库中所有表都参与逆向工程,此时使用默认规则 -->
		<!-- 默认规则:table_dept→TableDept -->
		<!-- 不符合默认规则时需要使用tableName和domainObjectName两个属性明确指定 -->
		<table tableName="tabple_emp" domainObjectName="Employee">
			<!-- 配置主键生成策略 -->
			<generatedKey column="emp_id" sqlStatement="Mysql" identity="true" />
		</table>
	</context>
</generatorConfiguration>

config.properties

# Database connection information
jdbc.driverClass = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/commonMapper
jdbc.user = root
jdbc.password = z*****y

#c3p0
jdbc.maxPoolSize=50
jdbc.minPoolSize=10
jdbc.maxStatements=100
jdbc.testConnection=true

# mapper
mapper.plugin = tk.mybatis.mapper.generator.MapperPlugin
mapper.Mapper = tk.mybatis.mapper.common.Mapper

自定义 Mapper<T>接口

tk.mybatis.mapper.common.Mapper层次结构:

image-20201025161233577

使用步骤

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

1) 创建自定义 Mapper<T>接口。⚠️MyMapper不能和原来的Mapper放在同一个包下。

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

}

2) 继承该接口

public interface EmployeeMapper extends MyMapper<Employee> {}

3) 配置 MapperScannerConfigurer 注册 MyMapper<T>

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

通用 Mapper 接口扩展

Pro03MapperOfMine

需要提供的接口和实现类

image-20201026115724959

MyBatchUpdateMapper

package cn.silince.mapper.mine_mappers;
public interface MyBatchUpdateMapper<T> {

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

MyMapper

package cn.silince.mapper.mine_mappers;
public interface MyMapper<T> 
		extends SelectAllMapper<T>,
		SelectByExampleMapper<T>,
		MyBatchUpdateMapper<T> {
}

MyBatchUpdateProvider

package cn.silince.mapper.mine_mappers;

/**
 * @program: Pro03MapperOfMine
 * @description:
 * @author: Silince
 * @create: 2020-10-25 22:29
 **/
public class MyBatchUpdateProvider extends MapperTemplate {

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

    /*
    <foreach collection="list" item="record" separator=";" >
        UPDATE tabple_emp
        <set>
            emp_name=#{record.empName},
            emp_age=#{record.empAge},
            emp_salary=#{record.empSalary},
        </set>
        where emp_id=#{record.empId}
    </foreach>
 */
    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) {
            // 7 判断主键
            boolean isPrimaryKey = entityColumn.isId();
            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();
    }

}

EmployeeService

package cn.silince.mapper.services;

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

	public List<Employee> getAll() {
		return employeeMapper.selectAll();
	}

	public void batchUpdateEmp(List<Employee> empList){
		employeeMapper.batchUpdate(empList);
	}
}

二级缓存

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

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

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

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

⚠️:实体类必须实现序列化接口

类型处理器:TypeHandler

类型处理器 code

通用 Mapper 默认情况下会忽略复杂类型,对复杂类型不进行“从类到表”的映射。

简单类型和复杂类型

基本数据类型:byte short int long double float char boolean

引用数据类型:类、接口、数组、枚举……

简单类型:只有一个值的类型

复杂类型:有多个值的类型

复杂类型 Address 处理

自定义类型转换器

image-20201026134109084

TypeHandler 接口

public interface TypeHandler<T> {
	//将 parameter 设置到 ps 对象中,位置是 i
  //在这个方法中将 parameter 转换为字符串
	void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  //根据列名从 ResultSet 中获取数据,通常是字符串形式 
  //将字符串还原为 Java 对象,以 T 类型返回
	T getResult(ResultSet rs, String columnName) throws SQLException;
	T getResult(ResultSet rs, int columnIndex) throws SQLException;
	T getResult(CallableStatement cs, int columnIndex) throws SQLException; 
}

继承体系

image-20201026134350905

BaseTypeHandler 类中的抽象方法说明

//将 parameter 对象转换为字符串存入到 ps 对象的 i 位置 
public abstract void setNonNullParameter(
	PreparedStatement ps,
	int i,
	T parameter,
	JdbcType jdbcType) throws SQLException;
//从结果集中获取数据库对应查询结果 
//将字符串还原为原始的 T 类型对象 
public abstract T getNullableResult(ResultSet rs,String columnName) throws SQLException;
public abstract T getNullableResult( ResultSet rs,int columnIndex) throws SQLException;
public abstract T getNullableResult( CallableStatement cs,int columnIndex) throws SQLException;

自定义类型转换器类

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;
	}

}

注册自定义类型转换器

字段级别:@ColumnType 注解

⚠️:在枚举类型这里无法使用@ColumnType注解注册MyBatis内置的枚举类型处理器

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

全局级别:在 MyBatis 配置文件中配置 typeHandlers

@Column
private Address address;

@Column
private SeasonEnum season;
	<typeHandlers>
		<!-- handler属性:指定自定义类型转换器全类名 -->
		<!-- javaType属性:指定需要使用“自定义类型转换器”进行类型处理的实体类型 -->
		<typeHandler 
			handler="cn.silince.mapper.handlers.AddressTypeHandler"
			javaType="cn.silince.mapper.entities.Address"/>
			
		<typeHandler 
			handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
			javaType="cn.silince.mapper.entities.SeasonEnum"/>
			
	</typeHandlers>

枚举类型的解决办法

在枚举类型中,无法使用@ColumnType注解注册MyBatis内置的枚举类型处理器

方法一:让通用 Mapper 把枚举类型作为简单类型处理。

增加一个通用Mapper的配置项,在 Spring 配置文件中找到 MapperScannerConfigurer。

本质:使用了 org.apache.ibatis.type.EnumTypeHandler<E>

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

方法二:为枚举类型配置对应的类型处理器。

image-20201026134109084

类型处理器:

  • 内置
    • org.apache.ibatis.type.EnumTypeHandler<E>
      • 在数据库中存储枚举值本身
    • org.apache.ibatis.type.EnumOrdinalTypeHandler<E>
      • 在数据库中仅仅存储枚举值的索引
  • 自定义
    • 和address的处理方法完全一样

内置枚举类型处理器注册:

  • 不能使用@ColumnType注解

    image-20201026145732477

  • 需要在 MyBatis 配置文件中配置专门的类型处理器并在字段上使用@Column 注解

    • ⚠️ 加@Column 注解的作用是让通用 Mapper 不忽略枚举类型。
	<typeHandlers>
		<!-- handler属性:指定自定义类型转换器全类名 -->
		<!-- javaType属性:指定需要使用“自定义类型转换器”进行类型处理的实体类型 -->
		<typeHandler
			handler="org.apache.ibatis.type.EnumTypeHandler"
			javaType="cn.silince.mapper.entities.SeasonEnum"/>

	</typeHandlers>