MyBatis Plus 快速开始
MybatisPlus
依赖
springboot2:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.14</version>
</dependency>springboot3:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.14</version>
</dependency>springboot4:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
<version>3.5.14</version>
</dependency>配置
Application.java添加MapperScan:
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}编码
User实体类
@Data
@TableName("`user`")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}重点,Mapper接口继承BaseMapper
public interface UserMapper extends BaseMapper<User> {
}简单使用
@SpringBootTest
public class SampleTest {
@Autowired
private UserMapper userMapper;
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
Assert.isTrue(5 == userList.size(), "");
userList.forEach(System.out::println);
}
}控制台输出:
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
可以看出来,使用非常简单,不用谢XML
核心功能具体使用
引入依赖->继承/实现接口->Wrapper->调用.
yml常用配置
mybatis-plus:
# 实体类别名包路径
type-aliases-package: com.itheima.mp.domain.po
# Mapper.xml文件地址,默认值
mapper-locations: "classpath*:/mapper/**/*.xml"
# MyBatis配置
configuration:
# 是否开启下划线和驼峰的映射
map-underscore-to-camel-case: true
# 是否开启二级缓存
cache-enabled: false
# 全局配置
global-config:
# 数据库配置
db-config:
# id为雪花算法生成
id-type: assign_id
# 更新策略:只更新非空字段
update-strategy: not_nullWrapper条件构造器(重点)
类继承关系图:
Wrapper (接口)
↑
|
AbstractWrapper (抽象类)
↑
______________|______________
| | |
| | |
AbstractLambdaWrapper UpdateWrapper QueryWrapper
↑
_______|____________________
| |
| |
LambdaUpdateWrapper LambdaQueryWrapper功能详解
MyBatis-Plus 的 Wrapper 类是构建复杂查询和更新条件的关键工具。它允许开发者以链式调用的方式构造 SQL 的 WHERE 子句,提供了极大的灵活性和便利性。
强大的where构造能力,复杂场景sql利用Wrapper构造where条件,然后自定义部分sql。
推荐使用lambadaWrapper。
常用方法
QueryWrapper:
selectList
selectOne
like
ge >=
le <=
eq =
ne !=
in
UpdateWrapper:
set
eq
lambdaWrapper:
功能和上面类似,但是可以避免写错字段名的问题。利用了反射
比如:
new LambdaQueryWrapper<User>()
.eq(User::getName, "jack") // 避免写错字段名
User user = new User();
user.setBalance(1000.0);
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.eq("name", "jack"); // 查询 name = 'jack'
usermapper.update(user,wrapper);
new UpdateWrapper<User>()
.eq("name", "jack") //
.set("balance", user.getBalance()); // 设置新的余额
usermapper.update(null,wrapper);
new UpdateWrapper<User>()
.setsql("balance = balance + 500") // 余额加500
.in("id", Arrays.asList(1, 2, 3)); // id 在 1, 2, 3 之中
usermapper.update(null,wrapper);自定义sql
利用Wrapper构造复杂的Where条件,然后自定义剩下的sql。
//这样写把SQL写入了查询硬编码
new UpdateWrapper<User>()
.in("id",ids) //
.setsql("balance = balance + 500"); // 设置新的余额//复杂业务场景,自定义sql+Wrapper构造的where
int amount = 500;
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().in(User::getId,ids);
userMapper.updateBalanceByIds(wrapper, amount);
// 在mapper方法中用@Param("ew")接收Wrapper和自定义参数,
//@Param("ew")也可以写为@Param(Constant.WRAPPER) ,效果一样
void updateBalanceByIds(@Param("ew") Wrapper<User> wrapper, @Param("amount") int amount);
// mapper.xml:
<update id="updateBalanceByIds">
UPDATE user
SET balance = balance + #{amount}
<where>
${ew.customSqlSegment} <!-- 使用 Wrapper 构造的 WHERE 条件 -->
</where>
</update>持久层接口
Mapper Interface
继承BaseMapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 继承 BaseMapper,获得基础 CRUD 方法
// 可以添加自定义方法
}注意
- 泛型是操作的对象。
- 记得加@Mapper注解。
- @MapperScan要扫描到Mapper所在的包
方法
暂略,增删改查都有
Service Interface
Service 层(服务层):继承 IService<T> 和 ServiceImpl<M, T>,提供增强的业务方法。
Service接口
Service接口继承IService<实体类>
public interface UserService extends IService<User> {
// 继承 IService,获得增强的 CRUD 方法
// 可以添加自定义业务方法
// 示例:自定义业务方法
boolean registerUser(User user);
}ServiceImpl实现类
具体的实现类也需要继承ServiceImpl<实体类mapper,实体类>
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 继承 ServiceImpl,自动注入 baseMapper
// baseMapper 就是 UserMapper 实例
@Override
public boolean registerUser(User user) {
// 可以直接使用 baseMapper
return baseMapper.insert(user) > 0;
// 也可以使用 IService 提供的方法
// return this.save(user);
}
}方法
增删改查:
- save: 增,插入数据
- removeById: 删,根据ID删除
- updateById: 改,根据ID更新
- getById: 查,根据ID查询
- list: 查询所有数据
batch方法批处理性能数据量大时好
page方法分页查询分页插件
以上方法可以在controller中用service.方法调用,需要传参数比如getOne(user1);
还有更简单的(重点):
Iservice的LambadaQuery方法,和LambadaUpdate方法,主要用来查询和更新,能够直接在serviceimpl中调用,不需要Wrapper,最后跟list,update等执行语句可以直接执行。相当于把wrapper和以上方法合二为一(十分推荐!)。
new LambadaQuery<User>()
.eq(User::getName,"jack")
.list(); //直接执行查询,返回listI. IService 的 saveBatch 批处理方法
IService 接口提供的 saveBatch(Collection<T> entityList) 方法是 MyBatis-Plus 推荐的批量插入方式,它的速度远超传统的 for 循环逐条插入。
🚀 为什么 saveBatch 比 for 循环快?
| 操作类型 | 逐条 for 循环 save() | saveBatch() 方法 |
|---|---|---|
| 网络开销 | 高: 每条数据一次网络请求和数据库通信。 | 低: 将多条数据打包,减少网络往返次数。 |
| 底层实现 | 每次执行独立的 INSERT 语句。 | 利用 JDBC 的 PreparedStatement.addBatch() 和 executeBatch() 机制。 |
| 性能提升 | 每次操作独立,效率低下。 | 通过聚合 I/O,实现伪批量操作。 |
网络请求少,预编译后统一发送,极大提升了插入效率。
但是不是真正的批处理,因为底层还是多条insert语句发送给数据库。
需要优化为一条insert多值语句,见下节。
II. 真正的批处理:配置 JDBC 驱动参数
虽然 saveBatch 已经很快,但要达到最优性能(即“真正的批处理”),还需要配置底层的 JDBC 驱动,使其将多条 SQL 重写为一条包含多值(Multi-Value)的大语句。
例如:
INSERT INTO user (name, age, email) VALUES
('Alice', 30),
('Bob', 25),
('Charlie', 28);为了在 MySQL 中实现真正的批量插入(一条 SQL 语句插入多行数据),必须在 JDBC 连接 URL 中添加以下参数:rewriteBatchedStatements=true
# 数据库连接 URL 示例
spring.datasource.url=jdbc:mysql://localhost:3306/db?serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&useServerPrepStmts=true&rewriteBatchedStatements=true即可实现真正的批处理插入,大幅提升性能。
常用entity注解
参考常用实体表注解
分页插件(夯)
扩展功能
代码生成器(好用)
MybatisPlus插件,女漫头像的。
静态工具
Db 工具类是最实用的静态工具,可以在任何地方无需注入即可操作数据库,非常适合工具类、实体方法等场景。
跟Iservice类似,但是是静态方法调用。
逻辑删除(好用)
因为存在逻辑删除不是真正的删除,所以每次查询更新都需要加逻辑删除的条件,为了避免在Wrapper多次写,直接采用了配置方式:
mybatis-plus:
global-config:
db-config:
# 逻辑删除字段名
logic-delete-field: deleted
# 删除后的值
logic-delete-value: 1
# 未删除的值
logic-not-delete-value: 0这样就不需要管删除条件了,自动加上。
实体类的字段上最好也加一下注解
// 实体类只需标注字段
@TableLogic
private Integer deleted;逻辑删除也有问题,会导致表数据越来越多,影响性能,可以采用数据迁移,想要逻辑删除把数据迁移到其他表中。
枚举处理器
没啥用,感觉甚至麻烦了。
Json处理器
// 问题:数据库存JSON字符串,如何自动映射到对象?
// user表 info字段:{"age": 18, "address": "北京"}2. 使用方式
实体类配置
@Data
@TableName(autoResultMap = true) // ⚠️ 必须加,否则不生效
public class User {
private Long id;
private String name;
@TableField(typeHandler = JacksonTypeHandler.class) // JSON处理器
private UserInfo info; // 对象类型
}
// 对应的对象
@Data
public class UserInfo {
private Integer age;
private String address;
}自动映射效果
// 插入:对象 → JSON字符串
UserInfo info = new UserInfo();
info.setAge(18);
info.setAddress("北京");
User user = new User();
user.setInfo(info);
userMapper.insert(user);
// 数据库存储:info = '{"age":18,"address":"北京"}'
// 查询:JSON字符串 → 对象
User user = userMapper.selectById(1);
user.getInfo().getAge(); // 直接用,返回 18支持的类型
// List
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> tags; // ["Java", "Python"]
// Map
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> extra; // {"key": "value"}
// 复杂对象
@TableField(typeHandler = JacksonTypeHandler.class)
private List<UserInfo> friends; // [{"age":18}, {"age":20}]5. 条件查询(有限制)
// ❌ 不支持直接查询JSON字段内部
wrapper.eq(User::getInfo, xxx); // 只能比较整个JSON
// ✅ 需要用数据库的JSON函数
@Select("SELECT * FROM user WHERE JSON_EXTRACT(info, '$.age') = #{age}")
List<User> selectByAge(Integer age);全局配置(可选)
mybatis-plus:
configuration:
# 自动扫描TypeHandler
type-handlers-package: com.example.handler核心总结
| 步骤 | 操作 |
|---|---|
| 1️⃣ 实体类加注解 | @TableName(autoResultMap = true) |
| 2️⃣ 字段加处理器 | @TableField(typeHandler = JacksonTypeHandler.class) |
| 3️⃣ 字段类型 | 用对象/List/Map,不用String |
| 4️⃣ 自动转换 | 增删改查自动JSON↔对象 |
适用场景
✅ 适合:
- 存储非结构化扩展信息
- 配置信息、元数据
- 不需要查询JSON内部字段
❌ 不适合:
- 需要频繁查询JSON内部
- 数据需要做索引
- 关系型数据(应该拆表)
完整示例
@Data
@TableName(autoResultMap = true) // 关键!
public class Article {
private Long id;
private String title;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> tags; // ["技术", "Java"]
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> meta; // {"views": 100}
}
// 使用
Article article = new Article();
article.setTags(Arrays.asList("技术", "Java"));
articleMapper.insert(article); // 自动转JSON存储一句话: 加 @TableName(autoResultMap = true) + @TableField(typeHandler = JacksonTypeHandler.class),实现对象↔JSON自动转换!
