制作网站需要哪些成本,什么网站好建设,公司做的网站费用计入什么科目,数据推广平台有哪些MyBatis-Plus#xff08;MP#xff09;除了封装常见的 CRUD 操作#xff0c;还提供了一些高级功能#xff0c;进一步简化复杂场景下的开发工作。本文将逐一讲解 逻辑删除、自动填充、多表关联查询的原理与使用方式#xff0c;让你快速掌握这些技巧#xff01; 一、逻辑删… MyBatis-PlusMP除了封装常见的 CRUD 操作还提供了一些高级功能进一步简化复杂场景下的开发工作。本文将逐一讲解 逻辑删除、自动填充、多表关联查询的原理与使用方式让你快速掌握这些技巧 一、逻辑删除
逻辑删除是指在数据库中不直接删除记录而是通过标记如 is_deleted 字段表示数据是否有效。
1. 原理与配置
逻辑删除是指在数据库中不直接删除记录而是通过标记如 is_deleted 字段来表示数据是否有效查询时会自动过滤掉已标记为“删除”的记录。
2. 配置步骤 在数据库表中添加逻辑删除字段如 is_deleted ALTER TABLE user ADD COLUMN is_deleted TINYINT(1) DEFAULT 0 COMMENT 逻辑删除标记;在实体类中添加逻辑删除注解 TableLogic
private Integer isDeleted;全局配置逻辑删除行为application.yml mybatis-plus:global-config:db-config:logic-delete-field: is_deletedlogic-delete-value: 1 # 逻辑已删除值logic-not-delete-value: 0 # 逻辑未删除值3. 使用示例
① 插入记录前的数据库表数据
执行以下查询语句
SELECT * FROM user;假设初始数据为空
idnameis_deleted
② 插入新记录
User user new User();
user.setName(Tom);
userMapper.insert(user);执行后生成的 SQL 为
INSERT INTO user (name, is_deleted) VALUES (Tom, 0);③ 数据库表中新增记录
idnameis_deleted1Tom0 ④ 执行逻辑删除操作
userMapper.deleteById(1);生成的 SQL 为
UPDATE user SET is_deleted 1 WHERE id 1;⑤ 数据库表更新后的记录
idnameis_deleted1Tom1 ⑥ 查询数据
默认情况下逻辑删除记录不会出现在查询结果中
ListUser users userMapper.selectList(null);生成的 SQL 为
SELECT id, name FROM user WHERE is_deleted 0;查询结果
idname
若想查询所有记录包括逻辑删除的记录需要自定义 SQL
Select(SELECT * FROM user)
ListUser selectAllUsers();查询结果
idnameis_deleted1Tom1 通过示例可以看出逻辑删除通过 自动更新 is_deleted 字段 和 动态添加查询条件 实现了逻辑上的“删除”操作同时保留了数据的可追溯性。
4. 注意事项
逻辑删除仅在 MP 自动生成的 SQL 中生效自定义 SQL 需手动添加条件。查询时默认不包含已删除记录若需查询已删除数据需使用自定义 SQL。 二、自动填充
自动填充用于在插入或更新记录时自动为某些字段赋值如创建时间、更新时间。
1. 原理与配置
实现自动填充的关键是使用 TableField 的 fill 属性并结合 MetaObjectHandler 接口完成填充逻辑。
自动填充的核心原理在于 MyBatis-Plus 提供的元对象处理器MetaObjectHandler接口。通过实现这个接口MP 能够在插入或更新数据时自动填充指定字段。这背后实际上是一种 拦截机制在执行插入或更新操作时MP 会检测是否有配置的填充字段如果有就调用实现类的逻辑为这些字段赋值。
以下我们详细来分析一下
自动填充的触发时机 MP 在执行插入INSERT或更新UPDATE操作时会检查实体类中是否有标注了 TableField(fill ...) 的字段。如果存在这些字段则会触发自动填充逻辑。元对象处理器的作用 MP 使用 MetaObjectHandler 接口实现了这个逻辑通过重写其中的 insertFill 和 updateFill 方法可以定义插入或更新时如何自动填充字段。拦截机制 MP 会在内部生成的 SQL 语句执行前通过拦截器将指定字段的值动态插入到 SQL 语句中。这一过程对开发者透明减少了重复编写代码的成本。 配置生效 MP 的核心配置会自动扫描所有实现了 MetaObjectHandler 的类并在执行插入或更新操作时调用相关方法。无需手动绑定这也是为什么只需要实现类即可实现自动填充的原因。
2. 配置步骤 在实体类中通过 TableField(fill ...) 指定需要填充的字段 TableField(fill FieldFill.INSERT)
private LocalDateTime createTime;TableField(fill FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;FieldFill.INSERT仅在插入时填充。 FieldFill.INSERT_UPDATE在插入和更新时都会填充。 实现 MetaObjectHandler 接口。只需创建一个类并实现 MetaObjectHandler就会自动扫描并加载这个类的配置无需额外声明。记得通过Component注解标注为组件SpringBoot 才能够扫描到 Component
public class MyMetaObjectHandler implements MetaObjectHandler {Overridepublic void insertFill(MetaObject metaObject) {this.strictInsertFill(metaObject, createTime, LocalDateTime::now, LocalDateTime.class);this.strictInsertFill(metaObject, updateTime, LocalDateTime::now, LocalDateTime.class);}Overridepublic void updateFill(MetaObject metaObject) {this.strictUpdateFill(metaObject, updateTime, LocalDateTime::now, LocalDateTime.class);}
}strictInsertFill 和 strictUpdateFill 是 MP 提供的方法用于安全地为指定字段赋值。 MP 会自动调用 insertFill 和 updateFill而开发者无需显式调用。
3. 使用示例
① 插入数据
插入或更新时无需手动设置 createTime 和 updateTime
User user new User();
user.setName(Tom);
userMapper.insert(user);执行后自动填充的 SQL 为
INSERT INTO user (name, create_time, update_time)
VALUES (Tom, 2025-01-01 12:00:00, 2025-01-01 12:00:00);② 更新数据
User user userMapper.selectById(1);
user.setName(Jerry);
userMapper.updateById(user);执行后自动填充的 SQL 为
UPDATE user
SET name Jerry, update_time 2025-01-01 12:05:00
WHERE id 1;三、多表关联查询
虽然 MyBatis-Plus 不直接支持多表联查但我们可以通过以下方式实现
1. 数据库表设计
假设我们有以下两张表
用户表user
字段名类型描述idINT主键nameVARCHAR(50)用户名emailVARCHAR(50)邮箱
订单表order
字段名类型描述idINT主键user_idINT用户 IDorder_timeDATETIME下单时间amountDECIMAL(10, 2)订单金额
2. 实体类定义
用户实体类User
Data
public class User {private Integer id;private String name;private String email;// 关联的订单集合private ListOrder orders;
}订单实体类Order
Data
public class Order {private Integer id;private Integer userId;private LocalDateTime orderTime;private BigDecimal amount;
}3. XML 配置
自定义 SQL 和返回结果映射
通过 MyBatis 的 XML 配置实现多表联查
UserMapper.xml
mapper namespacecom.example.mapper.UserMapper!-- 多表联查查询用户及其订单 --select idgetUserWithOrders resultMapuserWithOrdersMapSELECT u.id AS userId,u.name AS userName,u.email AS userEmail,o.id AS orderId,o.order_time AS orderTime,o.amount AS orderAmountFROM user uLEFT JOIN order o ON u.id o.user_idWHERE u.id #{userId}/select!-- 结果映射 --resultMap iduserWithOrdersMap typecom.example.entity.Userid propertyid columnuserId /result propertyname columnuserName /result propertyemail columnuserEmail /collection propertyorders ofTypecom.example.entity.Orderid propertyid columnorderId /result propertyorderTime columnorderTime /result propertyamount columnorderAmount //collection/resultMap/mapper4. Mapper 接口
public interface UserMapper extends BaseMapperUser {User getUserWithOrders(Param(userId) Integer userId);
}5. 测试联查
Service 层调用
Autowired
private UserMapper userMapper;public User getUserWithOrders(Integer userId) {return userMapper.getUserWithOrders(userId);
}测试用例
Test
public void testGetUserWithOrders() {User user userMapper.getUserWithOrders(1);System.out.println(用户信息 user.getName());System.out.println(订单信息);user.getOrders().forEach(order - {System.out.println(订单 ID order.getId());System.out.println(订单金额 order.getAmount());});
}6. 查询结果
假设 user 表中有以下记录
idnameemail1张三zhangsanmail.com
order 表中有以下记录
iduser_idorder_timeamount112025-01-01 12:00:00100.00212025-01-01 15:00:00200.00
运行测试后输出
用户信息Alice
订单信息
订单 ID1
订单金额100.00
订单 ID2
订单金额200.00