【家政平台开发(12)】家政平台数据库设计:从MySQL到MyBatis-Plus实战

发布于:2025-04-04 ⋅ 阅读:(40) ⋅ 点赞:(0)

本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析,剖析家政行业现状、挖掘用户需求与梳理功能要点,到系统设计阶段的架构选型、数据库构建,再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化,测试阶段多维度保障平台质量,部署发布阶段确保平稳上线。还深入探讨运营策略、技术创新应用及未来发展方向,为家政平台开发提供全面且实用的知识体系与实践指南。


一、数据库概念设计

1.1 实体关系模型(ER 图)构建

在家政平台的数据库设计中,核心实体包括用户、家政服务人员、订单、服务类型等。用户是使用平台寻求家政服务的个体,拥有诸如姓名、联系方式、地址等属性;家政服务人员则是提供服务的一方,具备姓名、技能、工作经验等信息。订单作为连接用户与家政服务人员的纽带,记录了服务的详情、时间、价格等关键数据。服务类型则对各种家政服务进行分类,如保洁、月嫂、维修等。

在 ER 图中,用户与订单呈现一对多的关系,即一个用户可以有多个订单;家政服务人员与订单同样是关联关系,一个家政服务人员可以承接多个订单,一个订单也会对应一个家政服务人员 。服务类型与订单是多对多的关系,一个订单可能包含多种服务类型,一种服务类型也可以被多个订单选用。通过这样的 ER 图构建,能够清晰地展示各实体之间的逻辑联系,为后续数据库表结构的设计奠定坚实基础,确保数据的完整性和一致性,使系统能够高效地存储和管理家政服务相关信息。

1.2 数据库表结构设计原则

  1. 数据独立性原则:数据的逻辑结构与物理结构应相互独立。在家政平台中,无论数据库的存储方式如何变化,如从本地磁盘存储转换为云存储,用户、订单等数据的逻辑结构不应受到影响,应用程序无需修改代码即可继续正常访问数据,这极大地提高了系统的可维护性和可扩展性。
  2. 完整性原则:通过设置主键约束、外键约束、唯一性约束和非空约束等,确保数据的准确性。例如,订单表中的订单 ID 设置为主键,保证每个订单都有唯一标识;用户表与订单表通过用户 ID 建立外键约束,确保订单所属用户的合法性;家政服务人员表中的姓名字段设置为非空约束,防止出现无姓名记录。
  3. 一致性原则:任何时刻数据库中的数据都应保持一致。当用户修改个人信息时,所有相关联的订单记录中的用户信息也应同步更新,避免出现数据不一致的情况,确保数据的准确性和可靠性。
  4. 简单性原则:数据库结构和操作应尽量简单易懂。设计数据库表时,避免过度复杂的表结构和关系,使开发人员能够快速理解和维护,提高开发效率和系统的易用性。
  5. 最小耦合原则:各表之间的依赖关系应尽量减少。用户表和家政服务人员表之间保持相对独立,仅通过订单表进行关联,当用户表结构发生变化时,对家政服务人员表的影响最小,提高了系统的灵活性和稳定性。
  6. 数据冗余原则:适度的数据冗余可以提高查询效率,但要避免过度冗余导致数据不一致。在订单表中重复存储用户的部分基本信息,如姓名和联系方式,在查询订单时可以减少关联查询,提高查询速度,但需确保在用户信息更新时,相关冗余数据也能及时同步更新。
  7. 安全性原则:采取多种安全措施保护数据。对用户的敏感信息,如密码进行加密存储;设置用户权限,不同角色(如普通用户、管理员)拥有不同的操作权限,防止非法访问和数据泄露,保障平台数据的安全。
  8. 有效性原则:数据库中的数据必须真实、准确、及时且相关。家政服务人员的技能信息应真实有效,服务时间和价格等数据应准确无误,确保数据能够满足业务需求,为平台的运营和决策提供可靠依据。
  9. 易用性原则:数据库的设计应方便用户操作。提供简单直观的查询和更新接口,使用户能够轻松地进行数据的查询、修改、删除和插入操作,提高用户体验和工作效率。
  10. 扩展性原则:数据库设计应具备良好的扩展性,以适应未来业务的变化和发展。随着家政平台业务的拓展,可能会增加新的服务类型、用户角色或功能模块,数据库结构应能够方便地进行扩展,如添加新表或字段,而无需进行大规模的重构。

1.3 基于需求的表结构初步规划

  1. 用户表:用于存储用户信息,字段包括用户 ID(主键,自增长整数)、用户名(字符串)、密码(加密字符串)、姓名(字符串)、手机号(字符串,设置唯一性约束)、邮箱(字符串)、地址(字符串)。用户 ID 作为唯一标识,方便在其他表中关联用户信息;用户名和密码用于用户登录;手机号和邮箱用于联系用户;地址用于服务配送。
  2. 家政服务人员表:记录家政服务人员信息,字段有服务人员 ID(主键,自增长整数)、姓名(字符串)、性别(枚举类型,男 / 女)、年龄(整数)、身份证号(字符串,设置唯一性约束)、技能(字符串,如保洁、月嫂、维修等,可存储多个技能,用逗号分隔)、工作经验(字符串,描述工作经历)、联系方式(字符串)。服务人员 ID 唯一标识服务人员,身份证号用于身份验证,技能字段方便用户筛选合适的服务人员。
  3. 服务类型表:存储服务类型信息,字段包含服务类型 ID(主键,自增长整数)、服务类型名称(字符串,如保洁服务、月嫂服务、家电维修等)。服务类型 ID 关联订单表,用于标识订单中包含的服务类型。
  4. 订单表:记录订单相关信息,字段有订单 ID(主键,自增长整数)、用户 ID(外键,关联用户表的用户 ID)、服务人员 ID(外键,关联家政服务人员表的服务人员 ID)、服务类型 ID(外键,关联服务类型表的服务类型 ID)、订单时间(日期时间类型)、服务时间(日期时间类型)、服务地址(字符串)、订单金额(浮点数)、订单状态(枚举类型,如待支付、已支付、待服务、服务中、已完成、已取消)。订单 ID 唯一标识订单,通过外键关联其他表,构建起用户、服务人员、服务类型与订单之间的关系。
  5. 评价表:用于用户对家政服务进行评价,字段包括评价 ID(主键,自增长整数)、用户 ID(外键,关联用户表的用户 ID)、服务人员 ID(外键,关联家政服务人员表的服务人员 ID)、订单 ID(外键,关联订单表的订单 ID)、评价内容(字符串)、评分(整数,1 - 5 分)、评价时间(日期时间类型)。评价 ID 唯一标识评价记录,通过外键关联其他表,方便查询和统计用户对家政服务的评价情况 。

二、数据库物理设计

2.1 MySQL 数据库表创建与优化

在 MySQL 中,创建家政平台数据库表时,可使用CREATE TABLE语句。例如创建用户表,代码如下:

CREATE TABLE user (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(100) NOT NULL,
    name VARCHAR(50),
    phone VARCHAR(20) UNIQUE,
    email VARCHAR(50),
    address VARCHAR(200)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在字段类型选择上,对于用户 ID 这类唯一标识且递增的字段,使用INT AUTO_INCREMENT类型,AUTO_INCREMENT属性使其自动生成唯一的递增数值 ,节省手动赋值的麻烦且保证数据的唯一性。VARCHAR类型用于存储可变长度字符串,如用户名、密码等,根据实际需求设置合适的长度,像用户名设置为VARCHAR(50),既能满足大多数用户的命名习惯,又不会浪费过多存储空间;密码字段考虑到安全性和加密后的长度,设置为VARCHAR(100) 。对于手机号这种固定格式且需要唯一性约束的字段,使用VARCHAR(20)并添加UNIQUE约束,确保每个手机号只对应一个用户。

为提高性能,表结构优化至关重要。尽量避免使用 NULL 值,因为 NULL 值会增加数据库的存储空间和查询复杂度。例如,在用户表中,如果某些字段如用户名、密码是必填项,就将其设置为NOT NULL。合理设置字段长度,避免过长或过短。过长会浪费存储空间,影响查询和写入速度;过短则可能无法存储完整数据。如地址字段设置为VARCHAR(200),一般能满足家庭住址等信息的存储需求。同时,选择合适的存储引擎,MySQL 常用的存储引擎有 InnoDB 和 MyISAM,对于家政平台这种注重事务处理、数据一致性和并发性能的应用,优先选择 InnoDB 引擎,它支持行级锁,能有效减少并发操作时的锁冲突,提高系统的并发处理能力。

2.2 索引设计与优化策略

索引在数据库中就如同书籍的目录,能极大提高数据的查询效率。其原理是通过对表中的一列或多列数据进行排序,创建一个指向这些数据的指针列表,数据库在查询时可以直接通过索引快速定位到所需数据,而无需全表扫描。

MySQL 中常见的索引类型有:

  • B-Tree 索引:是最常用的索引类型,适用于 InnoDB 和 MyISAM 存储引擎 。它是一种多路平衡查找树,数据存储在叶子节点,内部节点只保存索引信息。B-Tree 索引的平衡性使得查询操作的时间复杂度为 O (log n),并且支持范围查询和排序操作。例如,在家政服务人员表中,对年龄字段创建 B-Tree 索引,当执行SELECT * FROM domestic_service_staff WHERE age BETWEEN 25 AND 35;这样的范围查询时,B-Tree 索引能快速定位到符合年龄范围的数据。
  • 哈希索引:基于哈希表实现,通过将关键字转换为哈希值来快速定位数据存储位置 。在理想情况下,哈希索引的查找时间复杂度为 O (1),速度极快,适用于等值查询。但它不支持范围查询和排序操作,且存在哈希冲突问题。例如,在家政平台中,如果需要根据订单 ID 快速查询订单信息,由于订单 ID 是唯一标识,使用哈希索引能迅速定位到对应的订单记录。
  • 全文索引:主要用于加速文本搜索,适用于处理大文本字段,如家政服务人员的工作经验描述、用户评价内容等 。它通过创建倒排索引,将每个单词映射到包含该单词的文档或记录,实现高效的文本搜索,并支持布尔运算和相关性排名。例如,当用户搜索包含特定关键词的家政服务人员时,全文索引能快速找到相关人员记录。

根据查询需求选择合适的索引类型至关重要。对于经常进行等值查询的字段,如订单 ID、用户 ID 等,可选择哈希索引或 B-Tree 索引;对于范围查询、排序操作较多的字段,如订单金额、服务时间等,B-Tree 索引更为合适;对于需要进行文本搜索的字段,如服务人员的技能描述、用户评价等,则应使用全文索引。

设计复合索引和覆盖索引也能有效优化查询性能。复合索引是在多个字段上创建的索引,在使用时遵循最左前缀原则,即只有查询条件中使用了复合索引的左边字段时,索引才会被使用。例如,在家政订单表中,创建一个包含用户 ID、服务类型 ID 和订单状态的复合索引CREATE INDEX idx_order ON order (user_id, service_type_id, order_status);,当执行SELECT * FROM order WHERE user_id = 1 AND service_type_id = 2;查询时,该复合索引就能发挥作用。覆盖索引是指查询所需要的数据都能从索引中获取,无需回表查询。例如,查询订单的订单 ID 和订单金额,而这两个字段都包含在某个索引中,此时使用覆盖索引能避免访问表数据,提高查询效率。

然而,要避免过度索引,因为过多的索引会占用大量磁盘空间,增加数据插入、更新和删除操作的时间开销,同时也会降低数据库的写入性能。所以,在创建索引时,要综合考虑查询需求和系统性能,确保索引的有效性和合理性。

2.3 数据库表的维护与管理

定期对数据库表进行维护是保障家政平台数据库高效稳定运行的关键。更新统计信息是一项重要的维护操作,MySQL 依赖统计信息来制定查询执行计划。例如,随着家政服务订单数据的不断增加和变化,订单表的统计信息可能会过时,这会导致 MySQL 在执行查询时选择不合理的执行计划,影响查询性能。使用ANALYZE TABLE语句可以更新表的统计信息,让 MySQL 能更准确地评估查询成本,从而做出更优的查询优化决策。例如,对订单表执行ANALYZE TABLE order;,该语句会收集表中数据的分布情况、索引的统计信息等,为后续查询提供更可靠的依据。

监控和分析表的性能是及时发现和解决性能问题的重要手段。EXPLAIN语句是一个强大的工具,它可以帮助我们查看查询执行计划,了解 MySQL 如何执行查询语句。通过分析EXPLAIN的输出结果,我们可以识别查询中的性能瓶颈。例如,执行EXPLAIN SELECT * FROM domestic_service_staff WHERE skill LIKE ‘%保洁%’;,输出结果中的type字段表示连接类型,ALL表示全表扫描,这通常意味着查询性能较低;key字段显示使用的索引,如果为NULL,则表示没有使用索引。根据这些信息,我们可以针对性地进行优化,如对skill字段创建合适的索引,或者优化查询语句,避免全表扫描,从而提高查询性能,确保家政平台在处理大量数据时依然能保持高效稳定运行。

三、MyBatis-Plus 在数据库持久层的应用

3.1 MyBatis-Plus 配置与使用

在 Spring Boot 项目中集成 MyBatis-Plus,首先需在pom.xml文件中添加相关依赖,引入 MyBatis-Plus 启动器和 MySQL 驱动依赖:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>最新版本号</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

在application.yml文件中配置数据源相关信息,如数据库连接 URL、用户名和密码等:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_database_name?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: your_username
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

创建 MyBatis-Plus 配置类,通过@MapperScan注解扫描 Mapper 接口所在包路径,同时配置分页插件等,示例如下:

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.example.yourpackage.mapper")
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

使用 MyBatis-Plus 进行基本的 CRUD 操作时,以用户表为例,定义实体类User,使用@TableName注解指定表名,@TableId注解指定主键字段:

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("user")
public class User {

    @TableId
    private Long id;
    private String username;
    private String password;
    private String phone;
    private String email;
}

定义 Mapper 接口UserMapper,继承BaseMapper,其中T为实体类类型,如:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.yourpackage.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

在 Service 层中使用UserMapper进行 CRUD 操作,例如插入用户数据:

import com.example.yourpackage.entity.User;
import com.example.yourpackage.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public boolean saveUser(User user) {
        return userMapper.insert(user) > 0;
    }
}

查询用户数据:

import com.example.yourpackage.entity.User;
import com.example.yourpackage.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }

    public List<User> getAllUsers() {
        return userMapper.selectList(null);
    }
}

更新用户数据:

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.yourpackage.entity.User;
import com.example.yourpackage.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public boolean updateUser(User user) {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", user.getId());
        return userMapper.update(user, updateWrapper) > 0;
    }
}

删除用户数据:

import com.example.yourpackage.entity.User;
import com.example.yourpackage.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public boolean deleteUserById(Long id) {
        return userMapper.deleteById(id) > 0;
    }
}

3.2 基于 MyBatis-Plus 的代码生成器应用

MyBatis-Plus 提供了强大的代码生成器,能快速生成项目所需的基础代码,显著提高开发效率。使用代码生成器前,需在pom.xml文件中添加mybatis-plus-generator和模板引擎(如 Freemarker)依赖:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>最新版本号</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>最新版本号</version>
</dependency>

创建代码生成器配置类,以生成用户相关代码为例,配置如下:

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.Collections;

public class CodeGenerator {

    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/your_database_name?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
        String username = "your_username";
        String password = "your_password";

        FastAutoGenerator.create(url, username, password)
               .globalConfig(builder -> {
                    builder.author("Your Name") // 设置作者
                           .enableSwagger() // 开启swagger模式
                           .fileOverride() // 覆盖已生成文件
                           .outputDir(System.getProperty("user.dir") + "/src/main/java"); // 指定输出目录
                })
               .packageConfig(builder -> {
                    builder.parent("com.example") // 设置父包名
                           .moduleName("user") // 设置模块名
                           .pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/mapper")); // 设置mapperXml生成路径
                })
               .strategyConfig(builder -> {
                    builder.addInclude("user") // 设置需要生成的表名
                           .addTablePrefix("t_"); // 设置过滤表前缀
                })
               .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板
               .execute();
    }
}

上述配置中,globalConfig用于设置全局参数,包括作者、是否开启 Swagger、是否覆盖文件以及输出目录等;packageConfig定义了生成代码的包结构,包括父包名、模块名以及 mapperXml 文件的生成路径;strategyConfig指定了需要生成代码的表名以及表前缀过滤规则。执行main方法后,代码生成器将根据配置自动生成以下代码:

  • 实体类:在com.example.user.entity包下生成User实体类,包含表字段对应的属性,如id、username、password等,并使用@TableName和@TableId等注解进行标注,示例如下:
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("user")
public class User {

    @TableId
    private Long id;
    private String username;
    private String password;
    private String phone;
    private String email;
}
  • Mapper 接口:在com.example.user.mapper包下生成UserMapper接口,继承自BaseMapper,具备基本的 CRUD 操作方法,示例如下:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.user.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}
  • Service 接口和实现类:在com.example.user.service包下生成UserService接口,继承自IService,以及在com.example.user.service.impl包下生成UserServiceImpl实现类,继承自ServiceImpl<UserMapper, User>,并实现UserService接口中的方法,示例如下:
// UserService接口
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.user.entity.User;

public interface UserService extends IService<User> {
}

// UserServiceImpl实现类
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.user.entity.User;
import com.example.user.mapper.UserMapper;
import com.example.user.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
  • Controller 类:在com.example.user.controller包下生成UserController类,用于处理前端请求,示例如下:
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.user.entity.User;
import com.example.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getById(id);
    }

    @GetMapping("/list")
    public List<User> getUserList() {
        return userService.list();
    }

    @GetMapping("/page")
    public Page<User> getUserPage(int current, int size) {
        Page<User> page = new Page<>(current, size);
        return userService.page(page);
    }
}

通过代码生成器,开发人员只需关注业务逻辑的实现,减少了重复代码的编写,提高了开发效率,使项目的开发更加高效和规范。

3.3 MyBatis-Plus 高级特性应用

3.3.1 条件构造器的使用

MyBatis-Plus 的条件构造器为编写复杂查询条件提供了便捷方式,其中 Lambda 表达式的使用让代码更加简洁和类型安全。以家政服务人员表为例,若要查询年龄在 25 到 35 岁之间,且技能包含 “保洁” 的服务人员,代码如下:

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.yourpackage.entity.DomesticServiceStaff;
import com.example.yourpackage.mapper.DomesticServiceStaffMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DomesticServiceStaffService {

    @Autowired
    private DomesticServiceStaffMapper domesticServiceStaffMapper;

    public List<DomesticServiceStaff> getStaffByCondition() {
        LambdaQueryWrapper<DomesticServiceStaff> wrapper = new LambdaQueryWrapper<>();
        wrapper.between(DomesticServiceStaff::getAge, 25, 35)
              .like(DomesticServiceStaff::getSkill, "保洁");
        return domesticServiceStaffMapper.selectList(wrapper);
    }
}

上述代码中,LambdaQueryWrapper通过 Lambda 表达式指定实体类的属性,避免了硬编码字段名,提高了代码的可读性和维护性。between方法用于构建范围查询条件,like方法用于构建模糊查询条件。

3.3.2 分页插件的使用

MyBatis-Plus 的分页插件使分页功能的实现变得轻松。在配置类中添加分页插件(如前文MyBatisPlusConfig类中所示)后,即可在业务代码中使用分页功能。以查询家政订单列表为例,实现分页查询代码如下:

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.yourpackage.entity.Order;
import com.example.yourpackage.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    public Page<Order> getOrderPage(int current, int size) {
        Page<Order> page = new Page<>(current, size);
        return orderMapper.selectPage(page, null);
    }
}

在上述代码中,创建Page对象并传入当前页码current和每页显示条数size,然后调用selectPage方法进行分页查询,selectPage方法的第二个参数为查询条件构造器,这里查询所有订单,故传入null。查询结果Page对象包含了分页相关信息,如当前页数据、总页数、总记录数等。

3.3.3 乐观锁插件的使用

在高并发场景下,乐观锁插件能有效解决数据一致性问题。例如,在家政服务人员薪资调整场景中,多个线程可能同时尝试更新服务人员的薪资。首先在数据库表中添加version字段,用于记录数据版本。在实体类中添加对应的version属性,并使用@Version注解标注,示例如下:

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

@Data
@TableName("domestic_service_staff")
public class DomesticServiceStaff {

    @TableId
    private Long id;
    private String name;
    private Double salary;
    @Version
    private Integer version;
}

在配置类中添加乐观锁插件(如前文MyBatisPlusConfig类中所示)。当更新服务人员薪资时,代码如下:

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.yourpackage.entity.DomesticServiceStaff;
import com.example.yourpackage.mapper.DomesticServiceStaffMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DomesticServiceStaffService {

    @Autowired
    private DomesticServiceStaffMapper domesticServiceStaffMapper;

    public boolean updateSalary(Long id, Double newSalary) {
        DomesticServiceStaff staff = domesticServiceStaffMapper.selectById(id);
        if (staff != null) {
            staff.setSalary(newSalary);
            UpdateWrapper<DomesticServiceStaff> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", id)
                         .eq("version", staff.getVersion());
            boolean result = domesticServiceStaffMapper.update(staff, updateWrapper) > 0;
            if (result) {
                // 更新成功,版本号自增
                staff.setVersion(staff.getVersion() + 1);
                domesticServiceStaffMapper.updateById(staff);
            }
            return result;
        }
        return false;
    }
}

上述代码中,首先查询出要更新的服务人员信息,然后在更新时通过UpdateWrapper构建条件,确保version字段与当前数据库中的版本一致。如果更新成功,将版本号自增并再次更新到数据库中。这样,当多个线程同时尝试更新时,只有一个线程能成功更新,其他线程由于version不一致而更新失败,从而保证了数据的一致性。


网站公告

今日签到

点亮在社区的每一天
去签到