mysql中更新锁运用

  1. 业务场景描述

用户表(user) 用户编号 user_id 资金字段  fund
资金明细表(fund_record) 用户编号字段 user_id 更新前资金 before_fund  更新后资金after_fund 消费额度out_fund 增加额度in_fund
需求:在消费用户资金时,记录资金变动记录到明细表
方案:将更新用户表,添加明细表操作,加入同一事务。加事务级别排他锁,事务完毕释放锁。
  1. sql实现细节简写

用户表:update user set fund=fund-额度 where user_id=用户编号 and fund-额度>=0
明细表:简单插入略(事务过程中有计算流程)。
执行顺序:先update,若成功,查询计算,再添加记录。update不成功,不做后续操作
  1. 执行结果

100线程并发,单次额度1,用户更新后,延时1秒执行明细添加。最终数据无错误,数据库锁超时。成功执行48条。
  1. 猜测分析

update 语句添加排他锁,且是事务级别排他锁。所有线程到update处,执行模式转换为串行,所以在当前线程执行完毕前,其他线程被挂起。最终结果,既保证了用户资金更新正确,又保证了明细数据先入先出,资金记录不乱
好吧,添加下反思,上述实验,结果是错误的,对于单条具体记录,单数据库的情况下,update其实是分布式排他锁,但是无法保证资金明细记录不乱,因为时间上是乱序的,之所以正确,是因为只有一台机器访问数据库,如果是多台,明细在多台并发的情况下录入的数据肯定会出现错误数据,原因是读到其他机器更新后的结果,而不是自己更新后的结果。其实用线程模拟多台机器,思路好像没啥问题,但是这种并发的问题,本来就是非必发事件,我猜测是我当时实验数据太小,或者运气太好导致,这并不是真相。对应这种可能出现的并发错误,我现在的解决方案,是在事务入口加redis分布式锁,锁没被释放,那就拉倒,全部失败,这粗暴,但是好用。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java 项目使用 MySQL 悲观主要是通过 SQL 语句的 `SELECT ... FOR UPDATE` 或 `SELECT ... LOCK IN SHARE MODE` 实现的。 `SELECT ... FOR UPDATE` 语句会对查询结果的每一行加上排它(Exclusive Lock),其它事务无法对这些行进行修改或者加排它,直到当前事务结束,这种方式适用于需要修改的场景。 `SELECT ... LOCK IN SHARE MODE` 语句会对查询结果的每一行加上共享(Shared Lock),其它事务可以对这些行进行查询但是无法修改或者加排它,直到当前事务结束,这种方式适用于只读场景。 下面是使用 `SELECT ... FOR UPDATE` 的示例代码: ```java Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = dataSource.getConnection(); pstmt = conn.prepareStatement("SELECT * FROM my_table WHERE id = ? FOR UPDATE"); pstmt.setLong(1, 1L); rs = pstmt.executeQuery(); // 对查询结果进行修改 } catch (SQLException e) { // 异常处理 } finally { // 关闭连接和释放资源 try { rs.close(); } catch (Exception e) {} try { pstmt.close(); } catch (Exception e) {} try { conn.close(); } catch (Exception e) {} } ``` 在以上示例代码,通过 `SELECT ... FOR UPDATE` 查询 id 为 1 的记录并加上排它,然后对查询结果进行修改。 需要注意的是,使用悲观会对数据库性能有影响,因为在定期间其它事务无法访问被定的数据。因此,在使用悲观时需要谨慎权衡性能和数据一致性的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值