国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

mybatis使用樂觀鎖和悲觀鎖

這篇具有很好參考價值的文章主要介紹了mybatis使用樂觀鎖和悲觀鎖。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

悲觀鎖和樂觀鎖的概念:

悲觀鎖:就是獨占鎖,不管讀寫都上鎖了。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。Java中synchronized和ReentrantLock等獨占鎖就是悲觀鎖思想的實現(xiàn)。

樂觀鎖:不上鎖,讀取的時候帶版本號,寫入的時候帶著這個版本號,如果不一致就失敗,樂觀鎖適用于多讀的應用類型,因為寫多的時候會經(jīng)常失敗。

2.1 Maven依賴
需要引入spring-boot-starter-data-jpa,這里要訪問數(shù)據(jù)庫,所以要依賴數(shù)據(jù)庫相關(guān)jar包。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
        </dependency>

2.2 配置文件
在application.properties 中需要添加下面的配置:

spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.dbcp2.max-wait-millis=60000
spring.datasource.dbcp2.min-idle=20
spring.datasource.dbcp2.initial-size=2
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.connection-properties=characterEncoding=utf8
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.test-while-idle=true
spring.datasource.dbcp2.test-on-borrow=true
spring.datasource.dbcp2.test-on-return=false

spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=cff
spring.datasource.password=123456


mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

這里面,包含了數(shù)據(jù)庫連接信息、數(shù)據(jù)源的連接池配置信息、mybatis配置信息。

spring.datasource.dbcp2是配置dbcp2的連接池信息;
spring.datasource.type指明數(shù)據(jù)源的類型;
最上面的spring.datasource.xxx指明數(shù)據(jù)庫連接池信息;
mybatis.configuration.log-impl指明mybatis的日志打印方式
三、悲觀鎖
悲觀鎖在數(shù)據(jù)庫的訪問中使用,表現(xiàn)為:前一次請求沒執(zhí)行完,后面一個請求就一直在等待。

3.1 Dao層
數(shù)據(jù)庫要實現(xiàn)悲觀鎖,就是將sql語句帶上for update即可。 for update 是行鎖

所在mybatis的查詢sql加上for update,就實現(xiàn)了對當前記錄的鎖定,就實現(xiàn)了悲觀鎖。

UserInfoDao :

package com.cff.springbootwork.mybatislock.dao;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import cn.pomit.springwork.mybatislock.domain.UserInfo;

@Mapper
public interface UserInfoDao {

    @Select({
        "<script>",
            "SELECT ",
            "user_name as userName,passwd,name,mobile,valid, user_type as userType, version as version",
            "FROM user_info_test",
            "WHERE user_name = #{userName,jdbcType=VARCHAR} for update",
       "</script>"})
    UserInfo findByUserNameForUpdate(@Param("userName") String userName);

    @Update({
        "<script>",
        " update user_info_test set",
        " name = #{name, jdbcType=VARCHAR}, mobile = #{mobile, jdbcType=VARCHAR},version=version+1 ",
        " where user_name=#{userName}",
        "</script>"
    })
    int update(UserInfo userInfo);

    @Insert({
        "<script>",
        "INSERT INTO user_info_test",
        "( user_name,",
        "name ,",
        "mobile,",
        "passwd,",
        "version",
         ") ",
        " values ",
         "( #{userName},",
         "#{name},",
         "#{mobile},",
         "#{passwd},",
         "#{version}",
        " ) ",
        "</script>"
    })
    int save(UserInfo entity);
}

這里,findByUserNameForUpdate的sql中加上了for update。update就是普通的更新而已。

3.2 Service層
更新數(shù)據(jù)庫前,先調(diào)用findByUserNameForUpdate方法,使上面的配置的悲觀鎖鎖定表記錄,然后再更新。

UserInfoService :

package com.cff.springbootwork.mybatislock.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import cn.pomit.springwork.mybatislock.domain.UserInfo;
import cn.pomit.springwork.mybatislock.mapper.UserInfoDao;

@Service
public class UserInfoService {
    @Autowired
    UserInfoDao userInfoDao;

    public void save(UserInfo entity) {
        entity.setVersion(0);
        userInfoDao.save(entity);
    }


    @Transactional
    public UserInfo getUserInfoByUserNamePessimistic(String userName) {
        return userInfoDao.findByUserNameForUpdate(userName);
    }

    @Transactional
    public void updateWithTimePessimistic(UserInfo entity, int time) throws InterruptedException {      
        UserInfo userInfo = userInfoDao.findByUserNameForUpdate(entity.getUserName());
        if (userInfo == null)
            return;

        if (!StringUtils.isEmpty(entity.getMobile())) {
            userInfo.setMobile(entity.getMobile());
        }
        if (!StringUtils.isEmpty(entity.getName())) {
            userInfo.setName(entity.getName());
        }
        Thread.sleep(time * 1000L);

        userInfoDao.update(userInfo);
    }

    @Transactional
    public void updatePessimistic(UserInfo entity) {
        UserInfo userInfo = userInfoDao.findByUserNameForUpdate(entity.getUserName());
        if (userInfo == null)
            return;

        if (!StringUtils.isEmpty(entity.getMobile())) {
            userInfo.setMobile(entity.getMobile());
        }
        if (!StringUtils.isEmpty(entity.getName())) {
            userInfo.setName(entity.getName());
        }

        userInfoDao.update(userInfo);
    }

}

測試中,我們在update方法中sleep幾秒,其他線程的update將一直等待。

3.3 測試Web層
可以先調(diào)用/update/{time}接口,延遲執(zhí)行,然后馬上調(diào)用/update接口,會發(fā)現(xiàn),/update接口一直在等待/update/{time}接口執(zhí)行完成。

MybatisPessLockRest :

package com.cff.springbootwork.mybatislock.web;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import cn.pomit.springwork.mybatislock.domain.UserInfo;
import cn.pomit.springwork.mybatislock.service.UserInfoService;

/**
 * 測試悲觀鎖
 * 
 * @author fufei
 *
 */
@RestController
@RequestMapping("/mybatispesslock")
public class MybatisPessLockRest {

    @Autowired
    UserInfoService userInfoService;

    @RequestMapping(value = "/detail/{name}", method = { RequestMethod.GET })
    public UserInfo detail(@PathVariable("name") String name) {
        return userInfoService.getUserInfoByUserNamePessimistic(name);
    }

    @RequestMapping(value = "/save")
    public String save(@RequestBody UserInfo userInfo) throws InterruptedException {
        userInfoService.save(userInfo);
        return "0000";
    }

    @RequestMapping(value = "/update/{time}")
    public String update(@RequestBody UserInfo userInfo, @PathVariable("time") int time) throws InterruptedException {
        userInfoService.updateWithTimePessimistic(userInfo, time);

        return "0000";
    }

    @RequestMapping(value = "/update")
    public String update(@RequestBody UserInfo userInfo) throws InterruptedException {
        userInfoService.updatePessimistic(userInfo);
        return "0000";
    }
}

四、樂觀鎖
數(shù)據(jù)庫訪問dao層還是3.1那個UserInfoDao。

4.1 Dao層
UserInfoDao更新時,需要攜帶version字段進行更新:and version = #{version}。如果version不一致,是不會更新成功的,這時候,我們的select查詢是不能帶鎖的。

UserInfoDao :

package com.cff.springbootwork.mybatislock.dao;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import cn.pomit.springwork.mybatislock.domain.UserInfo;

@Mapper
public interface UserInfoDao {
    @Select({
        "<script>",
            "SELECT ",
            "user_name as userName,passwd,name,mobile,valid, user_type as userType, version as version",
            "FROM user_info_test",
            "WHERE user_name = #{userName,jdbcType=VARCHAR}",
       "</script>"})
    UserInfo findByUserName(@Param("userName") String userName);

    @Update({
        "<script>",
        " update user_info_test set",
        " name = #{name, jdbcType=VARCHAR}, mobile = #{mobile, jdbcType=VARCHAR},version=version+1 ",
        " where user_name=#{userName} and version = #{version}",
        "</script>"
    })
    int updateWithVersion(UserInfo userInfo);

    @Insert({
        "<script>",
        "INSERT INTO user_info_test",
        "( user_name,",
        "name ,",
        "mobile,",
        "passwd,",
        "version",
         ") ",
        " values ",
         "( #{userName},",
         "#{name},",
         "#{mobile},",
         "#{passwd},",
         "#{version}",
        " ) ",
        "</script>"
    })
    int save(UserInfo entity);
}

4.2 Service層
service層我們做一下簡單的調(diào)整。更新數(shù)據(jù)庫前,先調(diào)用findByUserName方法,查詢出當前的版本號,然后再更新。

UserInfoService :

package com.cff.springbootwork.mybatislock.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import cn.pomit.springwork.mybatislock.domain.UserInfo;
import cn.pomit.springwork.mybatislock.mapper.UserInfoDao;

@Service
public class UserInfoService {
    @Autowired
    UserInfoDao userInfoDao;
    public UserInfo getUserInfoByUserName(String userName){
        return userInfoDao.findByUserName(userName);
    }

    public void save(UserInfo entity) {
        entity.setVersion(0);
        userInfoDao.save(entity);
    }
    @Transactional
    public void updateWithTimeOptimistic(UserInfo entity, int time) throws Exception {      
        UserInfo userInfo = userInfoDao.findByUserName(entity.getUserName());
        if (userInfo == null)
            return;

        if (!StringUtils.isEmpty(entity.getMobile())) {
            userInfo.setMobile(entity.getMobile());
        }
        if (!StringUtils.isEmpty(entity.getName())) {
            userInfo.setName(entity.getName());
        }
        Thread.sleep(time * 1000L);

        int ret = userInfoDao.updateWithVersion(userInfo);
        if(ret < 1)throw new Exception("樂觀鎖導致保存失敗");
    }

    @Transactional
    public void updateOptimistic(UserInfo entity) throws Exception {
        UserInfo userInfo = userInfoDao.findByUserName(entity.getUserName());
        if (userInfo == null)
            return;

        if (!StringUtils.isEmpty(entity.getMobile())) {
            userInfo.setMobile(entity.getMobile());
        }
        if (!StringUtils.isEmpty(entity.getName())) {
            userInfo.setName(entity.getName());
        }

        int ret = userInfoDao.updateWithVersion(userInfo);
        if(ret < 1)throw new Exception("樂觀鎖導致保存失敗");
    }

}

4.2 測試Web層
可以先調(diào)用/update/{time}接口,延遲執(zhí)行,然后馬上調(diào)用/update接口,會發(fā)現(xiàn),/update接口不會等待/update/{time}接口執(zhí)行完成,讀取完版本號能夠成功更新數(shù)據(jù),但是/update/{time}接口等待足夠時間以后,更新的時候會失敗,因為它的版本和數(shù)據(jù)庫的已經(jīng)不一致了。

注意: 這里更新失敗不會拋異常,但是返回值會是0,即更新不成功,需要自行判斷。jpa的樂觀鎖可以拋出異常,手動catch到再自行處理。

MybatisOptiLockRest :文章來源地址http://www.zghlxwxcb.cn/news/detail-683254.html

package com.cff.springbootwork.mybatislock.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import cn.pomit.springwork.mybatislock.domain.UserInfo;
import cn.pomit.springwork.mybatislock.service.UserInfoService;

/**
 * 測試樂觀鎖
 * @author fufei
 *
 */
@RestController
@RequestMapping("/mybatislock")
public class MybatisOptiLockRest {

    @Autowired
    UserInfoService userInfoService;

    @RequestMapping(value = "/detail/{name}", method = { RequestMethod.GET })
    public UserInfo detail(@PathVariable("name") String name) {
        return userInfoService.getUserInfoByUserName(name);
    }

    @RequestMapping(value = "/save")
    public String save(@RequestBody UserInfo userInfo) throws InterruptedException {
        userInfoService.save(userInfo);
        return "0000";
    }

    @RequestMapping(value = "/update/{time}")
    public String update(@RequestBody UserInfo userInfo, @PathVariable("time") int time) throws Exception {
        userInfoService.updateWithTimeOptimistic(userInfo, time);

        return "0000";
    }

    @RequestMapping(value = "/update")
    public String update(@RequestBody UserInfo userInfo) throws Exception {
        userInfoService.updateOptimistic(userInfo);
        return "0000";
    }
}

到了這里,關(guān)于mybatis使用樂觀鎖和悲觀鎖的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • MySQL樂觀鎖與悲觀鎖

    遇見并發(fā)情況,需要保證數(shù)據(jù)的準確性,也就是與正確的預期一致,此時就會用到鎖。 鎖是在并發(fā)下控制程序的執(zhí)行邏輯,以此來保證數(shù)據(jù)按照預期變動。 如果不加鎖,并發(fā)情況下的可能數(shù)據(jù)不一致的情況,這是個概率問題。 樂觀鎖很樂觀,假設(shè)數(shù)據(jù)一般情況不會造成沖突

    2024年01月23日
    瀏覽(21)
  • JavaEE 初階篇-深入了解 CAS 機制與12種鎖的特征(如樂觀鎖和悲觀鎖、輕量級鎖與重量級鎖、自旋鎖與掛起等待鎖、可重入鎖與不可重入鎖等等)

    JavaEE 初階篇-深入了解 CAS 機制與12種鎖的特征(如樂觀鎖和悲觀鎖、輕量級鎖與重量級鎖、自旋鎖與掛起等待鎖、可重入鎖與不可重入鎖等等)

    ??博客主頁:?【 小扳_-CSDN博客】 ?感謝大家點贊??收藏?評論? 文章目錄 ? ? ? ? 1.0 樂觀鎖與悲觀鎖概述 ? ? ? ? 1.1 悲觀鎖(Pessimistic Locking) ? ? ? ? 1.2 樂觀鎖(Optimistic Locking) ? ? ? ? 1.3 區(qū)別與適用場景 ? ? ? ? 2.0 輕量級鎖與重量級鎖概述 ? ? ? ? 2.1 真正加

    2024年04月16日
    瀏覽(41)
  • Mysql--技術(shù)文檔--悲觀鎖、樂觀鎖-《控制并發(fā)機制簡單認知、深度理解》

    ????????首先在談到并發(fā)控制機制的時候,我們通常會提及兩種重要的鎖策略。悲觀鎖(Pessimistic Locking)和樂觀鎖(Optimistic Locking)。這兩個是在處理并發(fā)的時候采取的不同思路。 ????????悲觀鎖: 悲觀鎖機制認為并發(fā)操作中會有沖突,因此默認情況下假設(shè)會出現(xiàn)并

    2024年02月10日
    瀏覽(24)
  • 悲觀鎖&樂觀鎖

    1.悲觀鎖 悲觀鎖介紹(百科): 悲觀鎖,正如其名,它指的是對數(shù)據(jù)被外界(包括本系統(tǒng)當前的其他事務,以及來自外部系統(tǒng)的事務處理)修改持保守態(tài)度,因此,在整個數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機制(也只有數(shù)據(jù)庫層

    2024年02月08日
    瀏覽(25)
  • django實現(xiàn)悲觀鎖樂觀鎖

    前期準備 1.原生mysql悲觀鎖 2.orm實現(xiàn)上述(悲觀鎖)? 3 樂觀鎖秒殺--》庫存還有,有的人就沒成功 ?

    2024年02月12日
    瀏覽(26)
  • [鎖]:樂觀鎖與悲觀鎖

    摘要:樂觀鎖;悲觀鎖;實現(xiàn)方法;本地鎖;分布式鎖;死鎖;行級鎖;表級鎖 問題 : ① 在多個線程訪問共享資源時,會發(fā)生線程安全問題,例如:在根據(jù)訂單號生成訂單時,若用戶第一次由于某種原因(網(wǎng)絡連接不穩(wěn)定)請求失敗,則會再次發(fā)生請求,此時便會產(chǎn)生同一

    2024年02月08日
    瀏覽(18)
  • [鎖]:樂觀鎖、悲觀鎖與死鎖

    摘要:樂觀鎖;悲觀鎖;實現(xiàn)方法;本地鎖;分布式鎖;死鎖;行級鎖;表級鎖 問題 : ① 在多個線程訪問共享資源時,會發(fā)生線程安全問題,例如:在根據(jù)訂單號生成訂單時,若用戶第一次由于某種原因(網(wǎng)絡連接不穩(wěn)定)請求失敗,則會再次發(fā)生請求,此時便會產(chǎn)生同一

    2024年02月08日
    瀏覽(23)
  • redis實戰(zhàn)---樂觀鎖與悲觀鎖

    最近一直在研究Redis,今天學習到了樂觀鎖與悲觀鎖的部分,在這里進行總結(jié)。 Redis是一個內(nèi)存中的鍵值存儲系統(tǒng),支持多種數(shù)據(jù)結(jié)構(gòu),如字符串、哈希、列表等。 Redis提供了兩種鎖機制,即樂觀鎖和悲觀鎖。 樂觀鎖是一種樂觀的并發(fā)控制策略,它認為數(shù)據(jù)在大多數(shù)情況下

    2023年04月09日
    瀏覽(21)
  • Java并發(fā)(十四)----悲觀互斥與樂觀重試

    1. 悲觀互斥 互斥實際是悲觀鎖的思想 例如,有下面取款的需求 用互斥來保護 2. 樂觀重試 另外一種是樂觀鎖思想,它其實不是互斥

    2024年02月15日
    瀏覽(24)
  • (學習筆記-進程管理)什么是悲觀鎖、樂觀鎖?

    (學習筆記-進程管理)什么是悲觀鎖、樂觀鎖?

    最底層的兩種就是 [互斥鎖和自旋鎖],有很多高級的鎖都是基于它們實現(xiàn)的??梢哉J為它們是各種鎖的地基,所以我們必須清楚它們之間的區(qū)別和應用。 加鎖的目的就是保證共享資源在任意時間內(nèi),只有一個線程訪問,這樣就可以避免多線程導致共享數(shù)據(jù)錯亂的問題。 當已

    2024年02月11日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包