Mybatis自定义插件生成雪花ID做为主键项目

先附上项目项目GitHub地址 spring-boot-mybatis-interceptor

有关Mybatis雪花ID主键插件前面写了两篇博客作为该项目落地的铺垫。

1、Mybatis框架---Mybatis插件原理

2、java算法---静态内部类实现雪花算法

该插件项目可以直接运用于实际开发中,作为分布式数据库表主键ID使用。

一、项目概述

1、项目背景

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

主键自增1、自增ID容易被爬虫遍历数据。2、分表分库会有ID冲突。

UUID: 1、太长,并且有索引碎片,索引多占用空间的问题 2、无序。

雪花算法就很适合在分布式场景下生成唯一ID,它既可以保证唯一又可以排序,该插件项目的原理是

通过拦截器拦截Mybatis的insert语句,通过自定义注解获取到主键,并为该主键赋值雪花ID,插入数据库中。

2、技术架构

项目总体技术选型

SpringBoot2.1.7 + Mybatis + Maven3.5.4 + Mysql + lombok(插件)

3、使用方式

在你需要做为主键的属性上添加@AutoId注解,那么通过插件可以自动为该属性赋值主键ID。

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

4、项目测试

配置好数据库连接信息,直接启动Springboot启动类Application.java,访问localhost:8080/save-foreach-user就可以看到数据库数据已经有雪花ID了。

如图

二、项目代码说明

在正式环境中只要涉及到插入数据的操作都被该插件拦截,并发量会很大。所以该插件代码即要保证线程安全又要保证高可用。所以在代码设计上做一些说明。

1、线程安全

这里的线程安全主要是考虑产生雪花ID的时候必须是线程安全的,不能出现同一台服务器同一时刻出现了相同的雪花ID,这里是通过

静态内部类单例模式 + synchronized

来保证线程安全的,具体有关生成雪花ID的代码这里就不粘贴。

2、高可用

我们去思考消耗性能比较大的地方可能出要出现在两个地方

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

第一点

其实在静态内部类实现雪花算法这篇博客已经简单测试过,生成20万条数据,大约在1.7秒能满足实际开发中我们的需要。

第二点

这里是有比较好的解决方案的,可以通过两点去改善它。

1)、在插件中添加了一个Map处理器

   /**
* key值为Class对象 value可以理解成是该类带有AutoId注解的属性,只不过对属性封装了一层。
* 它是非常能够提高性能的处理器 它的作用就是不用每一次一个对象经来都要看下它的哪些属性带有AutoId注解
* 毕竟类的反射在性能上并不友好。只要key包含该Class,那么下次同样的class进来,就不需要检查它哪些属性带AutoId注解。
*/
private Map<Class, List<Handler>> handlerMap = new ConcurrentHashMap<>();

插件部分源码

public class AutoIdInterceptor implements Interceptor {
/**
* Map处理器
*/
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);
}
}
}

2)添加break label(标签)

这个就比较细节了,因为上面的process方法不是线程安全的,也就是说可能存在同一时刻有N个线程进入process方法,那么这里可以优化如下:

      //添加了SYNC标签
SYNC:
if (handlerList == null) {
//此时handlerList确实为null,进入这里
synchronized (this) {
handlerList = handlerMap.get(handlerKey);
//但到这里发现它已经不是为null了,因为可能被其它线程往map中插入数据,那说明其实不需要在执行下面的逻辑了,直接跳出if体的SYNC标签位置。
//那么也就不会执行 if (handlerList == null) {}里面的逻辑。
if (handlerList != null) {
break SYNC;
}
}
}

这里虽然很细节,但也是有必要的,毕竟这里并发量很大,这样设计能一定程度提升性能。

 我相信,无论今后的道路多么坎坷,只要抓住今天,迟早会在奋斗中尝到人生的甘甜。抓住人生中的一分一秒,胜过虚度中的一月一年!(7)

Mybatis框架(9)---Mybatis自定义插件生成雪花ID做为表主键项目的更多相关文章

  1. Mybatis框架(8)---Mybatis插件原理

    Mybatis插件原理 在实际开发过程中,我们经常使用的Mybaits插件就是分页插件了,通过分页插件我们可以在不用写count语句和limit的情况下就可以获取分页后的数据,给我们开发带来很大 的便 ...

  2. MyBatis框架之mybatis逆向工程自动生成代码

    http://www.jb51.net/article/82062.htm Mybatis属于半自动ORM,在使用这个框架中,工作量最大的就是书写Mapping的映射文件,由于手动书写很容易出错,我们 ...

  3. JavaWeb_(Mybatis框架)使用Mybatis对表进行增、删、改、查操作_二

    系列博文: JavaWeb_(Mybatis框架)JDBC操作数据库和Mybatis框架操作数据库区别_一 传送门 JavaWeb_(Mybatis框架)使用Mybatis对表进行增.删.改.查操作_ ...

  4. 从Redis生成数据表主键标识

    对于MySql的全局ID(主键),我们一般采用自增整数列.程序生成GUID.单独的表作为ID生成器,这几种方案各有优劣,最终效率都不能说十分理想(尤其海量数据下),其实通过Redis的INCR可以很方 ...

  5. mybatis框架(1)---mybatis入门

    mybatis入门   MyBatis是什么? MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了goog ...

  6. mybatis框架(7)---mybatis逆向工程

    mybatis逆向工程 ​ 逆向工程的目的就是缩减了我们的开发时间.所谓mybatis逆向工程,就是mybatis会根据我们设计好的数据表,自动生成pojo.mapper以及mapper.xml. 接 ...

  7. mybatis框架(6)---mybatis插入数据后获取自增主键

    mybatis插入数据后获取自增主键 首先理解这就话的意思:就是在往数据库表中插入一条数据的同时,返回该条数据在数据库表中的自增主键值. 有什么用呢,举个例子: 你编辑一条新闻,同时需要给该新闻打上标 ...

  8. Mybaits 源码解析 (一)----- 搭建一个mybatis框架(MyBatis HelloWorld)

    源码分析之前先搭一个mybatis的demo,这个在看源码的时候能起到了很大的作用,因为在看源码的时候,会恍然大悟,为什么要这么配置,为什么要这么写.(老鸟可以跳过这篇) 开发环境的准备 创建mave ...

  9. SpringBoot--Easycode、mybatisX插件生成entity,controller,service,dao,mapper IDEA版 项目提效神器

    一.介绍 Easycode是idea的一个插件,可以直接对数据的表生成entity,controller,service,dao,mapper,无需任何编码,简单而强大. MybatisX 是一款基于 ...

随机推荐

  1. 数据结构-哈夫曼树(python实现)

    好,前面我们介绍了一般二叉树.完全二叉树.满二叉树,这篇文章呢,我们要介绍的是哈夫曼树. 哈夫曼树也叫最优二叉树,与哈夫曼树相关的概念还有哈夫曼编码,这两者其实是相同的.哈夫曼编码是哈夫曼在1952年 ...

  2. 简单分析线程获取ReentrantReadWriteLock 读锁的规则

    1. 问题 最近有同事问了我一个问题,在Java编程中,当有一条线程要获取ReentrantReadWriteLock的读锁,此时已经有其他线程获得了读锁,AQS队列里也有线程在等待写锁.由于读锁是共 ...

  3. libvirt-qemu-TLS加密虚拟机传输实例分析

    说明 TLS(Transport Layer Security Protocol),即安全传输层协议,其核心是加密两台计算机之间的通信.libvirt中使用TLS,可以实现libvirt的安全加密.可 ...

  4. 《VR入门系列教程》之1---预热篇

     序     初识虚拟现实技术,非常倾心,奋力习之,阅<Learning Virtual Reality>一书之后觉得甚好,但不愿独乐乐,于是翻译之,与大家共同学习.本人学艺不精,难免有翻 ...

  5. Linux目录文件

    /binbin是binary的缩写.这个目录沿袭了UNIX系统的结构,存放着使用者最经常使用的命令.例如cp.ls.cat,等等. /boot这里存放的是启动Linux时使用的一些核心文件. /dev ...

  6. Linux 下实践 VxLAN:虚拟机和 Docker 场景

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫. 在上篇文章 ...

  7. 【iOS】receiver type *** for instance message is a forward declaration

    错误原因:没有引入相关的头文件 http://stackoverflow.com/questions/8815200/receiver-type-for-instance-message-is-a-f ...

  8. DDMS 视图 Emulator Control 为灰色

    Emulator Control 模拟发送短信时,发现所有选项均为灰色,如图所示: 解决方法: 确认以下四种情形或方法 已测试 Genymotion 模拟器和真机均不行,而Eclipse自带模拟器可以 ...

  9. 机房ping监控 smokeping+prometheus+grafana(续) 自动获取各省省会可用IP

    一.前言 1.之前的文章中介绍了如何使用smokeping监控全国各省的网络情况:https://www.cnblogs.com/MrVolleyball/p/10062231.html 2.由于之前 ...

  10. 【原创】JAVA进程突然消失的原因?

    引言 值此七夕佳节,烟哥放弃了无数妹纸的邀约,坐在电脑面前码字,就是为了给读者带来新的知识,这是一件伟大的事业! 好吧,实际情况是没人约.为了化解尴尬,我决定卖力写文章,嗯,一定是我过于屌丝! 好了, ...