1、前言

上一篇文章《Springboot集成Mybatis-flex(一)》提到Mybatis Flex和Spring Boot的初步集成和基础使用。今天我们再来探索Mybatis Flex其他特性的使用。

2、数据填充

数据填充指的是,当 Entity 数据被插入 或者 更新的时候,会为字段进行一些默认的数据设置。这个非常有用,比如当某个 entity 被插入时候 会设置一些数据插入的时间、数据插入的用户 id,多租户的场景下设置当前租户信息等等。

MyBatis-Flex 提供了两种方式,帮助开发者进行数据填充。

  • 通过 @Table 注解的 onInsert  和 onUpdate配置进行操作。 
  • 通过 @Column  注解的 onInsertValue  和 onUpdateValue配置进行操作。 

2.1、@Table的onInsert填充

@Table应用于实体类的注解,提供了onInsert填充属性,而该属性接收一个InsertListener的监听器。

/**
 * 数据库表信息注解。
 *
 * @author Michael Yang
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Table {

    /**
     * 显式指定表名称。
     */
    String value();

    /**
     * 数据库的 schema(模式)。
     */
    String schema() default "";

    /**
     * 默认为 驼峰属性 转换为 下划线字段。
     */
    boolean camelToUnderline() default true;

    /**
     * 默认使用哪个数据源,若系统找不到该指定的数据源时,默认使用第一个数据源。
     */
    String dataSource() default "";

    /**
     * 监听 entity 的 insert 行为。
     */
    Class<? extends InsertListener>[] onInsert() default {};

    /**
     * 监听 entity 的 update 行为。
     */
    Class<? extends UpdateListener>[] onUpdate() default {};

    /**
     * 监听 entity 的查询数据的 set 行为,用户主动 set 不会触发。
     */
    Class<? extends SetListener>[] onSet() default {};

    /**
     * 在某些场景下,我们需要手动编写 Mapper,可以通过这个注解来关闭 APT 的 Mapper 生成。
     */
    boolean mapperGenerateEnable() default true;

}

2.1.1、使用示例

使用前面的示例代码进行调整。t_user表中有字段extension为扩展字段,我们利用该字段进行填充测试。

1)User实体类添加@Table注解,并指定OnInsert填充监听器。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(value = "t_user", onInsert = UserEntityOnInsertListener.class)
public class User implements Serializable { 
    ...
}

2)创建监听器UserEntityOnInsertListener。

UserEntityOnInsertListener实现InsertListener接口,并实现onInsert方法。

package org.shamee.demo.listener;

import com.mybatisflex.annotation.InsertListener;
import org.shamee.demo.entity.User;

public class UserEntityOnInsertListener implements InsertListener {

    /**
     * 重写该方法,自动填充extension字段
     * @param entity 实体类
     */
    @Override
    public void onInsert(Object entity) {
        User user = (User) entity;
        user.setExtension("我是通过@Table注解的OnInsert监听器填充内容");
    }
}

3)controller层方法。

/**
 * 新增
 * @return
 */
@GetMapping("insert")
public Boolean insert(){
    User user = User.builder().userId("zhangsan").userName("张三").atk(100).battleNum(200).build();
    userService.insert(user);
    return Boolean.TRUE;
}

4)运行后查看数据填充。

04. Springboot集成Mybatis-flex(二)_mybatis

需要注意的是:onInsert 监听中,通过 mybatis 的 xml mapper 插入数据,或者通过 Db + Row 中插入数据,并不会触发 onInsert 行为,只有通过 UserMapper 进行插入数据才会触发。

@Table注解的onUpdate属性与onInsert一致,onUpdate是应用于更新的场景。

2.2、@Column的onInsertValue填充

@Column应用于字段的注解,提供了onInsertValue属性,可以对字段设置默认值。在 insert 中,onInsertValue 配置的内容会直接参与 SQL 拼接,而不是通过 JDBC 的 Statement 参数设置,需要开发者注意 onInsertValue 的内容,否则可能会造成 SQL 错误。

@Table的注解和@Column注解的填充有什么区别?

@Table 注解的 onInsert 主要是在 Java 应用层面进行数据设置。 

@Column 注解的 onInsertValue 则是在数据库层面进行数据设置。

2.2.1、使用示例

1)User实体类extension字段添加@Column注解。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(value = "t_user")
public class User implements Serializable {
    /**
     * 由于这里会直接拼接成为sql的一部分,因此这里字符串必须添加引号,不然sql执行会出错
     */
    @Column(onInsertValue = "'我是通过@Column注解的onInsertValue属性填充内容'")
    private String extension;
}

2)controller层方法。

/**
 * 新增
 * @return
 */
@GetMapping("insert")
public Boolean insert(){
    User user = User.builder().userId("zhangsan").userName("张三").atk(100).battleNum(200).build();
    userService.insert(user);
    return Boolean.TRUE;
}

3)运行后查看数据填充。

04. Springboot集成Mybatis-flex(二)_spring boot_02

3、数据脱敏

数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形, 实现敏感隐私数据的可靠保护。在涉及客户安全数据或者一些商业性敏感数据的情况下,在不违反系统规则条件下,对真实数据进行改造并提供使用, 如身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏。

Mybatis Flex提供了 @ColumnMask() 注解,并内置了以下脱敏规则:

04. Springboot集成Mybatis-flex(二)_数据_03

并支持自定义规则。

3.1、使用示例

t_user表的userName字段进行中文名脱敏,使用内置的中文名脱敏规则。

/**
 * @Table 注解自动映射实体类和表字段
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(value = "t_user")
public class User implements Serializable {
    ...
    
    @Column(value = "userName")
    @ColumnMask(Masks.CHINESE_NAME)
    private String userName;
    
    ...
}

通过接口查询可以看到userName字段已脱敏。

04. Springboot集成Mybatis-flex(二)_spring boot_04

4、多数据源

MyBaits-Flex 内置了功能完善的多数据源支持^1.0.6,不需要借助第三方插件或者依赖,开箱即用, 支持包括 druid、hikaricp、dbcp2、beecp 在内的任何数据源,使用Mybatis-Flex多数据源配置如下:

mybatis-flex:
  datasource:
    ds1:
      url: jdbc:mysql://127.0.0.1:3306/db
      username: root
      password: 123456
    ds2:
      url: jdbc:mysql://127.0.0.1:3306/db2
      username: root
      password: 123456

其中,ds1 和 ds2 是由用户自定义的数据源名称,使用方式如下:

List<Row> rows =  DataSourceKey.use("ds2", () -> Db.selectAll("t_user"));

但是通常我们会直接使用Spring Boot的多数据源配置方式。

5、读写分离

MyBatis-Flex 的读写分离功能是基于多数据源功能来实现的。读写分离的功能,要求当前环境必须是多个数据库(也可理解为多个数据源),其原理是: 让主数据库(master)处理事务性操作,比如:增、删、改(INSERT、DELETE、UPDATE),而从数据库(slave)处理查询(SELECT)操作。

例如,数据源配置:

mybatis-flex:
  datasource:
    master:
      type: druid
      url: jdbc:mysql://127.0.0.1:3306/master-db
      username: root
      password: 123456
    slave1:
      type: com.your.datasource.type2
      url: jdbc:mysql://127.0.0.1:3306/slave1
      username: root
      password: 123456
    slave2:
      type: com.your.datasource.type2
      url: jdbc:mysql://127.0.0.1:3306/slave2
      username: root
      password: 123456
    other:
      type: com.your.datasource.type2
      url: jdbc:mysql://127.0.0.1:3306/other
      username: root
      password: 123456

以上配置中,一共有 4 个数据源,分别为 master、slave1、slave2、other。 我们的需求是:在 增删改 时,走 master 数据源,而在查询时,随机自动使用 slave1、slave2 数据源进行负载均衡。

那么,我们的分片策略代码如下:

public class MyStrategy implements DataSourceShardingStrategy {

    public String doSharding(String currentDataSourceKey
        , Object mapper, Method mapperMethod, Object[] methodArgs){

        // 不管 other 数据源的情况
        if ("other".equals(currentDataSourceKey)){
            return currentDataSourceKey;
        }

        // 如果 mapper 的方法属于 增删改,使用 master 数据源
        if (StringUtil.startWithAny(mapperMethod.getName(),
            "insert", "delete", "update")){
            return "master";
        }

        //其他场景,使用 slave1 或者 slave2 进行负载均衡
        return "slave*";
    }
}

6、更多特性

此外,还有更多的特性如SQL审计,SQL打印,数据源加密,动态表名等特性,官网写的也很详细了,本文中很多也都是摘抄自官网,只是结合一些自己的动手demo,便于自己理解和掌握。更多的特性可见地址:快速开始 - MyBatis-Flex 官方网站