持久层—Mybatis Plus(二)

# 一. MyBatis-Plus 常用功能

下面我将详细介绍 MyBatis-Plus 中的一些常用功能。

条件构造器

条件构造器可以帮助我们快速构建 SQL 查询条件,避免手动拼接 SQL 语句。MyBatis-Plus 提供了一个 Wrapper 接口和一些实现类,用于表示查询条件的封装类。

例如,以下代码演示了基本的条件查询:


QueryWrapper<User> queryWrapper = new QueryWrapper<>();

queryWrapper.eq("username", "admin");

List<User> userList = userMapper.selectList(queryWrapper);

在这个例子中,我们创建了一个 QueryWrapper 对象,并调用了其 eq 方法来添加查询条件。最后调用了 Mapper 的 selectList 方法来执行查询并返回结果。

除了 eq 方法,还有很多其他的方法可以用来添加查询条件,例如:

  • ne:不等于

  • gt:大于

  • ge:大于等于

  • lt:小于

  • le:小于等于

  • like:模糊匹配

  • in:包含在指定值列表中

  • notIn:不包含在指定值列表中

  • isNull:为 NULL

  • isNotNull:不为 NULL

  • and:添加 AND 连接符

  • or:添加 OR 连接符

  • 等等

可以根据实际需要选择合适的方法来构造查询条件。

自动填充字段

在数据库中,有些字段的值是需要自动生成或者从其他地方获取的,例如创建时间、更新时间等。MyBatis-Plus 提供了一个 MetaObjectHandler 接口,用于自动填充这些字段的值。

例如,以下代码演示了如何配置自动填充:


@Component

public class MyMetaObjectHandler implements MetaObjectHandler {



    @Override

    public void insertFill(MetaObject metaObject) {

        this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);

    }



    @Override

    public void updateFill(MetaObject metaObject) {

        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);

    }



}

在这个例子中,我们实现了 MetaObjectHandler 接口,并重写了其中的 insertFillupdateFill 方法。这两个方法会在插入和更新操作时自动填充指定的字段,使用了 Java 8 的 LocalDateTime.now 方法来获取当前时间。

为了让 MyBatis-Plus 自动使用我们定义的 MetaObjectHandler 实现类,还需要在配置文件中添加对应的配置项:


mybatis-plus.global-config.meta-object-handler=com.example.MyMetaObjectHandler

## 分页查询

分页查询是 Web 应用中经常使用的功能之一。MyBatis-Plus 提供了一个 Page 类和相应的 Mapper 方法,可以方便地进行分页查询。

例如,以下代码演示了分页查询的基本用法:


IPage<User> userPage = new Page<>(1, 10);

QueryWrapper<User> queryWrapper = new QueryWrapper<>();

queryWrapper.eq("status", 1);

userMapper.selectPage(userPage, queryWrapper);

List<User> userList = userPage.getRecords();

在这个例子中,我们创建了一个 Page 对象,并指定了页码和每页数据数量,然后创建了一个 QueryWrapper 对象并添加了查询条件。最后调用了 Mapper 的 selectPage 方法来执行分页查询。

除了基本的分页查询外,MyBatis-Plus 还提供了一些高级的分页查询功能,例如按照多个字段排序、自定义返回结果等。

二.高级功能

以下是 MyBatis-Plus 常用的高级功能及其实现方式:

一、性能分析插件

MyBatis-Plus 提供了性能分析插件,可以用来分析 SQL 执行性能。步骤如下:

  1. 引入依赖

<dependency>

    <groupId>com.baomidou</groupId>

    <artifactId>mybatis-plus-boot-starter</artifactId>

    <version>${mybatis-plus.version}</version>

</dependency>

  1. 在 application.yml 文件中添加配置

mybatis-plus:

  configuration:

    # 开启驼峰命名转换(如果数据库字段为 user_id,则实体类属性为 userId)

    map-underscore-to-camel-case: true

    # 开启性能分析插件

    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    # SQL执行分析拦截器,用于输出每条 SQL 语句及其执行时间

    sql-explain-type: com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackSqlParser

  global-config:

    # 是否打印 SQL 日志

    sql-show: true

  1. 在 Mapper 接口上添加注解

@Mapper

public interface UserMapper extends BaseMapper<User> {

    

    /**

     * 查询所有用户

     * @return 用户列表

     */

    @Select("select * from user")

    @InterceptorIgnore(tenantLine = "true")

    List<User> selectAll();

}

二、乐观锁插件

MyBatis-Plus 也提供了乐观锁插件,可以用来解决并发更新问题。步骤如下:

  1. 引入依赖和配置

<dependency>

    <groupId>com.baomidou</groupId>

    <artifactId>mybatis-plus-boot-starter</artifactId>

    <version>${mybatis-plus.version}</version>

</dependency>


mybatis-plus:

  configuration:

    # 开启驼峰命名转换(如果数据库字段为 user_id,则实体类属性为 userId)

    map-underscore-to-camel-case: true

  global-config:

    # 是否开启逻辑删除

    db-config:

      logic-delete-value: 1

      logic-not-delete-value: 0

    # 自动填充

    meta-object-handler: com.baomidou.mybatisplus.extension.handlers.MybatisDefaultMetaObjectHandler

    # 注入主键生成器

    id-type: auto

  configuration:

    # 开启乐观锁插件

    plugins:

      - com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor

  1. 在实体类中添加 @Version 注解

@Data

public class User {

    /**

     * 用户ID

     */

    @TableId(type = IdType.AUTO)

    private Long id;



    /**

     * 版本号

     */

    @Version

    private Integer version;



    /**

     * 用户名

     */

    private String username;



    /**

     * 密码

     */

    private String password;



    /**

     * 手机号码

     */

    private String phone;



    /**

     * 邮箱

     */

    private String email;



    /**

     * 创建时间

     */

    @TableField(fill = FieldFill.INSERT)

    private Date createTime;



    /**

     * 更新时间

     */

    @TableField(fill = FieldFill.INSERT_UPDATE)

    private Date updateTime;



    /**

     * 是否删除

     */

    @TableLogic

    private Integer deleted;

}

  1. 在 Mapper 接口中使用 @Update 注解

@Mapper

public interface UserMapper extends BaseMapper<User> {

    

    /**

     * 根据ID更新用户信息

     * @param user 用户对象

     * @return 更新结果

     */

    @Update("<script>" +

            "update user set " +

            "<if test='username != null'>username=#{username}</if>" +

            "<if test='password != null'>, password=#{password}</if>" +

            "<if test='phone != null'>, phone=#{phone}</if>" +

            "<if test='email != null'>, email=#{email}</if>" +

            "where id=#{id} and version=#{version}" +

            "</script>")

    int updateUserById(User user);

}

在这个示例中,我们使用了动态 SQL 语句拼接,通过判断对象中的属性是否为空来决定是否加入 SET 子句中。同时还需要注意,为了实现乐观锁机制,我们在 WHERE 子句中添加了一个版本号的判断条件。

三、多数据源的配置

MyBatis-Plus 支持多数据源配置,可以通过 DynamicDataSource 根据不同的数据源进行动态切换。步骤如下:

  1. 引入依赖和配置

<dependency>

    <groupId>com.baomidou</groupId>

    <artifactId>mybatis-plus-boot-starter</artifactId>

    <version>${mybatis-plus.version}</version>

</dependency>



<!-- druid 数据源 -->

<dependency>

    <groupId>com.alibaba</groupId>

    <artifactId>druid-spring-boot-starter</artifactId>

    <version>${druid.version}</version>

</dependency>



<!-- HikariCP 数据源 -->

<dependency>

    <groupId>com.zaxxer</groupId>

    <artifactId>HikariCP</artifactId>

    <version>${hikari.version}</version>

</dependency>


spring:

  datasource:

    # 主数据源配置

    url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8

    username: root

    password: root

    driver-class-name: com.mysql.cj.jdbc.Driver

  mybatis-plus:

    configuration:

      # 开启驼峰命名转换(如果数据库字段为 user_id,则实体类属性为 userId)

      map-underscore-to-camel-case: true

    global-config:

      # 是否开启逻辑删除

      db-config:

        logic-delete-value: 1

        logic-not-delete-value: 0

      # 自动填充

      meta-object-handler: com.baomidou.mybatisplus.extension.handlers.MybatisDefaultMetaObjectHandler

      # 注入主键生成器

      id-type: auto

    configuration:

      # 开启性能分析插件

      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

      # SQL执行分析拦截器,用于输出每条 SQL 语句及其执行时间

      sql-explain-type: com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackSqlParser

      # 开启乐观锁插件

      plugins:

        - com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor

  1. 创建多个数据源的配置类

@Configuration

public class DataSourceConfig {

    /**

     * 主数据源配置

     */

    @Bean(name = "masterDataSource")

    @Primary

    @ConfigurationProperties(prefix = "spring.datasource")

    public DataSource masterDataSource() {

        return DruidDataSourceBuilder.create().build();

    }



    /**

     * 从数据源1配置

     */

    @Bean(name = "slave1DataSource")

    @ConfigurationProperties(prefix = "spring.datasource.slave1")

    public DataSource slave1DataSource() {

        return DruidDataSourceBuilder.create().build();

    }



    /**

     * 从数据源2配置

     */

    @Bean(name = "slave2DataSource")

    @ConfigurationProperties(prefix = "spring.datasource.slave2")

    public DataSource slave2DataSource() {

        return DruidDataSourceBuilder.create().build();

    }

}

在这个示例中,我们通过注解的方式创建了三个数据源,并分别对应主数据源和两个从数据源。

  1. 创建数据源路由器

@Component

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override

    protected Object determineCurrentLookupKey() {

        return DataSourceContextHolder.getDataSource();

    }

}

在这个示例中,我们通过继承 AbstractRoutingDataSource 类,并实现 determineCurrentLookupKey 方法来实现数据源的路由切换。其中 DataSourceContextHolder 是一个线程安全的上下文类,用于存储当前数据源。

好的,以下是创建数据源切换器的步骤:

  1. 创建数据源切换器
@Component
@Aspect
public class DataSourceAspect {
    /**
     * 定义切入点:所有配置了 @DS 注解的方法
     */
    @Pointcut("@annotation(com.baomidou.dynamic.datasource.annotation.DS)")
    public void dsPointCut() {}

    /**
     * 在执行方法前动态切换数据源
     */
    @Before("dsPointCut()")
    public void before(JoinPoint point) {
        // 获取方法上的 @DS 注解
        DS ds = point.getTarget().getClass().getAnnotation(DS.class);
        if (ds == null) {
            // 如果类上没有 @DS 注解,则获取方法上的 @DS 注解
            MethodSignature signature = (MethodSignature) point.getSignature();
            ds = signature.getMethod().getAnnotation(DS.class);
        }
        // 切换数据源
        if (ds != null) {
            DataSourceContextHolder.setDataSource(ds.value());
        }
    }

    /**
     * 在执行方法后清除数据源
     */
    @After("dsPointCut()")
    public void after(JoinPoint point) {
        DataSourceContextHolder.clearDataSource();
    }
}

在这个示例中,我们通过使用 AOP 技术,在目标方法执行前动态切换数据源。具体实现方式是:在切入点方法上定义一个 @DS 注解,并在 before 方法中根据该注解的值切换数据源。需要注意的是,如果类和方法都有 @DS 注解,方法上的注解优先级更高。

  1. 测试多数据源配置

最后,我们可以通过编写一个测试类来验证多数据源配置是否生效:

@RunWith(SpringRunner.class)
@SpringBootTest
public class DataSourceTest {
    @Autowired
    private UserService userService;

    @Test
    public void test() {
        // 切换到主数据源
        DataSourceContextHolder.setDataSource(DataSourceType.MASTER);
        User user1 = userService.getById(1L);
        System.out.println(user1);

        // 切换到从数据源1
        DataSourceContextHolder.setDataSource(DataSourceType.SLAVE1);
        User user2 = userService.getById(1L);
        System.out.println(user2);

        // 切换到从数据源2
        DataSourceContextHolder.setDataSource(DataSourceType.SLAVE2);
        User user3 = userService.getById(1L);
        System.out.println(user3);
    }
}

在这个示例中,我们通过切换数据源的方式,依次查询了三个不同数据源中的用户信息。如果没有出现异常,则说明多数据源配置已经生效。

四、分页插件

MyBatis-Plus 还提供了分页插件,可以用来实现分页查询。步骤如下:

  1. 引入依赖和配置

<dependency>

    <groupId>com.baomidou</groupId>

    <artifactId>mybatis-plus-boot-starter</artifactId>

    <version>${mybatis-plus.version}</version>

</dependency>


mybatis-plus:

  configuration:

    # 开启驼峰命名转换(如果数据库字段为 user_id,则实体类属性为 userId)

    map-underscore-to-camel-case: true

  global-config:

    # 是否开启逻辑删除

    db-config:

      logic-delete-value: 1

      logic-not-delete-value: 0

    # 自动填充

    meta-object-handler: com.baomidou.mybatisplus.extension.handlers.MybatisDefaultMetaObjectHandler

    # 注入主键生成器

    id-type: auto

  configuration:

    # 开启分页插件

    plugins:

      - com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor

  1. 在 Mapper 接口中使用 @Select 注解,并传入 Page 对象作为参数

@Mapper

public interface UserMapper extends BaseMapper<User> {

    

    /**

     * 分页查询用户列表

     * @param page 分页对象

     * @param username 用户名

     * @param email 邮箱

     * @return 用户列表

     */

    @Select("<script>" +

            "select * from user " +

            "<where>" +

            "<if test='username != null'>and username like concat('%',#{username},'%')</if>" +

            "<if test='email != null'>and email like concat('%',#{email},'%')</if>" +

            "</where>" +

            "order by id asc" +

            "</script>")

    List<User> selectUserList(Page<User> page, @Param("username")String username, @Param("email")String email);

}

  1. 在 Controller 层中调用查询方法,传入 Page 对象并设置分页参数

@RestController

public class UserController {



    @Autowired

    private UserMapper userMapper;



    /**

     * 分页查询用户列表

     * @param pageNum 当前页码

     * @param pageSize 每页条数

     * @param username 用户名

     * @param email 邮箱

     * @return 用户列表

     */

    @GetMapping("/users")

    public ResultVO selectUserList(

            @RequestParam(defaultValue = "1") Integer pageNum,

            @RequestParam(defaultValue = "10") Integer pageSize,

            String username,

            String email) {

        // 设置分页参数

        Page<User> page = new Page<>(pageNum, pageSize);

        // 调用查询方法

        List<User> userList = userMapper.selectUserList(page, username, email);

        // 封装结果

        Map<String, Object> resultMap = new HashMap<>();

        resultMap.put("total", page.getTotal());

        resultMap.put("pageNum", page.getCurrent());

        resultMap.put("pageSize", page.getSize());

        resultMap.put("list", userList);

        return ResultVO.success(resultMap);

    }

}

以上就是 MyBatis-Plus 常用的高级功能,并给出了具体实现的步骤和代码

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值