SpringBoot入门建站全系列(二十一)Mybatis使用乐观锁与悲观锁
一、概述
之前有两篇《SpringBoot入门建站全系列(三)Mybatis操作数据库》和《SpringBoot入门建站全系列(四)Mybatis使用进阶篇:动态SQL与分页》介绍了Springboot如何结合Mybatis进行数据库访问操作。这一篇介绍下springboot环境下Mybatis如何进行乐观锁、悲观锁的使用。
悲观锁和乐观锁的概念:
- 悲观锁:就是独占锁,不管读写都上锁了。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
- 乐观锁:不上锁,读取的时候带版本号,写入的时候带着这个版本号,如果不一致就失败,乐观锁适用于多读的应用类型,因为写多的时候会经常失败。
代码可以在Springboot组件化构建https://www.pomit.cn/java/spring/springboot.html中的MybatisLock组件中查看,并下载。
首发地址:
品茗IT-同步发布
如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。
二、配置
本文假设你已经引入spring-boot-starter-web。已经是个SpringBoot项目了,如果不会搭建,可以打开这篇文章看一看《SpringBoot入门建站全系列(一)项目建立》。
2.1 Maven依赖
需要引入spring-boot-starter-data-jpa,这里要访问数据库,所以要依赖数据库相关jar包。
<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=falsespring.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=123456mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
这里面,包含了数据库连接信息、数据源的连接池配置信息、mybatis配置信息。
- spring.datasource.dbcp2是配置dbcp2的连接池信息;
- spring.datasource.type指明数据源的类型;
- 最上面的http://spring.datasource.xxx指明数据库连接池信息;
- mybatis.configuration.log-impl指明mybatis的日志打印方式
三、悲观锁
悲观锁在数据库的访问中使用,表现为:前一次请求没执行完,后面一个请求就一直在等待。
3.1 Dao层
数据库要实现悲观锁,就是将sql语句带上for update即可。 for update 是行锁
所在mybatis的查询sql加上for update,就实现了对当前记录的锁定,就实现了悲观锁。
UserInfoDao :
package
这里,findByUserNameForUpdate的sql中加上了for update。update就是普通的更新而已。
3.2 Service层
更新数据库前,先调用findByUserNameForUpdate方法,使上面的配置的悲观锁锁定表记录,然后再更新。
UserInfoService :
package
测试中,我们在update方法中sleep几秒,其他线程的update将一直等待。
3.3 测试Web层
可以先调用/update/{time}接口,延迟执行,然后马上调用/update接口,会发现,/update接口一直在等待/update/{time}接口执行完成。
MybatisPessLockRest :
package
四、乐观锁
数据库访问dao层还是3.1那个UserInfoDao。
4.1 Dao层
UserInfoDao更新时,需要携带version字段进行更新:and version = #{version}。如果version不一致,是不会更新成功的,这时候,我们的select查询是不能带锁的。
UserInfoDao :
package
4.2 Service层
service层我们做一下简单的调整。更新数据库前,先调用findByUserName方法,查询出当前的版本号,然后再更新。
UserInfoService :
package
4.2 测试Web层
可以先调用/update/{time}接口,延迟执行,然后马上调用/update接口,会发现,/update接口不会等待/update/{time}接口执行完成,读取完版本号能够成功更新数据,但是/update/{time}接口等待足够时间以后,更新的时候会失败,因为它的版本和数据库的已经不一致了。
注意: 这里更新失败不会抛异常,但是返回值会是0,即更新不成功,需要自行判断。jpa的乐观锁可以抛出异常,手动catch到再自行处理。
MybatisOptiLockRest :
package
五、过程中用到的完整实体和Service
UserInfo:
UserInfoService :
UserInfoDao:
详细完整的实体及代码,可以访问品茗IT-博客《SpringBoot入门建站全系列(二十一)Mybatis使用乐观锁与悲观锁》进行查看
品茗IT-博客专题:https://www.pomit.cn/lecture.html汇总了Spring专题、Springboot专题、SpringCloud专题、web基础配置专题。
快速构建项目
Spring组件化构建
SpringBoot组件化构建
SpringCloud服务化构建
喜欢这篇文章么,喜欢就加入我们一起讨论SpringBoot使用吧!