广告
返回顶部
首页 > 资讯 > 操作系统 >mybatis使用乐观锁和悲观锁
  • 222
分享到

mybatis使用乐观锁和悲观锁

mysql 2023-08-30 15:08:58 222人浏览 薄情痞子
摘要

悲观锁和乐观锁的概念: 悲观锁:就是独占锁,不管读写都上锁了。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲

悲观和乐观锁的概念:

悲观锁:就是独占锁,不管读写都上锁了。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

乐观锁:不上锁,读取的时候带版本号,写入的时候带着这个版本号,如果不一致就失败,乐观锁适用于多读的应用类型,因为写多的时候会经常失败。

1 Maven依赖
需要引入spring-boot-starter-data-jpa,这里要访问数据库,所以要依赖数据库相关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 配置文件
在application.properties 中需要添加下面的配置:

spring.datasource.type=org.apache.commons.dbcp2.BasicDataSourcespring.datasource.dbcp2.max-wait-millis=60000spring.datasource.dbcp2.min-idle=20spring.datasource.dbcp2.initial-size=2spring.datasource.dbcp2.validation-query=SELECT 1spring.datasource.dbcp2.connection-properties=characterEncoding=utf8spring.datasource.dbcp2.validation-query=SELECT 1spring.datasource.dbcp2.test-while-idle=truespring.datasource.dbcp2.test-on-borrow=truespring.datasource.dbcp2.test-on-return=falsespring.datasource.driverClassName = com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTCspring.datasource.username=cffspring.datasource.passWord=123456mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

这里面,包含了数据库连接信息、数据源的连接池配置信息、mybatis配置信息。

spring.datasource.dbcp2是配置dbcp2的连接池信息;
spring.datasource.type指明数据源的类型;
最上面的spring.datasource.xxx指明数据库连接池信息;
mybatis.configuration.log-impl指明mybatis的日志打印方式
三、悲观锁
悲观锁在数据库的访问中使用,表现为:前一次请求没执行完,后面一个请求就一直在等待。

1 Dao层
数据库要实现悲观锁,就是将sql语句带上for update即可。 for update 是行锁

所在mybatis的查询sql加上for update,就实现了对当前记录的锁定,就实现了悲观锁。

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;@Mapperpublic interface UserInfoDao {    @Select({        ""})    UserInfo findByUserNameForUpdate(@Param("userName") String userName);    @Update({        ""    })    int update(UserInfo userInfo);    @Insert({        ""    })    int save(UserInfo entity);}

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

2 Service层
更新数据库前,先调用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;@Servicepublic 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 测试Web层
可以先调用/update/{time}接口,延迟执行,然后马上调用/update接口,会发现,/update接口一直在等待/update/{time}接口执行完成。

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;@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";    }}

四、乐观锁
数据库访问dao层还是3.1那个UserInfoDao。

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;@Mapperpublic interface UserInfoDao {    @Select({        ""})    UserInfo findByUserName(@Param("userName") String userName);    @Update({        ""    })    int updateWithVersion(UserInfo userInfo);    @Insert({        ""    })    int save(UserInfo entity);}

2 Service层
service层我们做一下简单的调整。更新数据库前,先调用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;@Servicepublic 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("乐观锁导致保存失败");    }}

2 测试Web层
可以先调用/update/{time}接口,延迟执行,然后马上调用/update接口,会发现,/update接口不会等待/update/{time}接口执行完成,读取完版本号能够成功更新数据,但是/update/{time}接口等待足够时间以后,更新的时候会失败,因为它的版本和数据库的已经不一致了。

注意: 这里更新失败不会抛异常,但是返回值会是0,即更新不成功,需要自行判断。jpa的乐观锁可以抛出异常,手动catch到再自行处理。

MybatisOptiLockRest :

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;@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";    }}

来源地址:https://blog.csdn.net/qq_43459184/article/details/132582876

--结束END--

本文标题: mybatis使用乐观锁和悲观锁

本文链接: https://www.lsjlt.com/news/383171.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • mybatis使用乐观锁和悲观锁
    悲观锁和乐观锁的概念: 悲观锁:就是独占锁,不管读写都上锁了。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲...
    99+
    2023-08-30
    mysql
  • mysql 乐观锁和悲观锁
    悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中, 将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层...
    99+
    2023-09-02
    mysql 数据库 java
  • 什么是悲观锁和乐观锁
    什么是悲观锁和乐观锁?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 悲观锁(Pessimistic Lock), 顾...
    99+
    2022-10-18
  • MySQL乐观锁和悲观锁介绍
    乐观锁 乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去...
    99+
    2022-10-18
  • 悲观锁和乐观锁是什么
    悲观锁和乐观锁是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。乐观锁( Optimistic Locking )乐观锁( ...
    99+
    2022-10-18
  • 悲观锁,乐观锁的概念
    悲观锁:顾名思义,就是很悲观,它指的是对数据被外界(包括本系统当前的其他事务,以及来自其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁实现,往往依...
    99+
    2022-10-18
  • mysql中如何使用乐观锁和悲观锁
    MySQL中可以使用SELECT ... FOR UPDATE语句来实现悲观锁。这个语句会在查询时锁定被查询的行,在事务结束前都不会释放锁。 例如,我们可以使用以下的 SQL 语句来锁定一个特定的行: ``` BEGIN; SELE...
    99+
    2023-09-18
    mysql
  • mysql 乐观锁和悲观锁的具体使用
    目录悲观锁介绍(百科):1如果不采用锁,那么操作方法如下:2使用悲观锁来实现:补充:MySQL select…for update的Row Lock与Tabl...
    99+
    2023-01-08
    mysql 乐观锁和悲观锁 mysql 乐观锁 mysql 悲观锁
  • mysql 乐观锁和悲观锁的具体使用
    目录悲观锁介绍(百科):1如果不采用锁,那么操作方法如下:2使用悲观锁来实现:补充:mysql select…for update的Row Lock与Table Lock乐观锁介绍:使用举例:以M...
    99+
    2023-01-09
    mysql 乐观锁和悲观锁 mysql 乐观锁 mysql 悲观锁
  • 什么是乐观锁、悲观锁和MVCC
    本篇内容主要讲解“什么是乐观锁、悲观锁和MVCC”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“什么是乐观锁、悲观锁和MVCC”吧!在数据库的实际使用过程中,我们...
    99+
    2022-10-18
  • redis乐观锁与悲观锁怎么使用
    本篇内容主要讲解“redis乐观锁与悲观锁怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“redis乐观锁与悲观锁怎么使用”吧!概念Redis是一个内存中的键值存储系统,支持多种数据结构,...
    99+
    2023-07-06
  • MySQL中的悲观锁与乐观锁
    在关系型数据库中,悲观锁与乐观锁是解决资源并发场景的解决方案,接下来将详细讲解🔎一下这两个并发解决方案的实际使用及优缺点。 首先定义一下数据库,做一个最简单的库存表,如下设计: CREATE TA...
    99+
    2022-05-15
    MySQL 悲观锁 MySQL 乐观锁
  • MySQL乐观锁和悲观锁具体实现
    目录前言锁分类表结构悲观锁乐观锁适用场景总结前言 对于mysql中的乐观锁和悲观锁,可能很多的开发者还不是很熟悉,并不知道其中具体是如何实现的。本文就针对这个问题做一个实际案例演示,让你彻底明白这两种锁的区别。 锁分类 ...
    99+
    2022-09-05
  • MySQL中乐观锁和悲观锁是什么
    这篇文章给大家分享的是有关MySQL中乐观锁和悲观锁是什么的内容。小编觉得挺实用的,因此分享给大家做个参考。一起跟随小编过来看看吧。数据库管理系统中并发控制的任务是确保在多个事务同时存取数据库中同一数据不破...
    99+
    2022-10-18
  • MySQL乐观锁和悲观锁如何实现
    这篇文章主要介绍了MySQL乐观锁和悲观锁如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇MySQL乐观锁和悲观锁如何实现文章都会有所收获,下面我们一起来看看吧。 ...
    99+
    2022-10-19
  • MySQL中乐观锁和悲观锁的区别
    这篇文章将为大家详细讲解有关MySQL中乐观锁和悲观锁的区别,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。悲观锁在关系数据库管理系统中,悲观并发控制(悲观锁...
    99+
    2022-10-18
  • 合理的使用MySQL乐观锁与悲观锁
    针对 MySQL的乐观锁与悲观锁的使用,基本都是按照业务场景针对性使用的。针对每个业务场景,对应的使用锁。 但是两种锁无非都是解决并发所产生的问题。下面我们来看看如何合理的使用乐观锁与悲观锁   何为悲观锁 悲观锁(Pessi...
    99+
    2015-02-12
    合理的使用MySQL乐观锁与悲观锁
  • redis乐观锁与悲观锁的实战
    目录概念乐观锁悲观锁乐观锁示例悲观锁示例总结提升概念 Redis是一个内存中的键值存储系统,支持多种数据结构,如字符串、哈希、列表等。Redis提供了两种锁机制,即乐观锁和悲观锁。 乐观锁 乐观锁是一种乐观的并发控制策略...
    99+
    2023-04-13
    redis 乐观锁 悲观锁 redis 乐观锁 redis 悲观锁
  • mysql乐观锁和悲观锁有什么区别
    本篇内容主要讲解“mysql乐观锁和悲观锁有什么区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mysql乐观锁和悲观锁有什么区别”吧! ...
    99+
    2022-10-18
  • Java悲观锁和乐观锁机制是什么
    本篇内容主要讲解“Java悲观锁和乐观锁机制是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java悲观锁和乐观锁机制是什么”吧!1、锁机制简介并发编程中一个最关键的问题,多线程并发处理同一...
    99+
    2023-06-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作