1. 程式人生 > >spring data jpa、Hibernate開啟全球唯一UUID設置

spring data jpa、Hibernate開啟全球唯一UUID設置

-- 工具 插入 ring 時間戳 cnblogs 導致 mac class

spring data jpa、Hibernate開啟全球唯一UUID設置

原文鏈接:https://www.cnblogs.com/blog5277/p/10662079.html

原文作者:博客園--曲高終和寡

*******************如果你看到這一行,說明爬蟲在本人還沒有發布完成的時候就抓走了我的文章,導致內容不完整,請去上述的原文鏈接查看原文****************

UUID這個東西,具體的我就不講了,網上的內容很多,我這裏就隨便放一個大家看一下就了解了

https://www.jianshu.com/p/d77f3ef0868a

這裏面有關於發號器,UUID的介紹,具體各位是使用UUID的哪個版本,或者使用雪花ID,或者使用其他別的方式,請各位自行判斷

在我的業務裏面呢:

1.準備部署至少兩臺服務器,且兩臺服務器時區不一樣,一臺阿裏雲香港,東八區,一臺美國洛杉磯,多少區忘了,反正有13個小時的時差,

——雪花ID的方案就被我否了,因為我不能保證美國那臺服務器的時區不會根據冬夏令時來回跳,雪花ID在時鐘回撥的情況下會一直等候,我也不需要雪花ID有序這個優點。

2.同樣為了容災,我準備在兩臺服務器分別部署數據庫

——主鍵自增的方案就被我否了,遷移有點麻煩了

3.我不需要主鍵來排序,我選用的PostgresQL也不會因為主鍵是字符型的而導致插入、讀取變快

——所以我不需要一切主鍵需要有序的生成方案,UUID完美符合我的需求

4.既然選用了UUID,我就希望它在任何情況下都不會重復,全球唯一

——那麽UUID的生成方案2.3.4.5就都不滿足我的要求了,雖然概率極地,但是還是有理論上重復的可能性的

5.UUID的方案1存在一定的危險性,是根據MAC地址(或者IP)生成的,那麽理論上能根據MAC地址找到所在地

——。。。然後呢。。。?我一臺服務器/IP在香港,一臺服務器/IP在洛杉磯,想通過這倆地方來找我怕是不太可能嗷。。。更何況我寫的東西根本就不會有多少人用,更沒有什麽法律風險不擔心被查水表,更沒有什麽價值。。。?誰會來搞我?

所以,最終選用了方案1的UUID生成方法,不可能重復,我開發的時候就不用考慮這種極小概率會導致的BUG,放心大膽的用就是了。

而生成方案1的UUID有很多工具包,比如Apache common 的UUID 包,還有github上一個項目 JAU,項目地址:

https://github.com/cowtowncoder/java-uuid-generator

我太懶了,不想在項目裏引入一個包,就為了生成UUID。。。所以就查了一下,原來HIbernate對生成UUID方案1還做了優化:

Version1變種 – Hibernate

Hibernate的CustomVersionOneStrategy.java,解決了之前version 1的兩個問題

- 時間戳(6bytes, 48bit):毫秒級別的,從1970年算起,能撐8925年….
- 順序號(2bytes, 16bit, 最大值65535): 沒有時間戳過了一秒要歸零的事,各搞各的,short溢出到了負數就歸0。
- 機器標識(4bytes 32bit): 拿localHost的IP地址,IPV4呢正好4個byte,但如果是IPV6要16個bytes,就只拿前4個byte。
- 進程標識(4bytes 32bit): 用當前時間戳右移8位再取整數應付,不信兩條線程會同時啟動。

值得留意就是,機器進程和進程標識組成的64bit Long幾乎不變,只變動另一個Long就夠了。

Hibernate解決了Version1的兩個問題,哪兩個問題呢:

但好像Version 1就沒考慮過一臺機器上起了兩個進程這類的問題,也沒考慮相同時間戳的並發問題

很好,HIbernate解決了這倆問題,那完美符合我的需求,並且本來項目就引入了JPA,官方支持豈不美哉?

廢話說了那麽多,配置只需要兩行的事,然而這個配置國內網站幾乎找不到,困擾了我很久怎麽在Hibernate裏面設置選用CustomVersionOneStrategy.java,作為主鍵生成策略的

@Entity
@Data
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@GenericGenerator(
        name = "uuid2",
        strategy = "uuid2",
        parameters = {@org.hibernate.annotations.Parameter(
                name = "uuid_gen_strategy_class",
                value = "org.hibernate.id.uuid.CustomVersionOneStrategy")
        })
public class BaseDomain {
    @Id
    @GeneratedValue(generator = "uuid2")
    private String id;
    @Column
    private LocalDateTime gmtCreate;
    @Column
    private LocalDateTime gmtModified;

    public void initInsert() {
        this.gmtCreate = LocalDateTime.now();
        this.gmtModified = LocalDateTime.now();
    }

    public void initUpdate() {
        this.gmtModified = LocalDateTime.now();
    }
}

這樣就可以了,以後每一個DO都繼承這個BaseDomain,ID就自動生成Hibernate優化版的版本1UUID了

spring data jpa、Hibernate開啟全球唯一UUID設置