mybatis的執行緒安全

2022-04-04 00:09:39 字數 2879 閱讀 4744

mybatis與jdbc最主要的區別就是mybatis用的是sqlsession,其實作用都是一樣的,就是資料庫的乙個連線,那麼sqlsession是不是執行緒安全呢?答案是否定的,

以下是測試過程:

這裡有兩個語句:查詢和修改:

當查詢和修改放在controller下,也就是沒放在乙個事務下的時候,會建立兩個sqlsession

而這兩個語句放在service 層中並開啟註解後會發現:

後來的乙個sql會獲取前邊的sqlsession並使用:

也就是說,獲取的連線是乙個,但是這樣能否保證執行緒安全呢?

於是我做了以下測試:

先進行查詢然後,在1秒內往資料庫插入100條資料,通過jmeter實現:

於是資料庫出現了這樣的場景:

可以看到資料全是一樣的,這說明連線的一致與執行緒安全無關,那怎麼解決這樣的執行緒安全呢?

什麼是鎖?我的理解是鎖就是唯一的乙個東西。

首先想到的是鎖:

1.synchonized和lock都可以實現,但是加鎖會消耗效能。

2.再就是 threadlocal,這個可以實現執行緒隔離但是在這裡需要的是執行緒競爭。

3.redis鎖(適合分布式),下面這個可以簡單實現,利用springboot自動裝配的stringredistemplate,因為redis就是單執行緒的,所以通過以下這個setifabsent原子方法可以實現redis鎖

別忘了在最後刪除鎖,但是下面這個**有幾個問題。

1.第一行加鎖成功後宕機了,結果所有執行緒都阻塞了,可以通過設定超時時間釋放鎖,但是這樣也有問題:如果乙個執行緒在時間內沒有執行完業務就把鎖釋放了,會導致鎖失效,

這種可以建立乙個執行緒用來非同步完成續命,就是通過乙個while迴圈,設定鎖的時常,注意一定要另開乙個執行緒,不然就會一直阻塞在續命這裡。

2.設定時間後假設時間是2s,2s後執行緒1沒執行完,但是鎖釋放了,執行緒2獲得了鎖,執行**,這個時候執行緒1執行完了**,然後刪除了這個鎖,但是這個鎖是執行緒2的,

這個可以在刪除鎖之前加乙個判斷,通過uuid進行實現,判斷前後執行的執行緒是否一致,一致的話就可以刪除鎖,然後這個uuid怎麼放呢?首先在加鎖 的時候把uuid放在redis和threadlocal中,

這樣在釋放鎖的時候從threadlocal中拿到uuid,跟redis中的值做判斷,如果是乙個的話就說明是這個執行緒。

3.非阻塞,如果同時有100個執行緒訪問,那麼乙個執行緒獲取鎖之後其他的就return了,不會繼續等待,這種適合於有1000個數量,然後由100個執行緒這樣的差距比較大的場景,如果改成阻塞的話把獲取鎖的**放到while迴圈就可以。

4.不可重入,如下**假設在加鎖後還有另乙個業務,也是需要加鎖的,這樣的話就會加不上鎖,導致不可重入,這個解決辦法是在加鎖前做乙個判斷,先從threadlocal中取資料,如果取不到的話就加鎖,取到的話呢就把boolean值的鎖設定為true,這樣就可以繼續加鎖了。

5.以上所有的問題都可以用redisson來解決。

4.還有cas無鎖,首先理解一下jvm的概念,在controller中每一次請求就是乙個執行緒,controller中的變數什麼的都屬於執行緒的內部變數,彼此不可見這個無所謂但是

下面這個方法是在service層中,執行緒沒通過這裡時update方法就在方法區中,而執行緒通過時就會在各自的虛擬機器棧上建立乙個棧幀,由於jmm策略,在每個棧幀的區域性變數表中

都獲取到乙個同樣的變數n,忽略運算元棧的操作,這裡的n就是0,然後下面這個就是cas鎖了,底層是unsafe包下用c++寫的乙個原子操作,意思是比較並交換,想象一下:

有兩個執行緒獲取同樣的 n,j,當第乙個執行緒進入cas方法後發現n和記憶體中的i是相等的,然後就把 j 賦值給 i,然後才能進行下一步操作,這個時候下乙個執行緒也比較,但是這時記憶體中 i 已經變為 1

了,於是進入迴圈中,重新獲取 記憶體中 i 的值,再 比較交換,整個流程就是這樣的,我說的流程有先後,但是實際上是同時比較交換的,因為 i 是乙個原子類所以不會出錯。

模型:

7.還有通過volatitle變數,通過排它鎖拿到這個變數,這個方法試了貌似可行,後續再研究一下。

8.最近在專案中用公司的jpa框架的@version註解實現了樂觀鎖,這種方法比較簡單直接,可以在mybatis中借鑑一下。

原理:1.先執行乙個查詢操作,拿到資料庫中的樂觀鎖欄位,假設這個樂觀鎖的字段是1,假設如果有兩個執行緒都拿到了這個1的樂觀鎖。

2.執行緒1執行修改操作,在修改的時候對比id和這個樂觀鎖欄位,如果跟之前拿到的一致則修改成功,把version這個樂觀鎖欄位加一

update  表 set   **=**,version = version+1 where id = * and version =*(上一步拿到的樂觀鎖的值)

3.執行緒2修改的時候where 條件發現version跟之前拿到的鎖對不上了,所以修改失敗。

在jpa中這個查詢操作通過@version註解隱藏了,但是確實是存在的。

mybatis的安全模糊查詢

select from user where name like concat 注意 where name like 為什麼說是安全呢?因為還有一種不安全的 where name like 這種不是預編譯功能實現的 攻擊者在介面的表單資訊或url上輸入一些奇怪的sql片段 例如 or 1 1 這樣的...

執行緒安全與非執行緒安全的區別

執行緒安全 是多執行緒訪問時,採用加鎖機制,當乙個執行緒訪問該類的某個資料時,進行保護,其他執行緒不能進行訪問直到該執行緒讀取完,其他執行緒才可使用。不會出現資料不一致或者資料汙染。非執行緒安全 是多執行緒訪問時,不提供資料訪問保護,有可能出現多個執行緒先後更改資料造成所得到的資料是髒資料。所得資料...

執行緒安全(常用的執行緒安全類)

string中的stringbuffer list集合中的vector copyonwritearraylist reentrantlock lock鎖 是執行緒安全的arraylist vector是增刪改查方法都加了synchronized,保證同步,但是每個方法執行的時候都要去獲得鎖,效能就會...