# common-mapper **Repository Path**: xiongrj/common-mapper ## Basic Information - **Project Name**: common-mapper - **Description**: 尚硅谷通用Mapper - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-08-29 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 通用 Mapper 笔记‌‌‌‌‌ # 1 引入 ## 1.1作用 替我们生成常用增删改查操作的 SQL 语句。 ![image](通用Mapper笔记/Image_001.png) ## 1.2代码官方发布地址 https://gitee.com/free https://gitee.com/free/Mapper/wikis/1.1-java?parent=1.integration ## 1.3前置知识 MyBatis Spring # 2 快速入门 ## 2.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'); * Java 实体类 考虑到基本数据类型在 Java 类中都有默认值,会导致 MyBatis 在执行相关操作 时很难判断当前字段是否为 null,所以在 MyBatis 环境下使用 Java 实体类时尽量不 要使用基本数据类型,都使用对应的包装类型。 ![image](通用Mapper笔记/Image_002.png) public class Employee { private Integer empId; private String empName; private Double empSalary; private Integer empAge; public Employee() { } public Employee(Integer empId, String empName, Double empSalary, Integer empAge) { super(); this.empId = empId; this.empName = empName; this.empSalary = empSalary; this.empAge = empAge; } @Override public String toString() { return "Employee [empId=" + empId + ", empName=" + empName + ", empSalary=" + empSalary + ", empAge=" + empAge + "]"; } public Integer getEmpId() { return empId; } public void setEmpId(Integer empId) { this.empId = empId; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public Double getEmpSalary() { return empSalary;‌‌ } public void setEmpSalary(Double empSalary) { this.empSalary = empSalary; } public Integer getEmpAge() { return empAge; } public void setEmpAge(Integer empAge) { this.empAge = empAge; } } ![image](通用Mapper笔记/Image_003.png) 1. 搭建 MyBatis+Spring 开发环境 2. 集成 Mapper  加入 Maven 依赖信息 tk.mybatis mapper 4.0.0-beta3 * 修改 Spring 配置文件 tk.mybatis.spring.mapper.MapperScannerConfigurer"> ## 2.4第一个操作 /** * 具 体 操 作 数 据 库 的 Mapper 接 口 , 需 要 继 承 通 用 Mapper 提 供 的 核 心 接 口 : Mapper * 泛型类型就是实体类的类型 * @author Lenovo * */ public interface EmployeeMapper extends Mapper {‌‌‌ } ![image](通用Mapper笔记/Image_004.png) # 3 常用注解 1. ## @Table 注解 作用:建立实体类和数据库表之间的对应关系。 默认规则:实体类类名首字母小写作为表名。Employee 类→employee 表。 用法:在@Table 注解的 name 属性中指定目标数据库表的表名 2. ## @Column 注解 作用:建立实体类字段和数据库表字段之间的对应关系。 默认规则: 实体类字段:驼峰式命名 数据库表字段:使用“_”区分各个单词 用法:在@Column 注解的 name 属性中指定目标字段的字段名 3. ## @Id 注解 通用 Mapper 在执行 xxxByPrimaryKey(key)方法时,有两种情况。 情况 1:没有使用@Id 注解明确指定主键字段 ### 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 主键明确标记和数据库表中主键字段对应的实体类字段。 ![image](通用Mapper笔记/Image_005.jpg) 4. ## @GeneratedValue 注解‌‌‌ 作用:让通用 Mapper 在执行 insert 操作之后将数据库自动生成的主键值回写到实 体类对象中。 自增主键用法: ![image](通用Mapper笔记/Image_006.png) 序列主键用法: 应用场景:购物车结账  增加商品销量...  减少商品库存...  生成订单数据→封装到 Order 对象中→保存 Order 对象→数据库自动生成主键 值→回写到实体类对象 Order 中 * 生成一系列订单详情数据→List →在每一个 OrderItem 中设置 Order 对象的主键值作为外键→批量保存 List …… 5. ## @Transient 主键 用于标记不与数据库表字段对应的实体类字段。 @Transient private String otherThings; //非数据库表中字段 # 4 常用方法 1. ## selectOne 方法  通用 Mapper 替我们自动生成的 SQL 语句情况 ![image](通用Mapper笔记/Image_007.jpg)  实体类封装查询条件生成 WHERE 子句的规则  使用非空的值生成 WHERE 子句  在条件表达式中使用“=”进行比较‌‌‌‌  要求必须返回一个实体类结果,如果有多个,则会抛出异常 ![image](通用Mapper笔记/Image_008.jpg)  2. ## xxxByPrimaryKey 方法 需要使用@Id 主键明确标记和数据库表主键字段对应的实体类字段,否则通用 ![image](通用Mapper笔记/Image_009.png) Mapper 会将所有实体类字段作为联合主键。 3. ## xxxSelective 方法 非主键字段如果为 null 值,则不加入到 SQL 语句中。 # 5 QBC 查询 ## 5.1概念 Query By Criteria Criteria 是 Criterion 的复数形式。意思是:规则、标准、准则。在 SQL 语句中相当 于查询条件。 QBC 查询是将查询条件通过 Java 对象进行模块化封装。 ## 5.2示例代码 //目标:WHERE (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 对象 ![image](通用Mapper笔记/Image_010.png) —————————————————————————————‌‌ 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 empList = employeeService.getEmpListByExample(example); for (Employee employee : empList) { System.out.println(employee); } # 6 逆向工程 ## 6.1原生 MyBatis 逆向工程和通用 Mapper 逆向工程对比 ## 6.2参考文档地址 https://github.com/abel533/Mapper/wiki/4.1.mappergenerator —————————————————————————————‌‌‌ # 7 自定义 Mapper接口 ![image](通用Mapper笔记/Image_011.png) ## 7.1用途 让我们可以根据开发的实际需要对 Mapper接口进行定制。 1. 创建自定义 Mapper接口 2. 配置 MapperScannerConfigurer 注册 MyMapper ### mappers=com.atguigu.mapper.mine_mappers.MyMapper ![image](通用Mapper笔记/Image_012.png) —————————————————————————————‌‌ # 8 通用 Mapper 接口扩展 ## 8.1说明 这里的扩展是指增加通用 Mapper 没有提供的功能。 ![image](通用Mapper笔记/Image_013.png) ## 8.2举例 通用 Mapper 官方文档中使用一个批量 insert 作为扩展功能的例子: tk.mybatis.mapper.additional.insert.InsertListMapper tk.mybatis.mapper.additional.insert.InsertListProvider 我们来仿照写一个批量 update。假设我们想生成下面这样的 SQL 语句: UPDATE tabple_emp SET emp_name=?,emp_age=?,emp_salary=? where emp_id=? ; UPDATE tabple_emp SET emp_name=?,emp_age=?,emp_salary=? where emp_id=? ; UPDATE tabple_emp SET emp_name=?,emp_age=?,emp_salary=? where emp_id=? ; …… 为了生成上面那样的 SQL 语句,我们需要使用到 MyBatis 的 foreach 标签。 UPDATE tabple_emp SET emp_name=#{record.empName}, emp_age=#{record.empAge}, emp_salary=#{record.empSalary} where emp_id=#{record.empId} ————————————————————————————— ## 8.3我们需要提供的接口和实现类 ![image](通用Mapper笔记/Image_014.png) ## 8.4参考代码 ![image](通用Mapper笔记/Image_015.png) # 9 二级缓存‌‌‌‌‌‌‌ 1. ## MyBatis 配置文件开启二级缓存功能 2. 在 XxxMapper 接口上使用@CacheNamespace 注解 @CacheNamespace public interface EmployeeMapper extends MyMapper { } ![image](通用Mapper笔记/Image_016.png) # 10 类型处理器:TypeHandler ## 10.1简单类型和复杂类型 | 基本数据类型 | byte short int long double float char boolean | | --- | --- | | 引用数据类型 | 类、接口、数组、枚举…… | | | | 简单类型 | 只有一个值的类型 | | 复杂类型 | 有多个值的类型 | ※通用 Mapper 默认情况下会忽略复杂类型,对复杂类型不进行“从类到表”的映 射。 ## 10.2Address 处理 10.2.1 自定义类型转换器 10.2.2 TypeHandler 接口 public interface TypeHandler { //将 parameter 设置到 ps 对象中,位置是 i ![image](通用Mapper笔记/Image_017.png) —————————————————————————————‌ //在这个方法中将 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; } 10.2.3 继承树 1. BaseTypeHandler 类中的抽象方法说明 //将 parameter 对象转换为字符串存入到 ps 对象的 i 位置 public abstract void setNonNullParameter( PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; ![image](通用Mapper笔记/Image_018.png) —————————————————————————————‌ //从结果集中获取数据库对应查询结果 //将字符串还原为原始的 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; 10.2.5 自定义类型转换器类 public class AddressTypeHandler extends BaseTypeHandler
{ …… 10.2.6 注册自定义类型转换器  方法一 字段级别:@ColumnType 注解 * 方法二 全局级别:在 MyBatis 配置文件中配置 typeHandlers ![image](通用Mapper笔记/Image_019.jpg) ![image](通用Mapper笔记/Image_020.jpg) ## 10.3枚举类型‌‌ ![image](通用Mapper笔记/Image_021.png) 10.3.1 办法一:让通用 Mapper 把枚举类型作为简单类型处理  增加一个通用 Mapper 的配置项 在 Spring 配置文件中找到 MapperScannerConfigurer  本质 使用了 org.apache.ibatis.type.EnumTypeHandler 10.3.2 办法二:为枚举类型配置对应的类型处理器  类型处理器  内置 * org.apache.ibatis.type.EnumTypeHandler  在数据库中存储枚举值本身 * org.apache.ibatis.type.EnumOrdinalTypeHandler  在数据库中仅仅存储枚举值的索引  自定义  内置枚举类型处理器注册 * 不能使用@ColumnType 注解 ![image](通用Mapper笔记/Image_022.jpg)  需要在 MyBatis 配置文件中配置专门的类型处理器并在字段上使用 @Column 注解 ![image](通用Mapper笔记/Image_023.png) ※注意:加@Column 注解的作用是让通用 Mapper 不忽略枚举类型。# title