如何一文学懂 SpringBoot 整合通用 Mapper 和逆向工程生成代码(Mybatis)

1、通用 Mapper 介绍

  • 通用Mapper都可以极大的方便开发人员。可以随意的按照自己的需要选择通用方法,还可以很方便的开发自己的通用方法。
  • 极其方便的使用MyBatis单表的增删改查。
  • 支持单表操作,不支持通用的多表联合查询。
  • 原生 Mapper 的难点:
  1. mapper.xml文件里有大量的sql,当数据库表字段变动,配置文件就要修改
  2. 需要自己实现sql分页,select * from table where . . . limit 1,3。自己手写分页,除了传参page、pageSize,还需要返回条目总数count。
  3. 数据库可移植性差:如果项目更换数据库,比如oracle–>mysql,mapper.xml中的sql要重新写,因为Oracle的PLSQL 和mysql 支持的函数是不同的。
  4. 生成的代码量过大。
  5. 批量操作,批量插入,批量更新,需要自写。
  • 这个东西使用后,会不会降低我们的代码执行效率呢?
       其实他的原理就是通过Mybatis的拦截器原理,利用反射机制拼出的 XML 形式的动态 SQL 然后去执行,并且内部对生成的 SQL 实现有缓存机制,所以你说代码时间消耗肯定也会有一些,但是这是很小很小的,再者在现在项目中,对于提供给前端的接口,通常都会利用些组件进行访问加速(毕竟直接从数据中检索不如在内存中来的快些),比如:redis、memcache、elastic search、solr 等,所以执行效率问题是可以避免或忽略的。
  • 如果有些方法不想使用,例如:用户的接口服务不能使用删除方法也不想暴漏出来,该怎么办呢?
      我们通常会定义增、删、改、查四个基础 Mapper 接口,之后可以按需要引入进行使用,其实即使你使用了公共的 CrudMapper(代表增删改查都在一起的类)也没有问题,只要你在 service 层不要放出删除方法也是可以的。

2、快速使用通用 Mapper

2.1、创建表、实体类和 Mapper 接口

表代码:

CREATE TABLE `table_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 类中都有默认值,会导致 MyBatis 在执行相关操作时很难判断当前字段是否为 null,所以如阿里开发手册所言,Java 实体类尽量不要使用基本数据类型,都使用对应的包装类型。

@Data // lombok 插件,自动生成 get、set 等方法
public class Employee {
	private Integer empId;
	private String empName;
	private Double empSalary;
	private Integer empAge;
}

操作数据库的 Mapper 接口代码:

public interface EmployeeMapper {

}

2.2、集成通用 Mapper

在 pom 文件中引入通用 Mapper 的启动器

<dependency>
	<groupId>tk.mybatis</groupId>
	<artifactId>mapper-spring-boot-starter</artifactId>
	<version>2.0.3</version>
</dependency>

2.3、配置扫描包

在 SpringBoot 启动类上面添加扫描包注解。此时用的是通用 Mapper 的扫描注解(其与原生 Mybatis 扫描包注解同名)
原始扫描包注解全类名:

import org.mybatis.spring.mapper.MapperScannerConfigurer

通用 Mapper 扫描包注解全类名:

import tk.mybatis.spring.mapper.MapperScannerConfigurer

原因是:由通用 Mapper 扫描的 dao 层接口,会在进入容器前,生成通用方法。
在这里插入图片描述

2.4、Mapper 接口继承通用 Mapper 的核心接口 Mapper< T >

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

3、常用注解

3.1、@Table

作用: 建立实体类和数据库表之间的对应关系。(指定类对应的表名称)
  默认规则为 实体类类名首字母小写作为表名。Employee 类→employee 表。
用法: 在@Table 注解的 name 属性中指定目标数据库表的表名

实体类代码:

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

3.2、@Column

作用: 建立实体类字段和数据库表字段之间的对应关系。
  默认规则:
    实体类字段:驼峰式命名
    数据库表字段:使用“_”区分各个单词
用法: 在@Column 注解的 name 属性中指定目标字段的字段名

实体类代码:

@Data
@Table(name = "table_emp")
public class Employee {
    @Column(name = "emp_id")
    private Integer empId;

    @Column(name = "emp_name")
    private String empName;

    @Column(name = "emp_salary")
    private BigDecimal empSalary;

    @Column(name = "emp_age")
    private Integer empAge;
}

3.3、@Id

通用 Mapper 在执行 xxxByPrimaryKey(key)方法时,有两种情况:
  情况 1:没有使用@Id 注解明确指定主键字段生成如下通用方法:
在这里插入图片描述
之所以会生成上面这样的 WHERE 子句是因为通用 Mapper 将实体类中的所有字段都拿来放在一起作为联合主键。
  情况 2:使用 @Id 主键明确标记和数据库表中主键字段对应的实体类字段:

   @Id
   @Column(name = "emp_id")
   private Integer empId;

3.4、@GeneratedValue

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

   @Id
   @Column(name = "emp_id")
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Integer empId;

序列主键用法(Oracle):

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

应用场景:

  • 增加商品销量…
  • 减少商品库存…
  • 生成订单数据→封装到 Order 对象中→保存 Order 对象→数据库自动生成主键值→回写到实体类对象 Order 中
  • 生成一系列订单详情数据→List< OrderItem >→在每一个 OrderItem 中设置 Order 对象的主键值作为外键→批量保存 List< OrderItem >

3.5、@Transient

用于标记不与数据库表字段对应的实体类字段,即该属性不参与 SQL 语句。若属性没有加该注解,并且在数据库表中找不到匹配列,则会抛出列找不到异常

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

4、常用方法

4.1、selectOne 方法

   public Employee getOne(Employee employee) {
    
       return employeeMapper.selectOne(employee);
   }
  • 通用 Mapper 替我们自动生成的 SQL 语句情况如下:

在这里插入图片描述

  • 实体类封装查询条件生成 WHERE 子句的规则
  1. 使用非空的值生成 WHERE 子句
  2. 在条件表达式中使用 “=” 进行比较(= 号局限性大,可以使用的是下文的 QBC 查询)
  • 要求必须返回一个实体类结果,如果有多个,则会抛出异常
    在这里插入图片描述

4.2、xxxByPrimaryKey 方法

    public Employee getOne(Employee employee) {
        
        return employeeMapper.selectByPrimaryKey(employee);
    }

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

4.3、xxxSelective 方法

非主键字段如果为 null 值,则不加入到 SQL 语句中。适用于字段很多,但是插入少的情况。如果表字段很多,但是一开始可能只插入某几个字段,用此方法生成的 SQL 语句会很简介,并且便于调试。

5、QBC 查询

5.1、概念

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

5.2、示例代码

//目标 SQL 查询语句: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);
}

6、逆向工程

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

在这里插入图片描述

6.2、参考文档地址

代码生成器

6.3、在 pom 文件中添加参数

在 pom 文件中写入所有参数并不是硬性的要求,可以在要用的时候硬编码写死到代码中。先把参数放在 pom 文件中方便管理

<properties>
    <!-- ${basedir} 引用工程根目录 -->
    <!-- targetJavaProject 标签:声明存放源码的目录(接口、实体类、XxxMapper.xml)-->
    <targetJavaProject>${basedir}/src/main/java</targetJavaProject>
    <!-- targetMapperPackage 标签:声明 MBG 生成 XxxMapper 接口后存放的 package 位置 -->
    <!-- 公司域名倒序(com.gongsi).项目名称.包名-->
    <targetMapperPackage>per.cjh.example.mappers</targetMapperPackage>
    <!-- targetModelPackage 标签:声明 MBG 生成实体类后存放的 package 位置 -->
    <!-- 公司域名倒序(com.gongsi).项目名称.包名-->
    <targetModelPackage>per.cjh.example.entities</targetModelPackage>
    <!-- targetResourcesProject 标签:声明存放资源文件和 XML 配置文件的目录位置-->
    <targetResourcesProject>${basedir}/src/main/resources</targetResourcesProject>
    <!-- targetXMLPackage 标签:在 targetResourcesProject 标签所配置的目录基础上,套上这一级目录,将生成的 xml 文件放入其中-->
    <targetXMLPackage>mappers</targetXMLPackage>
    <!-- 通用 mapper 的版本号 -->
    <mapper.version>4.0.0</mapper.version>
    <!-- mysql 驱动的版本号-->
    <mysql.version>8.0.19</mysql.version>
</properties>

6.4、在 pom 文件中添加插件

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <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>
            <!-- MBG 插件的依赖信息 -->
            <dependencies>
                <!-- 通用 mapper 生成代码时,需要读取数据库。并且引用前面配置的版本号属性 -->
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>${mysql.version}</version>
                </dependency>
                <!-- 通用 mapper 的版本号 -->
                <dependency>
                    <groupId>tk.mybatis</groupId>
                    <artifactId>mapper</artifactId>
                    <version>${mapper.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

6.5、创建 MBG 配置文件 generatorConfig.xml

注意:配置文件的路径要在上一步声明的路径下面。

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

<generatorConfiguration>
    <!-- 引入 config.properties 外部文件(内部配置属性,便于属性的管理,使用此方法之后,需要再下一步创建该 config 配置文件) -->
    <properties resource="config.properties"/>
    <!-- 常规配置 -->
    <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <!-- 配置通用 mapper 的 MBG 插件相关信息 -->
        <!-- 引用 config.properties 配置文件里面的通用 mapper 插件类型 -->
        <plugin type="${mapper.plugin}">
            <property name="mappers" value="${mapper.Mapper}"/>
            <property name="caseSensitive" value="true"/>
        </plugin>
        <!-- 引用数据库连接4大参数 -->
        <jdbcConnection driverClass="${jdbc.driverClass}"
                        connectionURL="${jdbc.url}"
                        userId="${jdbc.user}"
                        password="${jdbc.password}">
        </jdbcConnection>
        <!-- 配置 Java 实体类存放位置,引用的是 pom 文件中的配置参数-->
        <javaModelGenerator targetPackage="${targetModelPackage}"
                            targetProject="${targetJavaProject}"/>
        <!-- 配置 XxxMapper.xml 存放位置,引用的是 pom 文件中的配置参数-->
        <sqlMapGenerator targetPackage="${targetXMLPackage}"
                         targetProject="${targetResourcesProject}"/>

        <!-- 配置 XxxMapper.java 接口的存放位置,引用的是 pom 文件中的配置参数-->
        <javaClientGenerator targetPackage="${targetMapperPackage}"
                             targetProject="${targetJavaProject}"
                             type="XMLMAPPER"/>
        <!-- 根据数据库表生成 Java 文件的相关规则 -->
        <!-- 方法1:tableName='%' 表示数据库中所有表都参与逆向工程,此时使用默认规则 -->
        <!-- 默认规则:table_dept(表名) -> TableDept(实体类名) 通常不这么使用,因为此时实体类名带了无意义的前缀 Table -->
        <!--
            <table tableName="%">
                <generatedKey column="id" sqlStatement="Mysql" identity="true"/>
            </table>
        -->
        <!-- 方法2:tableName 属性指定具体的表名,domainObjectName 属性指定对应生成的实体类名称(常用)需要把每个类都写下来,进行配置-->
        <table tableName="account" domainObjectName="account">
            <!-- 配置主键生成策略,column 为数据库表的主键名 -->
            <generatedKey column="id" sqlStatement="Mysql" identity="true"/>
        </table>
    </context>
</generatorConfiguration>

6.6、运行通用 Mapper 逆向工程

6.6.1、Intellij 环境下

  1. 点击编译器左下角 Terminal,调出控制台
    在这里插入图片描述
  2. 让路径跳转到当前工程,即 pom 文件所在目录。cd 命令 (change dir 改变目录)
    在这里插入图片描述
  3. 运行 mvn mybatis-generator:generate 命令
    在这里插入图片描述

6.6.2、eclipse 环境下

右键 pom 文件,Run As -> Maven build
在弹出窗口的 Goals:文本框内写入右边的命令 mvn mybatis-generator:generate
点击Run

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值