当前位置: 首页 > news >正文

开发项目时遇到的横向越权、行锁表锁与事务的关联与区别、超卖问题

横向越权

横向越权指的是 用户A存储了相应信息在数据库, 假设此时用户B获得了用户A的主键(或者其他可查询行数据的信息),在我们不加以防护的情况下,用户B对A存储的对应内容进行修改,这就是横向越权。

在本章节对横向越权进行了防护,防护规则也很简单,就是进行鉴权。

通过对ThreadLocal中的用户信息与数据库中创建者的对应信息进行比对,从而鉴权。这样的鉴权,使得相应的修改操作,只能由创建者本人完成。

mysql数据库的排他锁

数据库的单条增删改是并发安全的,这是由于innodb底层实现的排他锁决定的。innodb引擎保证了在进行增删改时其他线程拿不到改行数据。

也就是说排他锁是一个行级锁。

那么既然mysql有了行级锁,为什么还需要使用事务?

原因很简单,单条语句的并发安全不代表多条语句的执行是并发安全的,事务的出现就是为了保证多条sql语句的原子性,从而实现多条语句的逻辑无差错。

为什么有了排他锁还会在电商系统中出现超卖?

电商系统中,多个并发线程来对数据库进行读写,如果此时读写是分离的状态,那么此时会出现超卖。

因为排他锁并不会对读上锁,而只会对增删改进行上锁。

那么如果业务逻辑为:

假设初始 stock = 1,有三条并发请求(线程 A、B、C):

sql复制编辑
-- 线程 A
SELECT stock FROM product WHERE id=100;  -- 读到 1-- 线程 B
SELECT stock FROM product WHERE id=100;  -- 也读到 1-- 线程 C
SELECT stock FROM product WHERE id=100;  -- 也读到 1-- 接着它们分别判断 stock>0,都成立
-- 然后各自执行:
UPDATE product SET stock = stock - 1 WHERE id=100;

所以,导致电商超卖的原因实质上是事务的不一致性,在读写分离时需要添加事务,或者使用同步读写、乐观锁来进行解决。

比如将上述sql语句修改为读写同步:

UPDATE productSET stock = stock - 1WHERE id = 100AND stock > 0;

这样一条sql语句实质上是具备排他锁的,所以不会出现并发安全问题。

为什么innodb已经有了行级锁,还需要表锁?

行级锁与表锁并不矛盾,在并发性高的表中,需要使用到行级锁,因为颗粒更细,能够提升整体表的读写效率。但是由于行锁的开销更高: 需要管理锁链、索引定位、MVCC 等 ,所以尽量在并发高的热点表中进行手动添加。

那么显然由于行锁的消耗高,所以表锁对于并发量不高,但又需要保证并发安全的表,就可以使用表锁,表锁的颗粒更大,但是表锁是一个轻量级锁,开销更小。

除此之外,表锁在DDL中具有必要性,因为DDL语言对表的结构进行修改,此时需要对整个表进行上锁,避免出现脏数据。

什么是乐观锁,乐观锁为什么能够解决超卖问题?

首先需要明确,乐观锁可以是锁,也可以是一种思想。

乐观锁的思想是,仅在非读操作的情况下进行检测加锁。也就是

” 先不加锁,假设不会发生冲突;在写入前检测是否有冲突,若检测到冲突则重试或报错 “

对应的悲观锁思想就是在操作之前进行上锁。

比如在解决超卖问题,读写分离时可以新建一个version列:

进行读:读出当前version

进行写:判断写时的version是否是读时的version,如果不是,则重试或者报错。

刚才的sql语句进行改写,就能得到乐观锁对应的语句:

读:SELECT stockFROM productWHERE id = 100;写:UPDATE productSET stock = stock - 1WHERE id = 100AND stock = #{oldStock};

http://www.lryc.cn/news/581639.html

相关文章:

  • Java学习——Lombok
  • Anaconda 常用命令
  • 【Elasticsearch】自定义评分检索
  • 【卫星语音】基于神经网络的低码率语音编解码(ULBC)方案架构分析:以SoundStream为例
  • Maven引入第三方JAR包实战指南
  • Day06- (使用asyncio进行异步编程:事件循环和协程)
  • 群晖 DS3617xs DSM 6.1.7 解决 PhotoStation 安装失败问题 PHP7.0
  • 数据结构---B+树
  • Modbus 与 BACnet 协议互操作:工业协议转换方案(二)
  • 深入理解 classnames:React 动态类名管理的最佳实践
  • 【系统分析师】2023年真题:论文及解题思路
  • 【机器学习笔记Ⅰ】7 向量化
  • 【IOS】XCode创建firstapp并运行(成为IOS开发者)
  • Tuning Language Models by Proxy
  • CentOS-6与CentOS-7的网络配置IP设置方式对比 笔记250706
  • 【Vibe Coding 实战】我如何用 AI 把一张草图变成了能跑的应用
  • 黑马点评系列问题之基础篇16jedis redis依赖引入后仍然还是报错
  • Docker 容器编排原理与使用详解
  • 国内Ubuntu访问不了github等外网
  • 牛客周赛Round 99(Go语言)
  • 【前端工程化】前端工作中的业务规范有哪些
  • 4.2 如何训练⼀个 LLM
  • Redis主从切换踩坑记:当Redisson遇上分布式锁的“死亡连接“
  • 鼓式制动器的设计+(说明书和CAD【6张】 - 副本➕降重
  • ClickHouse 全生命周期性能优化
  • Linux内核(一)
  • 【unity小技巧】在 Unity 中将 2D 精灵添加到 3D 游戏中,并实现阴影投射效果,实现类《八分旅人》《饥荒》等等的2.5D游戏效果
  • [leetcode] C++ 并查集模板
  • SQL 一键转 GORM 模型,支持字段注释、类型映射、tag 自定义!
  • D435i + ROS2