一、MyBatis Generator
为 MyBastis 框架设计 的代码生成工具,简化持久层编码工作。根据数据库表自动生成 Java 实体类、Mapper 接口、SQL 的 xml 文件。让开发者专注于业务逻辑。
1、引入插件
MyBatis 官网搜索 MyBatis Generator 插件:Running MyBatis Generator With Maven -- MyBatis Generator Corehttps://mybatis.org/generator/running/runningWithMaven.html
XML
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.6</version>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<phase>deploy</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<!--generator配置文件所在位置-->
<configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
<!-- 允许覆盖生成的文件;xml不会覆盖, 采用追加的方式-->
<overwrite>true</overwrite>
<verbose>true</verbose>
<!--将当前pom的依赖项添加到生成器的类路径中-->
<includeCompileDependencies>true</includeCompileDependencies>
</configuration>
<!--该插件的依赖,在 <dependencies> 中引入的它识别不到-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
</plugin>

2、修改 generatorConfig.xml 文件
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>
<!-- 一个数据库一个context -->
<context id="MysqlTables" targetRuntime="MyBatis3Simple">
<!--禁用自动生成的注释-->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接信息-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/book_test?serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true"
userId="root"
password="root">
</jdbcConnection>
<!-- 生成实体类, 配置路径 -->
<javaModelGenerator targetPackage="com.edu.generator.model" targetProject="src/main/java" >
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成mapxml文件 -->
<sqlMapGenerator targetPackage="generatorMapper" targetProject="src/main/resources" >
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- 生成mapxml对应client,也就是接口dao -->
<javaClientGenerator targetPackage="com.edu.generator.mapper" targetProject="src/main/java" type="XMLMAPPER" >
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- table可以有多个,tableName表示要匹配的数据库表 -->
<table tableName="user_info" domainObjectName="UserInfo" enableSelectByExample="true"
enableDeleteByExample="true" enableDeleteByPrimaryKey="true" enableCountByExample="true"
enableUpdateByExample="true">
<!-- 类的属性是否用数据库中的真实字段名做为属性名, 不指定这个属性会自动转换 _ 为驼峰命名规则 -->
<property name="useActualColumnNames" value="false" />
<!-- 数据库表主键 -->
<generatedKey column="id" sqlStatement="Mysql" identity="true" />
</table>
<table tableName="book_info" domainObjectName="BookInfo" enableSelectByExample="true"
enableDeleteByExample="true" enableDeleteByPrimaryKey="true" enableCountByExample="true"
enableUpdateByExample="true">
<!-- 类的属性是否用数据库中的真实字段名做为属性名, 不指定这个属性会自动转换 _ 为驼峰命名规则 -->
<property name="useActualColumnNames" value="false" />
<!-- 数据库表主键 -->
<generatedKey column="id" sqlStatement="Mysql" identity="true" />
</table>
</context>
</generatorConfiguration>
- targetRuntime="MyBatis3Simple":"MyBatis3Simple" 生成的 SQL 的 xml 语句比较简单;"MyBatis3" 比较复杂。
- targetPackage="com.edu.generator.model":生成在哪个包。
- tableName="user_info":数据库对应的表名。
- domainObjectName="BookInfo":对应的实体类名。
- <generatedKey column="id":主键名。
- <property name="useActualColumnNames" value="false" />:属性名自动转换成驼峰命名规则。
只生成实体类的版本:
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>
<!-- 一个数据库一个context -->
<context id="MysqlTables" targetRuntime="MyBatis3Simple">
<!-- 禁用自动生成的注释 -->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- 数据库连接信息 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/mybatis_test?serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true"
userId="root"
password="123456">
</jdbcConnection>
<!-- 生成实体类配置 -->
<javaModelGenerator targetPackage="com.edu.mybatis.plus.model" targetProject="src/main/java" >
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 移除SQL映射文件生成器(不生成Mapper XML) -->
<!-- 移除Java客户端生成器(不生成Mapper接口) -->
<!-- 表配置 -->
<table tableName="user_info" domainObjectName="UserInfo">
<property name="useActualColumnNames" value="false" />
<generatedKey column="id" sqlStatement="Mysql" identity="true" />
</table>
</context>
</generatorConfiguration>
3、生成代码
在 maven 中运行插件,自动生成代码:

生成的文件:

实体类把 getter、setter 都生成了,为了好看,可以调整为 @Data:
Mapper 接口、xml 文件生成了一些基础的数据库操作。(不建议用,mxl 文件代码太乱了,看着很复杂)
该插件的使用,需要配置很多东西,比如数据库连接的信息,但是这些信息已经在 spring boot 的配置文件中配置过了,因此该插件还不够方便。对于 mapper、xml 的编写,Mybatis-plus 框架才是我们学习的重点 。用用 MyBatis Generator 的实体类自动生成即可。
二、MyBatis-plus
MyBatis-plus 在 MyBatis 的基础上扩展功能,跟 MyBatis 不冲突。直接在 Spring Boot 项目的POM 文件中引入依赖即可。
官方文档:
快速开始 | MyBatis-Plushttps://baomidou.com/getting-started/
1、快速上手
创建一个 Spring Boot 项目:

引入依赖:spring boot3 对应的版本
XML
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.12</version>
</dependency>
配置数据库连接信息(.yml)。
在启动类 中加入 @MapperScan ,指定要扫描的 Mapper 文件路径。或者每个 mapper 类加 上 @Mapper,二选其一。

创建要操作的表对应的实体类。
编写 Mapper 接口类:


2、简单 CRUD 单元测试
(1)查
java
@Test
public void testSelectAll() {
System.out.println(("----- 查询所有 ------"));
List<UserInfo> userList = userInfoMapper.selectList(null);
userList.forEach(System.out::println);
}
@Test
void testSelectById(){
System.out.println(("----- 按 主键 查询 ------"));
UserInfo userInfo = userInfoMapper.selectById(2);
System.out.println(userInfo);
}
@Test
void testSelectByIds(){
System.out.println(("----- 按 主键 集合查询 ------"));
List<UserInfo> userInfos = userInfoMapper.selectByIds(List.of(1,2));
userInfos.forEach(System.out::println);
}
(2)增

java
@Test
void testInsert(){
System.out.println(("----- 插入一条数据 ------"));
UserInfo userInfo = new UserInfo();
userInfo.setUserName("Jay");
userInfo.setPassword("Chou");
int insert = userInfoMapper.insert(userInfo);
System.out.println("影响行数:"+ insert);
}
id 生成了随机数:

想自增需要使用 @TableId设置:


id 会从最大值 2 开始自增:

如果想修改最大值:表上右键 >> 设计表 >> 选项 修改

(3)改

java
@Test
void testUpdate(){
System.out.println(("----- 按 主键 更新一条数据 ------"));
UserInfo userInfo = new UserInfo();
userInfo.setId(2);
userInfo.setUserName("lisi");
userInfo.setDeleteFlag(1);
userInfoMapper.updateById(userInfo);
}
(4)删

java
@Test
void testDelete(){
System.out.println(("----- 按 主键 删除一条数据 ------"));
userInfoMapper.deleteById(-2019921918);
}
3、命名映射注解
MyBatis-plus 如何将类名、属性名与数据库表、主键字段、普通字段对应:
- 根据实体类名推断表名。(@TableName)
- 默认 id 属性是主键。(@TableId)
- 驼峰规则的属性名对应的蛇形命名,就是表字段。(@TableField)
- 如果 java 命名不符合自动对应的的规则,可以用注解进行绑定。

4、打印日志
把 mybatis 改成 mybatis-plus 即可:
java
mybatis-plus:
configuration: # 配置打印 MyBatis ⽇志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
5、自动生成代码(了解)
引入依赖:generator + 模板引擎
XML
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.12</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
自动生成代码:
java
public void test() {
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8" +
"&useSSL=false&allowPublicKeyRetrieval=true",
"root", "123456")
.globalConfig(builder -> builder
.outputDir(Paths.get(System.getProperty("user.dir")) + "/src/main/java")
)
.packageConfig(builder -> builder
.parent("com.edu.mybatis.plus.generator")
.entity("entity")
.mapper("mapper")
.service("service")
.xml("mapper.xml")
)
.strategyConfig(builder -> builder
.entityBuilder()
.enableLombok()
)
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
6、复杂 CRUD 操作
(1)什么是条件构造器
条件构造器(Wrapper 类)允许链式构造条件(用 . 的方式直接引用条件构造方法),避免编写复杂 SQL,同时减少 SQL 注入风险。
- AbstractWrapper:抽象类,提供 Wrapper 类共有的方法和属性。
- QueryWrapper:构造查询条件。
- UpdateWrapper:构造更新条件,可以不用构造实体类设置 set。
- LambdaQueryWrapper:基于 Lambda 表达式构造查询条件。
- LambdaUpdateWrapper:基于 Lambda 表达式构造更新条件。
AbstractWrapper 实现了 Compare 接口,包含了各种条件构造器 ,比如大于、等于、模糊查询等,这些操作是四种 Wrapper 共有的:(更多详情参考官方文档)

(Lambda)QueryWrapper 和 (Lambda)UpdateWrapper 的不同之处 就是红框的部分。绿框是构造函数,其余方法都是差不多一样的。
(2)QueryWrapper
增删改查都能用 QueryWrapper 实现。
查询:
sql
SELECT id,user_name,password FROM user_info WHERE delete_flag = 0 AND user_name
LIKE "%min%"
java
@Test
void testQueryWrapper(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id", "user_name", "password")
.eq("delete_flag", 0)
.like("user_name", "min");
List<UserInfo> userList = userInfoMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
更新:需要构造实体类,设置修改值。
sql
UPDATE user_info SET delete_flag=1 WHERE id < 3
java
@Test
void testQueryWrapper2(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
UserInfo userInfo = new UserInfo();
userInfo.setDeleteFlag(1);
queryWrapper.lt("id", 3);
userInfoMapper.update(userInfo, queryWrapper);
}
删:
sql
DELETE FROM user_info WHERE user_name = Jay2
java
@Test
void testQueryWrapper3(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_name", "Jay2");
userInfoMapper.delete(queryWrapper);
}
(3)UpdateWrapper
**更新:**不用构造实体类,直接 set。
sql
UPDATE user_info SET delete_flag=0 WHERE id IN (1,2)
java
@Test
void testUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("delete_flag", 0)
.in("id", List.of(1,2));
userInfoMapper.update(updateWrapper);
}
直接 set sql 语句更新:
sql
UPDATE user_info SET delete_flag=delete_flag+1 WHERE id IN (1,2)
java
@Test
void testUpdateWrapper2(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.setSql("delete_flag = delete_flag + 1")
.in("id", List.of(1,2));
userInfoMapper.update(updateWrapper);
}
(4)LambdaQueryWrapper
字段名容易写错,Lambda 的版本就是用 实体类名::get属性名 来替代字段名字符串。
可以直接 new Lambda 版本 ,或 者new 普通版本再 使用 lambda 方法转为 Lambda 版本。
SQL:
sql
SELECT id,user_name,password FROM user_info WHERE delete_flag = 0 AND user_name
LIKE "%min%"
java
@Test
void testLambdaQueryWrapper(){
// LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda()
.select(UserInfo::getId, UserInfo::getUserName, UserInfo::getPassword)
.eq(UserInfo::getDeleteFlag, 0)
.like(UserInfo::getUserName, "min");
List<UserInfo> userList = userInfoMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
(5)LambdaUpdateWrapper
SQL:
sql
UPDATE user_info SET delete_flag=0 WHERE id IN (1,2)
java
@Test
void testLambdaUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda()
.set(UserInfo::getDeleteFlag, 1)
.in(UserInfo::getId, List.of(1,2));
userInfoMapper.update(updateWrapper);
}
setIncrBy:递增
setDecrBy:递减
示例:
sql
UPDATE user_info SET delete_flag = delete_flag + 1
java
@Test
void testLambdaUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda()
.set(UserInfo::getDeleteFlag, 1)
.in(UserInfo::getId, List.of(1,2));
userInfoMapper.update(updateWrapper);
}
(6)自定义 SQL
MyBatis-plus 框架提供的操作不能满足所有的需求,我们可以利用 Wrapper 构造条件,在 Mapper 自定义 SQL。
- 条件构造器传参:参数名 ew 或者重命名 @Param(Constants.WRAPPER)。

- 构造器使用:${ew.customSqlSegment} 引用。
SQL:
sql
select id,username,password FROM user_info WHERE user_name = "admin"
注解方式:
java
@Select("SELECT id, user_name, password FROM user_info ${ew.customSqlSegment}")
UserInfo selectByCustom(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
XML 方式:
XML
<select id="selectByCustom2" resultType="com.edu.mybatis.plus.model.UserInfo">
SELECT id, user_name, password FROM user_info ${ew.customSqlSegment}
</select>
测试代码:
java
@Test
void testSelectByCustom(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(UserInfo::getUserName, "admin");
userInfoMapper.selectByCustom(queryWrapper);
}