SSM (十五) 乐观锁与悲观锁的实际应用(下)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 随着互联网的兴起,现在三高(高可用、高性能、高并发)项目是越来越流行。 本次来谈谈高并发。首先假设一个业务场景:数据库中有一条数据,需要获取到当前的值,在当前值的基础上+10,然后再更新回去。

悲观锁


简单理解下悲观锁:当一个事务锁定了一些数据之后,只有当当前锁提交了事务,释放了锁,其他事务才能获得锁并执行操作。


使用方式如下:


首先要关闭MySQL的自动提交:set autocommit = 0;


bigen --开启事务
select id, total, front, end from price where id=1 for update 
insert into price values(?,?,?,?,?)
commit --提交事务


这里使用select for update的方式利用数据库开启了悲观锁,锁定了id=1的这条数据(注意:这里除非是使用了索引会启用行级锁,不然是会使用表锁,将整张表都锁住。)。之后使用commit提交事务并释放锁,这样下一个线程过来拿到的就是正确的数据。


悲观锁一般是用于并发不是很高,并且不允许脏读等情况。但是对数据库资源消耗较大。


乐观锁


那么有没有性能好,支持的并发也更多的方式呢?


那就是乐观锁。


乐观锁是首先假设数据冲突很少,只有在数据提交修改的时候才进行校验,如果冲突了则不会进行更新。


通常的实现方式增加一个version字段,为每一条数据加上版本。每次更新的时候version+1,并且更新时候带上版本号。实现方式如下:


新建了一张price_version表:


CREATE TABLE `price_version` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `total` decimal(12,2) DEFAULT '0.00' COMMENT '总值',
  `front` decimal(12,2) DEFAULT '0.00' COMMENT '消费前',
  `end` decimal(12,2) DEFAULT '0.00' COMMENT '消费后',
  `version` int(11) DEFAULT '0' COMMENT '并发版本控制',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1268 DEFAULT CHARSET=utf8


更新数据的SQL:


<update id="updateByVersion" parameterType="com.crossoverJie.pojo.PriceVersion">
    UPDATE price_version
    SET front = #{front,jdbcType=DECIMAL},
        version= version + 1
    WHERE id = #{id,jdbcType=INTEGER}
    AND version = #{version,jdbcType=INTEGER}
  </update>


调用方式:


/**
     * 线程池,乐观锁
     * @param redisContentReq
     * @return
     */
    @RequestMapping(value = "/threadPriceVersion",method = RequestMethod.POST)
    @ResponseBody
    public BaseResponse<NULLBody> threadPriceVersion(@RequestBody RedisContentReq redisContentReq){
        BaseResponse<NULLBody> response = new BaseResponse<NULLBody>() ;
        try {
            for (int i=0 ;i<3 ;i++){
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        PriceVersion priceVersion = priceVersionMapper.selectByPrimaryKey(1);
                        int ron = new Random().nextInt(20);
                        logger.info("本次消费="+ron);
                        priceVersion.setFront(new BigDecimal(ron));
                        int count = priceVersionMapper.updateByVersion(priceVersion);
                        if (count == 0){
                            logger.error("更新失败");
                        }else {
                            logger.info("更新成功");
                        }
                    }
                });
                config.submit(t);
            }
            response.setReqNo(redisContentReq.getReqNo());
            response.setCode(StatusEnum.SUCCESS.getCode());
            response.setMessage(StatusEnum.SUCCESS.getMessage());
        }catch (Exception e){
            logger.error("system error",e);
            response.setReqNo(response.getReqNo());
            response.setCode(StatusEnum.FAIL.getCode());
            response.setMessage(StatusEnum.FAIL.getMessage());
        }
        return response ;
    }


处理逻辑:开了三个线程生成了20以内的随机数更新到front字段。


当调用该接口时日志如下:


03.jpg


可以看到线程1、4、5分别生成了15,2,11三个随机数。最后线程4、5都更新失败了,只有线程1更新成功了。


查看数据库:


04.jpg


发现也确实是更新的15。


乐观锁在实际应用相对较多,它可以提供更好的并发访问,并且数据库开销较少,但是有可能存在脏读的情况。


总结


以上两种各有优劣,大家可以根据具体的业务场景来判断具体使用哪种方式来保证数据的一致性。


项目地址:github.com/crossoverJi…

个人博客地址:crossoverjie.top


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
5月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的代驾应用系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的代驾应用系统附带文章和源代码部署视频讲解等
201 21
|
5月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的服装品牌的推广及应用网站附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的服装品牌的推广及应用网站附带文章和源代码部署视频讲解等
50 4
|
5月前
|
Java 测试技术 数据安全/隐私保护
基于ssm+vue.js+uniapp小程序的《数据库原理及应用》课程平台附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的《数据库原理及应用》课程平台附带文章和源代码部署视频讲解等
38 0
基于ssm+vue.js+uniapp小程序的《数据库原理及应用》课程平台附带文章和源代码部署视频讲解等
|
6月前
|
JavaScript Java 测试技术
基于ssm+vue.js的绿色农产品推广应用网站附带文章和源代码设计说明文档ppt
基于ssm+vue.js的绿色农产品推广应用网站附带文章和源代码设计说明文档ppt
59 4
|
消息中间件 监控 Kafka
SSM(十七) MQ应用(下)
写这篇文章的起因是由于之前的一篇关于Kafka异常消费,当时为了解决问题不得不使用临时的方案。 总结起来归根结底还是对Kafka不熟悉导致的,加上平时工作的需要,之后就花些时间看了Kafka相关的资料。
|
消息中间件 Kafka API
SSM(十七) MQ应用(中)
写这篇文章的起因是由于之前的一篇关于Kafka异常消费,当时为了解决问题不得不使用临时的方案。 总结起来归根结底还是对Kafka不熟悉导致的,加上平时工作的需要,之后就花些时间看了Kafka相关的资料。
|
消息中间件 算法 Java
SSM(十七) MQ应用(上)
写这篇文章的起因是由于之前的一篇关于Kafka异常消费,当时为了解决问题不得不使用临时的方案。 总结起来归根结底还是对Kafka不熟悉导致的,加上平时工作的需要,之后就花些时间看了Kafka相关的资料。
|
Java 数据库
SSM (十五) 乐观锁与悲观锁的实际应用(上)
随着互联网的兴起,现在三高(高可用、高性能、高并发)项目是越来越流行。 本次来谈谈高并发。首先假设一个业务场景:数据库中有一条数据,需要获取到当前的值,在当前值的基础上+10,然后再更新回去。
|
缓存 Java 数据库连接
SSM(九) 反射的实际应用 - 构建日志对象
相信做Java的童鞋或多或少都听过反射,这也应该是Java从入门到进阶的必经之路。 但是在我们的实际开发中直接使用它们的几率貌似还是比较少的,(除了造轮子或者是Spring Mybatis这些框架外)。 所以这里介绍一个在实际开发中还是小有用处的反射实例。
|
3月前
|
Java 数据库连接 Maven
手把手教你如何搭建SSM框架、图书商城系统案例
这篇文章是关于如何搭建SSM框架以及实现一个图书商城系统的详细教程,包括了项目的配置文件整合、依赖管理、项目结构和运行效果展示,并提供了GitHub源码链接。
手把手教你如何搭建SSM框架、图书商城系统案例