04. Springboot集成Mybatis-flex(二)

news2024/11/24 19:05:50

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)运行后查看数据填充。

需要注意的是: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)运行后查看数据填充。

3、数据脱敏

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

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

并支持自定义规则。

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字段已脱敏。

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 官方网站

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1053988.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ghostscript 字体处理深究: 解决字体缺失问题

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Hello World!1分钟配置好你的Go环境

目录 一、简介为什么选择Golang&#xff1f;Golang与其他语言的对比核心特性应用场景社区和生态系统性能标准企业级应用 二、环境要求操作系统WindowsLinux/UnixmacOS 硬件需求其他依赖软件异常情况和处理方法 三、下载和安装GolangWindows系统使用官方安装包使用Chocolatey&am…

使用CreateProcess崩溃:处未处理的异常: 0xC0000005: 写入位置 0x00415652 时发生访问冲突

问题代码 if (!CreateProcess(NULL,L"pela.exe",NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)){return 0;}如果CreateProcess的第二个参数字符串是常量或者是储存在堆中的就会被写保护&#xff0c;崩溃。如果字符串定义到栈或者全局变量就不存在此问题了。 正确的…

初级篇—第二章SELECT查询语句

文章目录 什么是SQLSQL 分类SQL语言的规则与规范阿里巴巴MySQL命名规范数据导入指令 显示表结构 DESC基本的SELECT语句SELECTSELECT ... FROM列的别名 AS去除重复行 DISTINCT空值参与运算着重号查询常数过滤数据 WHERE练习 运算符算术运算符加减符号乘除符号取模符号 符号比较运…

SNERT预备队招新CTF体验赛-Misc(SWCTF)

目录 1、最简单的隐写 2、旋转我 3、is_here 4、zip伪加密 5、压缩包密码爆破 6、我就藏在照片里 7、所以我放弃了bk 8、套娃 9、来自银河的信号 10、Track_Me 11、勇师傅的奇思妙想 1、最简单的隐写 下载附件后&#xff0c;图片格式并不支持打开 根据题目提示&…

Window 安装多个版本的 java 并按需切换

1、按需下载对应版本的 java 官网链接&#xff1a;Java Downloads | Oracle 2、执行安装程序&#xff0c;根据安装向导一步一步走就行&#xff0c;每个版本安装在不同的目录下。 3、配置环境变量 a&#xff09;为每个版本 java 新建不同名称的 JAVA_HOME 系统变量&#xff0…

最优化:建模、算法与理论(最优性理论

第五章 最优性理论 在实际中最优化问题的形式多种多样&#xff0c;给定一类具体的优化问题&#xff0c;我们首先需要分析其解的存在性。如果优化问题的解存在&#xff0c;再考虑如何设计算法求出最优解&#xff0c;一般的非凸优化问题可能存在很多局部极小解&#xff0c;但其往…

使用WPS自动化转换办公文档: 将Word, PowerPoint和Excel文件转换为PDF

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

IDEA-2023-jdk8 HelloWorld的实现

目录 1 新建Project - Class 2 编写代码 3 运行 1 新建Project - Class 选择"New Project"&#xff1a; 指名工程名、使用的JDK版本等信息。如下所示&#xff1a; 接着创建Java类&#xff1a; 2 编写代码 public class HelloWorld {public static void main(S…

桂院校园导航 | 云上高校导航 云开发项目 二次开发教程 1.2

Gitee代码仓库&#xff1a;桂院校园导航小程序 GitHub代码仓库&#xff1a;GLU-Campus-Guide 演示视频 【2023广西赛区 | 三等奖】中国大学生计算机设计大赛 云上高校导航 先 假装 大伙都成功安装了云开发项目&#xff0c;并能在 微信开发者工具 和 手机 上正确运行。 接着就…

【生物信息学】使用HSIC LASSO方法进行特征选择

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 3. IDE 三、实验内容 0. 导入必要的工具 1. 读取数据 2. 划分训练集和测试集 3. 进行HSIC LASSO特征选择 4. 特征提取 5. 使用随机森林进行分类&#xff08;使用所有特征&#xff09; 6. 使用随机森…

【面试经典150 | 矩阵】有效的数独

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;一次遍历数组 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结…

电脑通过串口助手和51单片机串口通讯

今天有时间把电脑和51单片机之间的串口通讯搞定了&#xff0c;电脑发送的串口数据&#xff0c;单片机能够正常接收并显示到oled屏幕上&#xff0c;特此记录一下&#xff0c;防止后面自己忘记了怎么搞得了。 先来两个图片看看结果吧&#xff01; 下面是串口3.c的文件全部内容&a…

python爬取百度图片

1.查询数据 打开网页。 https://cn.bing.com/images/search?q%E7%99%BE%E5%BA%A6%E5%9B%BE%E7%89%87&formHDRSC2&first1&cw1585&ch924 我们右键查看网页源代码,发现能找到我们需要的img衔接,但是这是一个动态网页。我们每次向下滑动网页&#xff0c;会发现图…

基于Java的医院预约挂号系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

uboot启动流程-涉及lowlevel_init汇编函数

一. uboot启动流程涉及函数 之前文章简单分析了 uboot启动流程的开始&#xff0c;从链接脚本文件 u-boot.lds 中&#xff0c;我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的 _start函数。 _start函数&#xff1a;调用了 reset 函数&#xff0c;reset 函数内部&…

【小沐学前端】Node.js实现基于Protobuf协议的UDP通信(UDP/TCP/WebSocket)

文章目录 1、简介1.1 node1.2 Protobuf 2、下载和安装2.1 node2.2 Protobuf2.2.1 安装2.2.2 工具 3、node 代码示例3.1 HTTP3.2 UDP单播3.4 UDP广播 4、Protobuf 代码示例4.1 例子: awesome.proto4.1.1 加载.proto文件方式4.1.2 加载.json文件方式4.1.3 加载.js文件方式 4.2 例…

An attempt was made to call the method xxx but it does not exist

场景 在公司项目中做配置迁移的时候&#xff0c;服务启动时报错 报错信息 Description:An attempt was made to call the method redis.clients.jedis.Jedis.<init>(Ljava/lang/String;IIIZLjavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/SSLParameters;Ljavax/net/…

编程每日一练(多语言实现)基础篇:求总数问题

文章目录 一、实例描述二、技术要点三、代码实现3.1 C 语言实现3.2 Python 语言实现3.3 Java 语言实现3.4 JavaScript 语言实现 一、实例描述 集邮爱好者把所有的邮票存放在三个集邮册中&#xff0c;在A册内存放全部的十分之二&#xff0c;在B册内存放不知道是全部的七分之几&…

xPortPendSVHandler任务切换流程

__asm void xPortPendSVHandler( void ) { extern uxCriticalNesting; extern pxCurrentTCB; extern vTaskSwitchContext; PRESERVE8 mrs r0, psp isb//指令同步命令&#xff0c; ldr r3, pxCurrentTCB /* Get the location of the current TCB. */ ldr r2, [r3]//r2保存…