首頁 > 軟體

Java程式設計師:專門為SpringBoot定製的防重元件

2021-05-18 08:00:13

Tomato是一款專門為SpringBoot定製的業務防止重複提交的元件。使用極其簡單,基於SpringBoot自動化配置,可以達到開箱即用的境界。無需條件任何多餘的配置。最近更新了到1.0.6-RELEASE新的版本引入了完美支援了SpringEL表示式,支援更加豐富的語法。下面主要介紹其用法。

一、防重 & 冪等的解決方案

防重和冪等其實是兩種概念,但是一般大部分開發都會將其混為一談,所以為避免這種情況,這裡著重在此解析一下。

1.1 防重

防重就是防止表單重複提交,是一種技術上的解決方案,它可以在一定程度上幫助我們的程式做到冪等。但是防重並不等於冪等防重只是一種技術,在短時間內對重複的請求做一個攔截。防止因為併發場景導致的冪等問題。如下圖所示,當兩個執行緒因為併發都執行完了2步驟,進入到了3步驟就會導致重複執行啟用操作。為了解決這種場景,我們就需要攔截重複的請求。【這裡就可以使用我們本文的Tomato來解決】

1.2 冪等

冪等往往是一種業務上的含義,比如說買火車票一張票只能賣給一個人。如果火車票買給了兩個人,那就會出現嚴重的問題。再比如上圖,一個產品的溯源碼只能啟用一次,如果激活了多次就是沒有用的了。對於解決冪等問題,徹底的解決方案就是利用資料庫的唯一索引,如果同一條資料插入了一次,那麼再次插入資料的時候就會報錯。但是這種情況完全就是利用資料庫來做冪等的,雖然簡單,但是對於資料庫的壓力就比較大了。所以往往程式開發者會做多次校驗,然後再用資料庫來兜底,避免直接對資料庫進行傷害。那麼這種解決方案就很多了。如下例子。

1.2.1 業務校驗

通過業務邏輯進行前置校驗,比如在賣票的時候先去查詢一下,這個人有沒有已經買過票了。或者是查詢要賣的這張票是否已經屬於其他人了。如果沒有的話就可以買。看上去也是不錯的吧,但是這裡面時候有一個問題,如果併發量很大的場景下,同一個人提交了2次,或者多個人都來搶這個票,就會有問題,解決方案就是如果多個人併發搶這一張票就要對這張票加鎖。一個人操作完再讓另外一個人搶。好比我們在12306買票,如果搶到了30分鐘內沒有支付,這張票才能被其他人買,其實就是這張票被這個人鎖定了,其他人看不到。場景2當同一人併發提交了2次搶這一張票的時候,也只會讓這人支付一次,不會因為這個人提交了2次就支付兩次。這裡的解決方案就是防止重複提交。

通過前面說的這兩個情況,我們應該清楚,冪等和防重不是一個概念,冪等是業務上的概念,防重是一種技術。而我們可以通過防止重複提交來一定程度上解決冪等問題。但是做到了防重並不一定代表著做到了冪等。這點一定要注意。

下面我們介紹這款簡單易用的防止重複提交的後端解決方案。Tomato【西紅柿】

二、如何使用Tomato

tomato已經持續釋出了6個版本,其核心邏輯非常簡單,就是利用redis來做防重判斷,另外依賴redis來達到分散式防重的能力。大家感興趣的可以去看看它的源碼。是開源的元件。這裡介紹它最新的版本。

元件的作者比較活躍,一直在對其進行維護使用。大家可以一起聊天交流。或者是提供更好的解決方案。

2.1 引入依賴

最新版本1.0.6.RELEASE。 到這裡就結束了。就這麼簡單。

<dependency> <groupId>com.github.lxchinesszz</groupId> <artifactId>tomato-spring-boot-starter</artifactId> <version>1.0.6.RELEASE</version></dependency>2.2 那麼如何看引入成功了呢?

啟動SpringBoot應用,如果看到下面的提示。說明就成功了。

2.3 使用

使用非常簡單如圖所示,通過SpringEl表示式的加持更加簡單好用,且支援表示式裡面使用自定義的函數。

2.2 新特性-支援SpringEL表示式

1.0.6.RELEASE 是最近釋出的版本,對之前的業務做了重構優化了程式碼的效率。同時引入了Spring的EL表示式,並在其基礎上做了一定的擴展。是我們可以在表示式更加的靈活和方便。為了讓大家快速的瞭解Spring的EL語法,這裡就把項目中使用的單測用例。展示一下。相信大家一看就會使用。

@Test public void testExample() { // 表示式解析器 User lx = new User("liuxin", 23,new Phone("123213321")); // 執行toString方法 System.out.println(ExpressionUtils.getElValue("toString()", lx)); System.out.println(ExpressionUtils.getThisElValue("${name}", lx)); // 支援從根元素獲取資料 System.out.println(ExpressionUtils.getThisElValue("S_AO:${name}", lx)); System.out.println(ExpressionUtils.getThisElValue("${name + '_字尾'}", lx)); // 支援從變數元素獲取資料,根元素 = c #是變數,$是模板佔位符 System.out.println(ExpressionUtils.getThisElValue("${#c.name}, ${#c.age}", lx)); // 獲取toString方法 System.out.println(ExpressionUtils.getThisElValue("${#c.toString()}", lx)); // 獲取值並處理 System.out.println(ExpressionUtils.getThisElValue("${#c.age +'-'+ #c.age}", lx)); // 獲取值,並通過方法計算 System.out.println(ExpressionUtils.getThisElValue("${T(Integer).parseInt(#c.age + 1)}", lx)); // 計算雜湊值 System.out.println(ExpressionUtils.getThisElValue("${T(com.github.tomato.support.DefaultTokenProviderSupportTest).hash(#c.age + 1)}", lx)); System.out.println(ExpressionUtils.getThisElValue("${T(com.github.tomato.support.DefaultTokenProviderSupportTest).json(#c)}", lx)); }

大家快去試用體驗吧。


IT145.com E-mail:sddin#qq.com