欢迎关注个人主页:逸狼
创造不易,可以点点赞吗
如有错误,欢迎指出~
MyBatisGenerator
MyBatisGenerator是⼀个为MyBatis框架设计的代码⽣成⼯具,它可以根据数据库表结构⾃动⽣成相应 的JavaModel,Mapper接⼝以及SQL映射⽂件,简化数据访问层的编码⼯作,使得开发者可以更专注于 业务逻辑的实现. 接下来我们看下,如何使⽤MyBatisGenerator来⽣成代码.
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>
<!-- 一个数据库一个context -->
<context id="MysqlTables" targetRuntime="MyBatis3" defaultModelType="flat">
<!--去除注释-->
<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/java_blog_spring?serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true"
userId="root"
password="111111">
</jdbcConnection>
<!-- 生成实体类 -->
<javaModelGenerator targetPackage="com.example.demo.model" targetProject="src/main/java" >
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成mapxml文件 -->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources" >
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- 生成mapxml对应client,也就是接口dao -->
<javaClientGenerator targetPackage="com.example.demo.mapper" targetProject="src/main/java" type="XMLMAPPER" >
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- table可以有多个,每个数据库中的表都可以写一个table,tableName表示要匹配的数据库表,也可以在tableName属性中通过使用%通配符来匹配所有数据库表,只有匹配的表才会自动生成文件 -->
<table tableName="user_info">
<property name="useActualColumnNames" value="false" />
<!-- 数据库表主键 -->
<generatedKey column="id" sqlStatement="Mysql" identity="true" />
</table>
</context>
</generatorConfiguration>
在pom文件添加插件
<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>
<!-- 允许覆盖生成的文件, mapxml不会覆盖, 采用追加的方式-->
<overwrite>true</overwrite>
<verbose>true</verbose>
<!--将当前pom的依赖项添加到生成器的类路径中-->
<includeCompileDependencies>true</includeCompileDependencies>
</configuration>
<dependencies>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
</plugin>
mybatis-plus
MyBatis-Plus(简称MP)是⼀个MyBatis的增强⼯具,在MyBatis的基础上只做增强不做改变,为简化开 发.提⾼效率⽽⽣
特性:
- 润物⽆声:只做增强不做改变,引⼊它不会对现有⼯程产⽣影响,如丝般顺滑.
- 效率⾄上:只需简单配置,即可快速进⾏单表CRUD操作,从⽽节省⼤量时间.
- 丰富功能:代码⽣成、⾃动分⻚、逻辑删除、⾃动填充、拦截器等功能⼀应俱全.
- ⼴泛认可:连续5年获得开源中国年度最佳开源项⽬殊荣,Github累计16KStar.
⽀持数据库:
PostgreSQL,MySQL,MariaDB,Oracle,SQLServer,OceanBase,H2,DB2... (任何能使⽤MyBatis进⾏增删改查,并且⽀持标准SQL的数据库应该都在MyBatis-Plus的⽀持范围 内)
准备工作
配置yml
# 数据库连接配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: 111111
driver-class-name: com.mysql.cj.jdbc.Driver
添加依赖,对于springboot3添加下面依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.10.1</version>
</dependency>
数据准备
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据
USE mybatis_test;
-- 创建表[⽤⼾表]
DROP TABLE IF EXISTS user_info;
10CREATE TABLE `user_info` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`username` VARCHAR ( 127 ) NOT NULL,
`password` VARCHAR ( 127 ) NOT NULL,
`age` TINYINT ( 4 ) NOT NULL,
`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',
`phone` VARCHAR ( 15 ) DEFAULT NULL,
`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
-- 添加⽤⼾信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
后端代码
UserInfo
package com.example.demo.model;
import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
private Integer id;
private String username;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}
UserInfoMapper
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
BaseMapper提供了众多crud的方法
MyBatis-Plus复杂操作
3.1 常⻅注解
在上⾯的程序中,MyBatis是如何知道,我们要操作的是哪张表,表⾥有哪些字段呢? 我们来看下咱们Mapper的代码
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
UserInfoMapper在继承 BaseMapper 时,指定了⼀个泛型,这个UserInfo就是与数据库表相对应的实 体类. MyBatis-Plus会根据这个实体类来推断表的信息.
默认情况下:
- 1. 表名:实体类的驼峰表⽰法转换成蛇形表⽰法(下划线分割),作为表名.⽐如UserInfo->user_info
- 2. 字段:根据实体类的属性名转换为蛇形表⽰法作为字段名.⽐如deleteFlag->delete_flag3. 主键:默认为id
- 3.主键:默认为id
如果实体类和数据库不是按照上述规则定义
MyBatis-Plus也给我们提供了⼀下注解,让我们标 识表的信息.
@TableName
修改实体类名UserInfo为Userinfo
从⽇志可以看到,默认查找的表名为userinfo. 我们可以通过 @TableName 来标识实体类对应的表
@Data
@TableName("user_info")//绑定表名
public class UserInfo {
private Integer id;
....}
@TableField
修改属性名deleteFlag为deleteflag,重新执⾏测试⽅法testSelectById
从⽇志可以看到,根据属性名转换后的字段名为:deleteflag. 我们可以通过 @TableField 来标识对应的字段名
@Data
@TableName("user_info")//绑定表名
public class UserInfo {
...
private String phone;
@TableField("delete_flag")//标识表名
private Integer deleteflag;
private Date createTime;
private Date updateTime;
}
@TableId
修改属性名id为userId,重新执⾏测试⽅法testSelectById 运⾏结果报错,程序默认主键为id,这个时候需要可以使用@TableId指定主键
@Data
@TableName("user_info")//绑定表名
public class UserInfo {
@TableId(value = "id" )
private Integer userId;
private String username;
如果属性名和字段名不⼀致,需要在 @TableId 指明对应的字段名
属性名和字段⼀致的情况下,直接加 @TableId 注解就可以.
@Test
void testInsert(){
UserInfo userInfo = new UserInfo();
userInfo.setUsername("111");
userInfoMapper.insert(userInfo);
}
执⾏测试⽅法testInsert 运⾏结果:
要通过@TableId指定id自增方式
@Data
@TableName("user_info")//绑定表名
public class UserInfo {
@TableId(type = IdType.AUTO)
private Integer id;
...}
重新执行结果正常
打印⽇志
为了⽅便学习,我们可以借助⽇志,查看Mybatis-Plus执⾏的SQL语句,参数和执⾏结果 Mybatis-Plus配置⽇志如下:
mybatis-plus:
configuration: # 配置打印 MyBatis⽇志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
条件构造器
⼊⻔程序⾥的使⽤,都是简单的CRUD,在实际的应⽤场景中,我们还需要使⽤更复杂的操作,MyBatisPlus 也给我们提供了相应的⽀持. MyBatis-Plus提供了⼀套强⼤的条件构造器(Wrapper),⽤于构建复杂的数据库查询条件.
Wrapper类 允许开发者以链式调⽤的⽅式构造查询条件,⽆需编写繁琐的SQL语句,从⽽提⾼开发效率并减少SQL 注⼊的⻛险.
以下是主要的Wrapper类及其功能:
- AbstractWrapper:这是⼀个抽象基类,提供了所有Wrapper类共有的⽅法和属性.详细参考官⽹ 介绍:条件构造器
- QueryWrapper:⽤于构造查询条件,在AbstractWrapper的基础上拓展了⼀个select⽅法,允许指 定查询字段.
- UpdateWrapper:⽤于构造更新条件,可以在更新数据时指定条件.
- LambdaQueryWrapper:基于Lambda表达式的查询条件构造器,它通过Lambda表达式来引⽤ 实体类的属性,从⽽避免了硬编码字段名.
- LambdaUpdateWrapper:基于Lambda表达式的更新条件构造器,它允许你使⽤Lambda表达 式来指定更新字段和条件,同样避免了硬编码字段名的问题. 接下来通过代码来看下如何使⽤.
查询
QueryWrapper
实现下面sql查询
SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"
测试
@Test
void testQueryWrapper(){
//SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id", "username", "password", "age")
.eq("age", 18)
.like("username", "min");
userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
}
- lt :"lessthan"的缩写,表⽰⼩于.
- le :"lessthanorequalto"的缩写,表⽰⼩于等于
- ge :"greaterthanorequalto"的缩写,表⽰⼤于等于.
- gt :"greaterthan"的缩写,表⽰⼤于.
- eq :"equals"的缩写,表⽰等于.
- ne :"notequals"的缩写,表⽰不等于.
更新
执行下面sql
UPDATE user_info SET delete_flag=? WHERE age < 20
测试
@Test
//UPDATE user_info SET delete_flag=? WHERE age < 20
void testUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("delete_flag", 2)
.lt("age", 20);
userInfoMapper.update(updateWrapper);
}
UpdateWrapper
UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
测试
@Test
//UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
void testUpdateWrapper2(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("delete_flag", 0).set("age",20)
.in("id", List.of(1,2,3));
userInfoMapper.update(updateWrapper);
}
基于SQL更新
UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)
测试
@Test
//UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)
void testUpdateWrapper3(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.setSql("age = age + 10")
.in("id", List.of(1,2,3));
userInfoMapper.update(updateWrapper);
}
LambdaQueryWrapper
QueryWrapper和UpdateWrapper存在⼀个问题,就是需要写死字段名,如果字段名发⽣变更,可能会 因为测试不到位酿成事故.MyBatis-Plus给我们提供了⼀种基于Lambda表达式的条件构造器,它通过Lambda表达式来引⽤实体 类的属性,从⽽避免了硬编码字段名,也提⾼了代码的可读性和可维护性.
LambdaQueryWrapper和 LambdaUpdateWrapper 分别对应上述的QueryWrapper和UpdateWrapper 接下来我们看下具体使⽤.
@Test
//SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"
void testLambdaQueryWrapper(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda()
.select(UserInfo::getId, UserInfo::getUsername, UserInfo::getPassword)
.eq(UserInfo::getAge, 18)
.like(UserInfo::getUsername, "min");
userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
}
@Test
void testLambdaUpdateWrapper() {
//UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
// updateWrapper.set("delete_flag", 2).set("age",20)
// .in("id", List.of(1,2,3));
updateWrapper.lambda()
.set(UserInfo::getDeleteFlag, 2)
.set(UserInfo::getAge, 20)
.in(UserInfo::getId, List.of(1, 2, 3));
userInfoMapper.update(updateWrapper);
}
⾃定义SQL
在实际的开发中,MyBatis-Plus提供的操作不能满⾜我们的实际需求,MyBatis-Plus也提供了⾃定义 SQL的功能,我们可以利⽤Wrapper构造查询条件,再结合Mapper编写SQL
为了使⽤这⼀功能,mybatis-plus 版本不低于3.0.7
select id,username,password,age FROM user_info WHERE username = "admin"
//select id,username,password,age FROM user_info WHERE username = "admin"
@Select("select id,username,password,age FROM user_info ${ew.customSqlSegment}")
List<UserInfo> selectCustom(@Param(Constants.WRAPPER) Wrapper wrapper);
注意事项:
- 参数命名:在⾃定义SQL时,传递Wrapper对象作为参数时,参数名必须为ew ,或者使⽤注解 @Param(Constants.WRAPPER) 明确指定参数为Wrapper对象
- 使⽤${ew.customSqlSegment} :在SQL语句中,使⽤${ew.customSqlSegment} 来 引⽤Wrapper对象⽣成的SQL⽚段
- 不⽀持基于entity的where语句:⾃定义SQL时,Wrapper对象不会基于实体类⾃动⽣成 where⼦句,你需要⼿动编写完整的SQL语句.
测试
@Test
void selectCustom() {
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", "admin");
userInfoMapper.selectCustom(queryWrapper).forEach(System.out::println);
}
使用xml方式
配置yml
mybatis-plus:
mapper-locations: "classpath*:/mapper/**.xml" # Mapper.xml
mapper
List<UserInfo> selectByCustom2(@Param(Constants.WRAPPER) Wrapper wrapper);
编写UserInfoMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserInfoMapper">
<select id="selectByCustom2" resultType="com.example.demo.model.UserInfo">
select id,username,password,age FROM user_info ${ew.customSqlSegment}
</select>
</mapper>
//UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
@Update("UPDATE user_info SET age = age + #{age}} ${ew.customSqlSegment}")
List<UserInfo> update(@Param("age") Integer age, @Param(Constants.WRAPPER) Wrapper wrapper);
测试
@Test
void update() {
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
updateWrapper.in("id", List.of(1,2,3))
.in("id", List.of(1,2,3));
userInfoMapper.update(10,updateWrapper);
}
总结
1. MyBatis-Plus是MyBatis的增强⼯具,在MyBatis的基础上只做增强不做改变,可以⽤更少的代码 实现数据库表的CRUD,让我们的开发变得更加简单.
2. MyBatis-Plus⽀持⾃定义SQL,版本不低于3.0.7,传递Wrapper对象作为参数时,参数名必须为ew, 在SQL语句中,使⽤${ew.customSqlSegment}来引⽤Wrapper对象⽣成的SQL⽚段