MyBatis拦截器在实际项目中的应用

news2024/9/9 5:32:44

MyBatis 是一个流行的 Java 持久层框架,它简化了数据库访问的复杂性,为开发者提供了强大的功能。其中,MyBatis 拦截器是一个非常有用的特性,可以帮助开发者灵活地解决各种问题。

一、MyBatis 拦截器

1.1 从执行 SQL 语句的核心流程说起

在 MyBatis 中,要执行一条 SQL 语句,会涉及非常多的组件,比较核心的有:Executor、StatementHandler、ParameterHandler 和 ResultSetHandler。下图展示了 MyBatis 执行一条 SQL 语句的核心过程:

 

SQL 语句执行时,首先到达 Executor,Executor 会调用事务管理模块实现事务的相关控制。真正执行将会由 StatementHandler 实现,StatementHandler 会先依赖 ParameterHandler 进行 SQL 模板的实参绑定,然后由 java.sql.Statement 对象将 SQL 语句以及绑定好的实参传到数据库执行。

数据库执行后,从中拿到 ResultSet,最后,由 ResultSetHandler 将 ResultSet 映射成 Java 对象返回给调用方,这就是 SQL 执行模块的核心。

MyBatis 允许开发者拦截这些核心组件的关键方法,从而实现对 SQL 执行过程的自定义控制。

1.2 MyBatis 拦截器

MyBatis 允许我们自定义 Interceptor,拦截 SQL 语句执行过程中的某些关键逻辑,允许拦截的方法有:

  • Executor 类中的 update()、query()、flushStatements()、commit()、rollback()、getTransaction()、close()、isClosed() 方法;

  • ParameterHandler 中的 setParameters()、getParameterObject() 方法;

  • ResultSetHandler中的 handleOutputParameters()、handleResultSets() 方法;

  • StatementHandler 中的 parameterize()、prepare()、batch()、update()、query() 方法。

下面,我们就从实际出发,看看 MyBatis 拦截器的具体使用场景。

二、使用场景

2.1 数据加密

多数公司出于信息安全等考虑,会将个人信息等敏感数据在存储时进行加密,在数据读取时进行解密。这种场景就适合使用 MyBatis 拦截器实现了,具体来说:

写入数据时,拦截 insert 和 update 语句,通过自定义注解获取到加密字段,并对其进行加密后再写入数据库。

读取数据时,拦截 select 语句,通过自定义注解获取到加密字段,对密文进行解密,然后返回给上层调用。

这样就能够在不修改业务代码的情况下,自动完成数据的加解密处理了。我们来看具体的代码实现。

在实体属性上添加@EncryptField注解:

public class UserEntity {
    /**
     * 身份证
     */
    @EncryptField
    private String idCard;
    //其它属性 包括get, set方法
}

接着执行下面插入操作:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest extends TestCase {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void insert() {
        UserEntity user = new UserEntity();
        user.setName("张三");
        user.setIdCard("442222111233322210");
        user.setSex("男");
        user.setAge(0);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setStatus(0);

        userMapper.insert(user);
    }

}

数据库里id_card就是密文了。

在读取数据时,执行下面查询操作: 

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest extends TestCase {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void selectByPrimaryKey() {
        UserEntity user = userMapper.selectByPrimaryKey(682230480968224768L);
        System.out.println(user);
    }

}

返回结果如下:

{
  "id": 682230480968224768,
  "name": "张三",
  "idCard": "442222111233322210",
  "sex": "男",
  "age": 0,
  "createTime": "2024-07-05 10:16:56",
  "updateTime": "2024-07-05 10:16:56",
  "status": 0
}

可以看到,拦截器实现了对数据自动解密。拦截器的具体实现请点击:

  • 读拦截器[1]

  • 写拦截器[2]

接着我们来看第二个场景的应用。

2.2 生成ID主键

在生成表主键 ID 时,我们通常会考虑主键自增或者 UUID,但它们都有很明显的缺点。

  • 对于自增 ID 来说,第一,容易被爬虫遍历数据;第二,分表分库会有 ID 冲突。

  • 对于 UUID 来说,数据太长,且有索引碎片、过多占用索引空间的问题。

雪花算法就很适合在分布式场景下生成唯一 ID,它既可以保证唯一又可以保证有序。通过 MyBatis 拦截器,我们可以实现在插入数据时自动生成全局唯一且有序的雪花 ID。

具体做法是:拦截 insert 语句,通过自定义注解获取主键字段,然后为其赋值雪花 ID 后再写入数据库。我们来看具体的代码实现。

在主键的属性上添加@AutoId注解。

public class UserEntity {
    /**
     * id(添加自定义注解)
     */
    @AutoId
    private Long id;
    /**
     * 姓名
     */
    private String name;
    //其它属性 包括get,set方法
}

执行插入操作后,数据库里就已经有雪花ID了。

如果在正式环境中,由于只要涉及到插入数据的操作都被该插件拦截,并发量会很大。所以该插件代码既要保证线程安全又要保证高性能。

1、线程安全

产生雪花 ID 的时候必须是线程安全的,不能出现同一台服务器同一时刻出现了相同的雪花 ID,可以通过:

单例模式 + synchronized

来实现。

2、高性能

性能消耗比较大可能会出现在两个地方:

1)雪花算法生成雪花ID的过程。
2)通过类的反射机制找到哪些属性带有@AutoId注解的过程。

第一,生成雪花ID。简单测试过,生成20万条数据,大约在1.7秒,能满足我们实际开发中的需要。

第二,反射查找。可以在插件中添加缓存。

/**
 * key值为Class对象 value可以理解成是该类带有AutoId注解的属性
 */
private Map<Class, List<Handler>> handlerMap = new ConcurrentHashMap<>();

插件部分源码如下:

public class AutoIdInterceptor implements Interceptor {
    /**
     * 处理器缓存
     */
    private Map<Class, List<Handler>> handlerMap = new ConcurrentHashMap<>();

    private void process(Object object) throws Throwable {
        Class handlerKey = object.getClass();
        List<Handler> handlerList = handlerMap.get(handlerKey);
        //先判断handlerMap是否已存在该class,不存在先找到该class有哪些属性带有@AutoId
        if (handlerList == null) {
            handlerMap.put(handlerKey, handlerList = new ArrayList<>());
            // 通过反射 获取带有AutoId注解的所有属性字段,并放入到handlerMap中
        }
         //为带有@AutoId赋值ID
        for (Handler handler : handlerList) {
            handler.accept(object);
        }
    }
}

三、小结

MyBatis 拦截器是一个非常值得开发者深入学习和应用的技术。相信通过本文的介绍,您已经对 MyBatis 拦截器有了更加具体的认识。如果您还有任何疑问,欢迎与我交流探讨。

 

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

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

相关文章

力扣爆刷第163天之TOP100五连刷81-85(回文链表、路径和、最长重复子数组)

力扣爆刷第163天之TOP100五连刷81-85&#xff08;回文链表、路径和、最长重复子数组&#xff09; 文章目录 力扣爆刷第163天之TOP100五连刷81-85&#xff08;回文链表、路径和、最长重复子数组&#xff09;一、234. 回文链表二、112. 路径总和三、169. 多数元素四、662. 二叉树…

sort命令

简介 sort是在Linux里非常常用的一个排序命令。将文件的每一行作为一个单位&#xff0c;从首字符向后&#xff0c;依次按ASCII码值进行比较&#xff0c;默认将他们按升序输出。 常用参数 -u &#xff1a;去除重复行 -r &#xff1a;降序排列&#xff0c;默认是升序 …

华为HCIP Datacom H12-821 卷36

1.单选题 在PIM- SM中&#xff0c;以下关于RP 的描述&#xff0c;错误的是哪一选项? A、在PIM-SM中&#xff0c;组播数据流量不一定必须经过RP的转发。 B、对于一个组播组来说&#xff0c;可以同时有多个RP地址&#xff0c;提升网络可靠性。 C、组播网络中&#xff0c;可以…

一篇文章带你解密最近爆火的消费增值模型!

今天&#xff0c;我非常激动地向您介绍一个令人振奋的成功故事。我们的合作伙伴在短短一个月内实现了业绩的飞跃&#xff0c;达到了百万级别的销售额&#xff0c;同时他们的用户活跃度也保持在极高的水平&#xff0c;平均每天有8万至10万的在线用户。这一成就的取得&#xff0c…

ARMV8安全特性:Pointer Authentication

文章目录 前言一、Introduction二、Problem Definition三、Pointer Authentication3.1 Instructions3.2 Cryptography3.3 Key Management 四、Sample Use Cases4.1 Software Stack Protection4.2 Control Flow Integrity (CFI)4.3 Binding Pointers to Addresses 五、Security …

十大优秀AI人工智能作词软件有哪些?

1、妙笔生词&#xff1a;国内专业智能作词工具&#xff0c;是一款非常优秀的国内作词软件&#xff0c;它可以选择语言&#xff0c;风格&#xff0c;韵脚一键生成歌词&#xff0c;也可以仿写歌词&#xff0c;可以续写歌词&#xff0c;可以智能取歌名&#xff0c;找优秀词句&…

华宇携TAS应用中间件亮相2024年山东江信智能信创产品推介会

信创产业是数据、网络安全的基础&#xff0c;也是“新基建”的重要内容&#xff0c;将成为拉动经济发展的重要抓手之一。 7月5日&#xff0c;以“信守时代机遇&#xff0c;创造辉煌未来”为主题的山东江信智能信创产品推介会在济南举办。本次产品推介会汇聚了国内众多信息技术…

windows sshkeygen 多平台添加配置

文章目录 .ssh目录生成新的ssh配置添加公钥到仓库验证 .ssh目录 windows下一般为&#xff1a;C:\Users\15237\.ssh &#xff0c;其中“15237”为当前登录用户 生成新的ssh .ssh目录下打开“Git Bash Here”&#xff08;如果没有&#xff0c;先安装 Git 软件&#xff09; 执…

阿一课代表今日分享之使用dnscat2 进行dns隧道反弹shell(直连模式linux对linux)

DNS介绍 DNS是域名系统(Domain Name System)的缩写&#xff0c;是因特网的一项核心服务&#xff0c;它作为可以将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便的访问互联网&#xff0c;而不用去记住能够被机器直接读取的IP数串。 DNS的记录类型有很多&a…

The First项目报告:创新型金融生态Lista DAO

一、Lista DAO是什么&#xff1f; LISTA是Lista DAO的原生加密协议代币&#xff0c;设计为一种可互操作的实用代币&#xff0c;旨在促进去中心化金融&#xff08;DeFi&#xff09;领域内的支付、治理与激励。LISTA的诞生源于Lista DAO项目&#xff0c;该项目是一个基于BNB链的…

IntelliJ IDEA 2024.1.4最新教程!!直接2099!!爽到飞起!!

IntelliJ IDEA 2024.1.4最新破解教程&#xff01;&#xff01;直接2099&#xff01;&#xff01;爽到飞起&#xff01;&#xff01;【资源在末尾】安装馆长为各位看官准备了多个版本&#xff0c;看官可根据自己的需求进行下载和选择安装。https://mp.weixin.qq.com/s/Tic1iR_Xc…

【一文带你了解RAG(检索增强生成) | 概念理论介绍+ 代码实操(含源码)】

文末有福利&#xff01; 引言 针对大型语言模型效果不好的问题&#xff0c;之前人们主要关注大模型再训练、大模型微调、大模型的Prompt增强&#xff0c;但对于专有、快速更新的数据却并没有较好的解决方法&#xff0c;为此检索增强生成&#xff08;RAG&#xff09;的出现&am…

【简历】南京某一本大学:JAVA简历指导,基本拿不到offer

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 这份简历是一个一本计算机专业的同学。一本同学在校招的时候&#xff0c;要做好自己的求职层次定位&#xff0c;因为像工业类、邮电类、…

【JavaScript 报错】未捕获的URI错误:Uncaught URIError

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、错误原因分析1. 不合法的URI字符2. 不匹配的编码 二、解决方案1. 检查URI字符2. 使用try-catch块 三、实例讲解四、总结 Uncaught URIError 是JavaScript中常见的一种错误&#xff0c;通常发生在全局URI处理函数&#x…

前端如何取消接口调用

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 1. xmlHttpRequest是如何取消请求的&#xff1f; 实例化的XMLHttpRequest对象上也有abort方法 const xhr new XMLHttpRequest(); xhr.addEventListener(load, function(e)…

程控水冷阻性负载是否有替代品出现?

程控水冷阻性负载是广泛应用于工业生产过程中的设备&#xff0c;主要用于冷却和控制电阻性负载。然而&#xff0c;随着科技的不断发展&#xff0c;新型的冷却和控制设备不断涌现&#xff0c;使得程控水冷阻性负载面临着替代品的挑战。 空气冷却系统是一种可能的替代品&#xff…

形态学图像处理

1 工具 1.1 灰度腐蚀和膨胀 当平坦结构元b的原点是(x,y)时&#xff0c;它在(x,y)处对图像f的灰度腐蚀定义为&#xff0c;图像f与b重合区域中的最小值。结构元b在位置(x,y)处对图像f的腐蚀写为&#xff1a; 类似地&#xff0c;当b的反射的原点是(x,y)时&#xff0c;平坦结构元…

C++ 【 Open3D 】 点云按高程进行赋色

一、 Open3D中根据点云的高程度信息为点云中的每个点附上颜色&#xff0c;并保存颜色渲染结果&#xff01; #include<iostream> #include<open3d/Open3D.h>using namespace std;int main() {//-------------------------------读取点云--------------------------…

FastAPI 学习之路(四十三)路径操作的高级配置

在实际开发中&#xff0c;可能我们有些接口不能在接口文档中与其他业务接口一样开放给前端或者其他对接人&#xff0c;那么我们肯定会想着在接口文档中对其进行屏蔽隐藏操作&#xff0c;那么可以实现吗&#xff1f; 接口文档中隐藏接口 当然&#xff0c;还很简单&#xff0c;…

利用Hbuilder创建vue3的web项目

大体流程如下 npm install vue-router4 下载完&#xff0c;就创建完了