最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入講解基于Java開發(fā)的借據(jù)鎖

 更新時(shí)間:2026年03月08日 11:16:02   作者:LWH!  
這篇文章主要介紹了基于Java開發(fā)借據(jù)鎖的相關(guān)資料,這個(gè)借據(jù)鎖并非編程語言層面的鎖,也不是數(shù)據(jù)庫的行鎖/表鎖,而是一種業(yè)務(wù)層面的邏輯鎖(也叫狀態(tài)鎖/軟鎖),需要的朋友可以參考下

基于 Java 開發(fā)的借據(jù)鎖信息數(shù)據(jù)模型(DO)類,它映射了數(shù)據(jù)庫中的 asset_loan_invoice_lock_info

@Table(name = "asset_loan_invoice_lock_info")
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class AssetLoanInvoiceLockInfoDo extends AssetLoanInvoiceLockInfoKeyDo implements Serializable {
    private static final long serialVersionUID = 1101362594517114915L;
    /**
     * 借據(jù)鎖鎖狀態(tài) EnumBool 0-否 1-是
     */
    @Column(name = "lock_status")
    private String lockStatus;
    /**
     * 鎖定流水
     */
    @Column(name = "lock_serial_no")
    private String lockSerialNo;
    /**
     * 鎖定交易碼
     */
    @Column(name = "lock_trade_code")
    private String lockTradeCode;
    /**
     * 鎖定交易描述
     */
    @Column(name = "lock_trade_description")
    private String lockTradeDescription;
    /**
     * 樂觀鎖版本
     */
    @Column(name = "lock_version")
    private Integer lockVersion;
    /**
     * 創(chuàng)建時(shí)間
     */
    @Column(name = "create_time")
    private java.util.Date createTime;
    /**
     * 更新時(shí)間
     */
    @Column(name = "update_time")
    private java.util.Date updateTime;
    /**
     * 鎖定時(shí)間
     */
    @Column(name = "lock_time")
    private java.util.Date lockTime;
}
字段名類型對(duì)應(yīng)數(shù)據(jù)庫列含義
serialVersionUIDlong-序列化版本號(hào),保證序列化 / 反序列化的兼容性
lockStatusStringlock_status借據(jù)鎖狀態(tài),枚舉值(0 - 未鎖定,1 - 已鎖定)
lockSerialNoStringlock_serial_no鎖定操作的流水號(hào),用于追蹤鎖定行為
lockTradeCodeStringlock_trade_code鎖定交易的編碼,標(biāo)識(shí)具體的鎖定業(yè)務(wù)類型
lockTradeDescriptionStringlock_trade_description鎖定交易的描述信息,補(bǔ)充說明鎖定原因 / 場(chǎng)景
lockVersionIntegerlock_version樂觀鎖版本號(hào),用于解決并發(fā)更新沖突
createTimeDatecreate_time記錄創(chuàng)建時(shí)間
updateTimeDateupdate_time記錄更新時(shí)間
lockTimeDatelock_time借據(jù)鎖定的具體時(shí)間

借據(jù)鎖的核心本質(zhì)

這個(gè) “借據(jù)鎖”并非編程語言層面的鎖(如 Java 的 synchronized、ReentrantLock),也不是數(shù)據(jù)庫的行鎖 / 表鎖,而是一種業(yè)務(wù)層面的邏輯鎖(也叫狀態(tài)鎖 / 軟鎖),本質(zhì)是通過數(shù)據(jù)庫記錄的狀態(tài)標(biāo)識(shí)來控制借據(jù)的操作權(quán)限,屬于金融系統(tǒng)中典型的 “樂觀鎖 + 業(yè)務(wù)狀態(tài)” 組合設(shè)計(jì)。

簡(jiǎn)單來說:它是給每一筆借據(jù)(貸款憑證)加的 “業(yè)務(wù)標(biāo)記”,標(biāo)記該借據(jù)是否被占用,防止同一筆借據(jù)在不同業(yè)務(wù)流程中被重復(fù)操作(比如重復(fù)放款、重復(fù)核銷)。

借據(jù)鎖的核心作用場(chǎng)景

以金融資產(chǎn)系統(tǒng)為例,借據(jù)鎖主要用于這些高并發(fā)、高風(fēng)險(xiǎn)的場(chǎng)景:

  1. 放款操作:發(fā)起放款時(shí),先鎖定借據(jù),防止同一筆借據(jù)被多個(gè)放款請(qǐng)求同時(shí)處理,導(dǎo)致重復(fù)放款;放款完成后解鎖。
  2. 核銷 / 沖正操作:處理借據(jù)的核銷、沖正時(shí),鎖定借據(jù),避免和放款、還款等操作沖突。
  3. 資產(chǎn)處置 / 轉(zhuǎn)讓:借據(jù)涉及資產(chǎn)轉(zhuǎn)讓、抵債等操作時(shí),鎖定后防止其他流程修改借據(jù)狀態(tài)。
  4. 批量處理:系統(tǒng)夜間批量計(jì)算利息、罰息時(shí),鎖定相關(guān)借據(jù),避免批量處理和實(shí)時(shí)操作沖突。

關(guān)鍵字段的配合邏輯:

  • lockStatus:核心開關(guān),0 = 未鎖、1 = 已鎖,是判斷能否操作的核心依據(jù);
  • lockSerialNo:鎖定流水號(hào),可追溯是誰(哪個(gè)業(yè)務(wù)請(qǐng)求)鎖定了借據(jù),便于問題排查;
  • lockTradeCode/lockTradeDescription:記錄鎖定的業(yè)務(wù)類型(比如 “放款”“核銷”),明確鎖定原因;
  • lockVersion:樂觀鎖,防止多線程同時(shí)更新 lockStatus,比如兩個(gè)請(qǐng)求同時(shí)查到 lockStatus=0,更新時(shí)通過版本號(hào)保證只有一個(gè)能成功;
  • lockTime:記錄鎖定時(shí)間,可設(shè)置 “鎖超時(shí)” 邏輯(比如鎖定超過 30 分鐘自動(dòng)解鎖,防止死鎖)。

借據(jù)鎖 vs 技術(shù)鎖的區(qū)別

類型借據(jù)鎖(業(yè)務(wù)邏輯鎖)Java 鎖(編程語言鎖)數(shù)據(jù)庫行鎖
作用范圍跨 JVM、跨服務(wù)(分布式)單個(gè) JVM 進(jìn)程內(nèi)數(shù)據(jù)庫事務(wù)內(nèi)
持久化持久化到數(shù)據(jù)庫,重啟不丟失內(nèi)存中,進(jìn)程重啟消失事務(wù)結(jié)束釋放
鎖超時(shí)可自定義(比如 30 分鐘)需手動(dòng)實(shí)現(xiàn)依賴數(shù)據(jù)庫事務(wù)超時(shí)
適用場(chǎng)景分布式業(yè)務(wù)流程控制單進(jìn)程內(nèi)并發(fā)控制數(shù)據(jù)庫操作的原子性

重復(fù)加鎖問題:

一、為什么會(huì)出現(xiàn)重復(fù)加鎖?

重復(fù)加鎖的本質(zhì)是并發(fā)場(chǎng)景下,“查狀態(tài) - 加鎖” 這兩步操作不是原子性的,常見成因有 3 類:

1. 最典型的并發(fā)競(jìng)態(tài)問題(核心原因)

線程A:查詢lockStatus=0 → 準(zhǔn)備更新為1 線程B:查詢lockStatus=0 → 準(zhǔn)備更新為1 線程A:更新lockStatus=1 ? 線程B:更新lockStatus=1 ?(重復(fù)加鎖)

這種情況在高并發(fā)場(chǎng)景下(比如批量放款)極易發(fā)生,只靠lockStatus字段完全無法防范。

2. 樂觀鎖使用不當(dāng)

如果lockVersion(樂觀鎖)的更新邏輯寫錯(cuò),比如:

-- 錯(cuò)誤寫法:只更新狀態(tài),沒帶版本號(hào)條件 UPDATE asset_loan_invoice_lock_info SET lock_status = '1', lock_time = NOW() WHERE loan_id = 'xxx';

-- 正確寫法:必須帶版本號(hào)條件 UPDATE asset_loan_invoice_lock_info SET lock_status = '1', lock_time = NOW(), lock_version = lock_version + 1 WHERE loan_id = 'xxx' AND lock_status = '0' AND lock_version = #{oldVersion};

一旦樂觀鎖沒生效,就會(huì)出現(xiàn)重復(fù)加鎖。

3. 鎖超時(shí) / 解鎖邏輯漏洞

  • 業(yè)務(wù)操作超時(shí),但沒觸發(fā)解鎖,導(dǎo)致鎖一直占用;
  • 解鎖時(shí)沒校驗(yàn) “鎖歸屬”(比如用lockSerialNo判斷是誰加的鎖),A 加的鎖被 B 解鎖,解鎖后又被 C 重復(fù)加鎖;
  • 沒有鎖超時(shí)機(jī)制,某筆借據(jù)被異常鎖定后,一直無法釋放,業(yè)務(wù)方強(qiáng)行繞過鎖狀態(tài)加鎖。

二、如何徹底避免重復(fù)加鎖?

結(jié)合金融系統(tǒng)的最佳實(shí)踐,需要從原子性、唯一性、可追溯、超時(shí)控制四個(gè)維度設(shè)計(jì)加鎖邏輯:

1. 核心:保證 “查 - 加鎖” 的原子性(必做)

最可靠的方式是用數(shù)據(jù)庫的原子操作實(shí)現(xiàn)加鎖,而不是在代碼里分兩步查和更。

/**
 * 加鎖方法:通過數(shù)據(jù)庫UPDATE的原子性保證不會(huì)重復(fù)加鎖
 * @param loanId 借據(jù)ID
 * @param tradeCode 交易碼
 * @param serialNo 流水號(hào)
 * @return true=加鎖成功,false=已被鎖定
 */
public boolean lockLoanInvoice(String loanId, String tradeCode, String serialNo) {
    // 1. 先查詢當(dāng)前鎖信息(獲取舊版本號(hào))
    AssetLoanInvoiceLockInfoDo lockInfo = lockInfoMapper.selectByLoanId(loanId);
    if (lockInfo == null) {
        // 首次加鎖,初始化記錄
        lockInfo = new AssetLoanInvoiceLockInfoDo();
        lockInfo.setLoanId(loanId);
        lockInfo.setLockStatus("1");
        lockInfo.setLockSerialNo(serialNo);
        lockInfo.setLockTradeCode(tradeCode);
        lockInfo.setLockVersion(1);
        lockInfo.setLockTime(new Date());
        lockInfoMapper.insert(lockInfo);
        return true;
    }
    
    // 2. 原子更新:帶版本號(hào)+鎖狀態(tài)條件
    int updateCount = lockInfoMapper.updateLockStatus(
        loanId, 
        "0",          // 原狀態(tài):未鎖定
        lockInfo.getLockVersion(), // 原版本號(hào)
        "1",          // 新狀態(tài):鎖定
        serialNo,
        tradeCode,
        new Date()
    );
    
    // 3. 只有更新成功(影響行數(shù)=1),才代表加鎖成功
    return updateCount == 1;
}
<update id="updateLockStatus">
    UPDATE asset_loan_invoice_lock_info
    SET lock_status = #{newLockStatus},
        lock_serial_no = #{serialNo},
        lock_trade_code = #{tradeCode},
        lock_time = #{lockTime},
        lock_version = lock_version + 1,
        update_time = NOW()
    WHERE loan_id = #{loanId}
      AND lock_status = #{oldLockStatus}
      AND lock_version = #{oldVersion}
</update>

2. 輔助:增加 “鎖歸屬” 校驗(yàn)(防止誤解鎖 / 重復(fù)加鎖)

解鎖時(shí)必須校驗(yàn)lockSerialNo(只有加鎖的那個(gè)流水才能解鎖)

public boolean unlockLoanInvoice(String loanId, String serialNo) {
    int updateCount = lockInfoMapper.updateUnlockStatus(
        loanId,
        "1",          // 原狀態(tài):已鎖定
        serialNo,     // 必須是加鎖時(shí)的流水號(hào)
        "0"           // 新狀態(tài):未鎖定
    );
    return updateCount == 1;
}

3. 兜底:設(shè)置鎖超時(shí)機(jī)制(防止死鎖)

定時(shí)任務(wù)掃描超時(shí)的鎖,自動(dòng)解鎖:

/**
 * 定時(shí)任務(wù):解鎖超過30分鐘的借據(jù)鎖
 */
@Scheduled(fixedRate = 5 * 60 * 1000) // 每5分鐘執(zhí)行一次
public void unlockTimeoutLock() {
    // 計(jì)算超時(shí)時(shí)間:當(dāng)前時(shí)間 - 30分鐘
    Date timeoutTime = new Date(System.currentTimeMillis() - 30 * 60 * 1000);
    // 只解鎖超時(shí)且未解鎖的鎖
    lockInfoMapper.unlockTimeoutLock(timeoutTime);
}
<update id="unlockTimeoutLock">
    UPDATE asset_loan_invoice_lock_info
    SET lock_status = '0',
        lock_serial_no = '',
        lock_trade_code = '',
        lock_version = lock_version + 1,
        update_time = NOW()
    WHERE lock_status = '1'
      AND lock_time < #{timeoutTime}
</update>

只要保證 “加鎖操作是原子的、解鎖操作是可控的、異常情況有兜底的”,重復(fù)加鎖問題就能規(guī)避

總結(jié)

到此這篇關(guān)于基于Java開發(fā)借據(jù)鎖的文章就介紹到這了,更多相關(guān)Java借據(jù)鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java原生動(dòng)態(tài)生成驗(yàn)證碼

    java原生動(dòng)態(tài)生成驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了java原生動(dòng)態(tài)生成驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • FactoryBean的使用及底層工作原理分析

    FactoryBean的使用及底層工作原理分析

    FactoryBean接口解析與使用示例,詳解Spring框架中FactoryBean的作用和底層原理,以及如何通過FactoryBean實(shí)現(xiàn)對(duì)象的動(dòng)態(tài)創(chuàng)建is裝配is代理is包裝和生命周期管理
    2026-05-05
  • Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之線上水果超市商城的實(shí)現(xiàn)

    Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之線上水果超市商城的實(shí)現(xiàn)

    這是一個(gè)使用了java+SSM+springboot+redis開發(fā)的網(wǎng)上水果超市商城,是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有水果超市商城該有的所有功能,感興趣的朋友快來看看吧
    2022-01-01
  • MyBatis中SQL片段復(fù)用使用方法詳解

    MyBatis中SQL片段復(fù)用使用方法詳解

    在使用 MyBatis 進(jìn)行數(shù)據(jù)庫操作時(shí),常常會(huì)遇到一些 SQL 語句的部分內(nèi)容重復(fù)出現(xiàn)的情況,比如多個(gè)查詢語句都涉及相同的字段列表,這時(shí),MyBatis 的 SQL 片段復(fù)用功能就派上用場(chǎng)了,接下小編給大家介紹了MyBatis中SQL片段復(fù)用使用方法,需要的朋友可以參考下
    2024-12-12
  • 解決idea爆紅 cant resolve symbol String的問題解析

    解決idea爆紅 cant resolve symbol String的問題解析

    連著出差幾個(gè)禮拜沒有使用idea開發(fā)工具,突然一天打開電腦發(fā)現(xiàn)idea里的代碼全部爆紅,懵逼不如所措,很多朋友建議我按住Alt+回車設(shè)置jdk就能解決,但是仍然報(bào)錯(cuò),經(jīng)過幾個(gè)小時(shí)的倒騰最終解決,遇到此問題的朋友參考下本文吧
    2021-06-06
  • Android/Java中創(chuàng)建類實(shí)例的各種模式實(shí)例代碼

    Android/Java中創(chuàng)建類實(shí)例的各種模式實(shí)例代碼

    這篇文章主要介紹了Android/Java中創(chuàng)建類實(shí)例各種模式的相關(guān)資料,包括New關(guān)鍵字、靜態(tài)工廠方法、建造者模式、單例模式、依賴注入、抽象工廠模式、原型模式和Reflection,每個(gè)模式有其特點(diǎn)和適用場(chǎng)景,需要的朋友可以參考下
    2025-09-09
  • Java?代碼本地設(shè)置Hadoop用戶名密碼的方法

    Java?代碼本地設(shè)置Hadoop用戶名密碼的方法

    在Hadoop環(huán)境中,通常使用Kerberos進(jìn)行身份驗(yàn)證,這篇文章主要介紹了Java?代碼本地設(shè)置Hadoop用戶名密碼的方法,需要的朋友可以參考下
    2024-08-08
  • Hibernate中實(shí)現(xiàn)增刪改查的步驟詳解

    Hibernate中實(shí)現(xiàn)增刪改查的步驟詳解

    本篇文章主要介紹了Hibernate中實(shí)現(xiàn)增刪改查的步驟與方法,具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • 快速解決?IDEA?報(bào)錯(cuò):?“java?找不到符號(hào)“(“cannot?find?symbol“)

    快速解決?IDEA?報(bào)錯(cuò):?“java?找不到符號(hào)“(“cannot?find?symbol“)

    文章詳細(xì)講解了在IntelliJIDEA中解決“找不到符號(hào)”錯(cuò)誤的方法,包括檢查導(dǎo)入語句、拼寫錯(cuò)誤、類路徑設(shè)置、文件編譯狀態(tài)、JDK配置以及IDE配置問題,通過具體示例代碼,展示了如何從錯(cuò)誤代碼到解決步驟,感興趣的朋友一起看看吧
    2025-03-03
  • SpringBoot 單元測(cè)試實(shí)戰(zhàn)(Mockito,MockBean)

    SpringBoot 單元測(cè)試實(shí)戰(zhàn)(Mockito,MockBean)

    這篇文章主要介紹了SpringBoot 單元測(cè)試實(shí)戰(zhàn)(Mockito,MockBean),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09

最新評(píng)論

通城县| 嘉善县| 女性| 玉屏| 浦江县| 新蔡县| 天津市| 苗栗市| 包头市| 新沂市| 吴桥县| 府谷县| 贡山| 邯郸市| 泾川县| 睢宁县| 霸州市| 天柱县| 周宁县| 井陉县| 江油市| 商河县| 大港区| 安乡县| 平舆县| 南开区| 沾化县| 苏尼特左旗| 高平市| 卢氏县| 乌兰察布市| 青川县| 高台县| 湖北省| 荥经县| 丰宁| 怀化市| 浦东新区| 晴隆县| 临潭县| 宝坻区|