亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

解決"并發(fā)下查詢并更新帶來的問題"

roadtogeek / 2259人閱讀

摘要:場景在日常開發(fā)中經(jīng)常遇到先根據(jù)條件判斷某條數(shù)據(jù)是否存在,如果不存在的話就插入,如果存在的話就更新或提示異常。查詢名字叫的用戶是否存在如果不存在就插入數(shù)據(jù)使用鎖其實和代碼塊是相同的作用,但是要注意必須在中釋放鎖,避免出現(xiàn)異常死鎖了。

場景:

在日常開發(fā)中經(jīng)常遇到先根據(jù)條件判斷某條數(shù)據(jù)是否存在,如果不存在的話就插入,如果存在的話就更新或提示異常。一般代碼的模式都寫成下面這個樣子,是一種很常見的寫法,但是在并發(fā)情況下很容易會重復(fù)插入兩條數(shù)據(jù),大概的情況就是第一個請求進來,沒有查詢到該用戶通過了if判斷,但是if中有比較耗時的邏輯,在第一個請求還沒執(zhí)行insert的時候第二個請求也進來了,因為這個時候第一個請求還沒執(zhí)行insert操作,所以第二個請求也沒有查詢到該用戶也通過了if判斷,這個樣子就造成了兩條重復(fù)的數(shù)據(jù)。

// 查詢名字叫user1的用戶是否存在
UserVo userVo= userMapper.selectUserByName("user1");
    // 如果不存在就插入數(shù)據(jù)
    if (userVo==null) {
        Thread.sleep(10000);
        UserVo userVo = new UserVo();
        userVo.setUserName("user1");
        userMapper.insert(userVo);
     }
}
解決方法: 1.使用synchronized同步代碼塊

直接將查詢校驗邏輯和插入邏輯都進行同步,也就是說第一個請求的邏輯沒結(jié)束,第二個請求就會一直等待著,只有當(dāng)?shù)谝粋€請求執(zhí)行完同步代碼塊中的邏輯釋放鎖后第二個請求才能獲取到鎖執(zhí)行這段邏輯。

private Object obj = new Object();

synchronized (object){
    // 查詢名字叫user1的用戶是否存在
    UserVo userVo= userMapper.selectUserByName("user1");
    // 如果不存在就插入數(shù)據(jù)
    if (userVo==null) {
        Thread.sleep(10000);
        UserVo userVo = new UserVo();
        userVo.setUserName("user1");
        userMapper.insert(userVo);
     }
}
2.使用Lock

其實和synchronized代碼塊是相同的作用,但是要注意必須在finally中釋放鎖,避免出現(xiàn)異常死鎖了。

private Lock lock = new ReentrantLock();
try {
    lock.lock();
    // 查詢名字叫user1的用戶是否存在
    UserVo userVo = userMapper.selectUserByName("user1");
    // 如果不存在就插入數(shù)據(jù)
    if (userVo == null) {
        Thread.sleep(10000);
        UserVo userVo = new UserVo();
        userVo.setUserName("user1");
        userMapper.insert(userVo);
    }
} finally {
    lock.unlock();
}
3.給數(shù)據(jù)庫索引

既然是要根據(jù)用戶名字判斷是否有重復(fù)數(shù)據(jù),所以可以直接在數(shù)據(jù)庫上給userName字段添加UNIQUE索引,這樣在第二次重復(fù)插入的時候就會提示異常。如果不想重復(fù)插入的時候有報錯提示可以使用INSERT IGNORE INTO語句。而代碼則不必做任何邏輯操作。

// 查詢名字叫user1的用戶是否存在
UserVo userVo= userMapper.selectUserByName("user1");
// 如果不存在就插入數(shù)據(jù)
if (userVo==null) {
    Thread.sleep(10000);
    UserVo userVo = new UserVo();
    userVo.setUserName("user1");
    userMapper.insert(userVo);
   }
}
4.使用redissetnx來作為鎖

redissetnx命令是只有當(dāng)你存入的key不存在時才會成功存入,并返回1,而如果key已經(jīng)存在的時候則存入失敗并返回0,我們可以拿這個特性來當(dāng)做鎖。首先這個方法進來第一步就是執(zhí)行setnx操作,把查詢的用戶名存入redis,然后查詢該用戶是否存在,第一個請求進到if判斷中但是沒執(zhí)行插入邏輯,第二個請求雖然也沒有查詢到該用戶,但是它的setnx會失敗,因為第一個請求存的key還沒刪除,所以這樣就避免了并發(fā)重新插入的問題,而且最大的優(yōu)點就是它不像synchronizedLock無論所有請求進來都只能一個一個通過,使用這種方法是只有當(dāng)操作同一個用戶有并發(fā)請求的時候才會阻塞,而如果是請求兩個不同的用戶時是不會阻塞的,都可以順利通過,因為存入的key是不同的。

// 自動注入spring的redis操作類
@Autowired
private RedisTemplate redisTemplate;

public String addUser (String userName) {
    // 執(zhí)行setnx命令,存入當(dāng)前拿來判斷的用戶名
    BoundValueOperations operations = redisTemplate.boundValueOps(userName);
    // 執(zhí)行setnx命令的結(jié)果,這里封裝的方法是直接返回true和false
    boolean addFlag = operations.setIfAbsent(1);

    // 返回結(jié)果
    String result = null;
    
    UserVo userVo= userMapper.selectUserByName(userName);
    try {
        if (userVo == null && addFlag == true) {
            Thread.sleep(10000);
            UserVo userVo = new UserVo();
            userVo.setUserName("user1");
            userMapper.insert(userVo);
            result = "更新成功";
        } else{
            result = "更新失敗";
        }
    } finally {
        // 無論更新成功和失敗都去刪除setnx添加的key
        operations.getOperations().delete(userName);
    }
    return result;
}
總結(jié):

上述四種方法,給數(shù)據(jù)庫加索引、Lockredis都有使用過,synchronizedLock也差不多,個人感覺給數(shù)據(jù)庫加索引來控制這種并發(fā)太死板了,萬一系統(tǒng)中有其他地方的邏輯是需要重復(fù)添加這個字段的數(shù)據(jù),這個時候就沒辦法使用索引了,synchronizedLock效率太低了,如果是并發(fā)量太大的這種方式肯定是不可缺的,而redis的這種方法則效率高很多,比較適合并發(fā)量高的操作。

結(jié)尾:

因為本人接觸的系統(tǒng)的并發(fā)量也不是很大,所以對這方面的技術(shù)也是自己在鉆研摸索,可能會有很多地方有遺漏和錯誤,如果大家有更好的方法歡迎一起留言討論,也歡迎指出錯誤。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/77799.html

相關(guān)文章

  • 支付寶防發(fā)方案之"一鎖二判三更新"

    摘要:每年支付寶在雙和雙的活動中,都展示了絕佳的技術(shù)能力。對于異步并發(fā)重復(fù)消息的處理亦是如此,加深對狀態(tài)機的判斷后還可以處理消息亂序問題。 每年支付寶在雙11和雙12的活動中,都展示了絕佳的技術(shù)能力。這個能力不但體現(xiàn)在處理高TPS量的訪問,更體現(xiàn)在幾乎不會出錯,不會出現(xiàn)重復(fù)支付的情況,那這個是怎么做到的呢? 誠然,為了實現(xiàn)在高并發(fā)下仍不會出錯的技術(shù)目標(biāo),支付寶下了很多功夫,比如冪等性的處理,...

    yibinnn 評論0 收藏0
  • 支付寶防發(fā)方案之"一鎖二判三更新"

    摘要:每年支付寶在雙和雙的活動中,都展示了絕佳的技術(shù)能力。對于異步并發(fā)重復(fù)消息的處理亦是如此,加深對狀態(tài)機的判斷后還可以處理消息亂序問題。 每年支付寶在雙11和雙12的活動中,都展示了絕佳的技術(shù)能力。這個能力不但體現(xiàn)在處理高TPS量的訪問,更體現(xiàn)在幾乎不會出錯,不會出現(xiàn)重復(fù)支付的情況,那這個是怎么做到的呢? 誠然,為了實現(xiàn)在高并發(fā)下仍不會出錯的技術(shù)目標(biāo),支付寶下了很多功夫,比如冪等性的處理,...

    imingyu 評論0 收藏0
  • python查詢本身拼裝所有庫導(dǎo)出命令

      文章內(nèi)容通常是闡述了python查詢本身拼裝所有庫并導(dǎo)出,主要包括查詢拼裝庫依據(jù)命令查詢,導(dǎo)出庫安裝文件運行指令,原文中給大家介紹得相當(dāng)詳細,對于大家學(xué)習(xí)與工作具有極強的參考文獻參照實際意義,務(wù)必的朋友可以參考一下  一、查詢拼裝庫  1.命令查詢  piplist  2.從安裝路徑site-packages查詢  二、導(dǎo)出庫安裝文件  1.導(dǎo)出  在我們要導(dǎo)出的庫文件夾內(nèi)運行指令:  pip...

    89542767 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<