最近碰到一个数据库并发的问题, 觉得是一个很有意义的经验教训, 备忘一下.
大致过程是这样的:
在一次迭代发布之后, 用户反馈了一个问题: 虚拟商品交易成功, 但是买家没有收到卡密.而在日志中跟踪该笔交易, 正好有一个超时情况, 日志中打印出了程序执行的完整路径, 也就是说整个交易完全没有问题. 当时百思不得其解. 怀疑数据库出了问题. 又过了一天, 用户反映了同样的问题, 对比一下本次发布的代码修改, 里面有一个是关于sql的优化, 比较修改前后的代码, 终于找到了问题的罪魁祸首:原来是在sql上出现了问题.
最开始正确的sql:
update table set status =#newStatus#, trade_id = #tradeId#, buyer_id = #buyer_id# where id in (
select * from (
select id from table
where item_id = #itemId#
and status = #initStatus#
order by id
) where rownum <= #count#
) and status = #initStatus#
这句sql的意思是, 一个商品下面有多个虚拟物品(比如游戏币, 充值卡), 一个买家购买了该商品的多个虚拟物品, 此时应该将虚拟物品的状态设置为已购买状态, 因为这些虚拟物品会有多个人购买, 为了避免同一个虚拟物品被不同的人同时购买, 需要对要购买的虚拟物品排序, 然后从中获取要购买的数量, 最后更新状态.
修改后有问题的sql是这样:
update table set status =#soldStatus#, trade_id = #tradeId#, buyer_id = #buyer_id# where id in (
select * from (
select id from table
where item_id = #itemId#
and status = #initStatus#
order by id
) where rownum <= #count#
)
当时咨询dba, 认为在里面已经判断了状态, 外层sql的状态判断显得多余, 建议去掉.
虽然整个sql操作过程也是在事务中执行. 但是依然无法避免并发的出现, 经过分析, 基本上可以还原出问题的场景:
因为更新状态实际上分为两步, 首先要查出数据, 接着再更新. 当两个人同时购买同一个商品时. 如果两人同时查出同一批数据, 一人先更新, 退出事务(此时这批数据的状态已经发生改变), 接着另外一个人再次更新, 如果此时更新没有判断这批数据当前的状态(也就是做乐观锁), 那么就会覆盖前更新者的数据, 导致前一个没有获得最终购买的虚拟物品.
而外层的状态判断相当于对执行的sql加了一个乐观锁, 如果查询得到的那批数据被另一个请求更新, 则在更新状态的数量将与请求的数量不一致, 导致该次更新失败.
分享到:
相关推荐
数据库在运行过程中可能会遭遇各种故障,如硬件故障、软件故障或操作失误等,数据库恢复技术的目的是在这些异常情况下能够将数据恢复到一个一致的、正确的状态。而并发控制是为了在多用户环境下,合理地管理对数据库...
阿里巴巴大并发插入优化案例充分展示了在面临高并发场景时,通过深入理解并优化数据库底层存储结构和索引策略,可以有效解决性能瓶颈问题。尤其是针对ASSM位图结构的精细控制,以及索引设计的创新思路,为其他企业...
- 当数据库遭遇故障或破坏时,数据库恢复技术能够将系统恢复到一致状态。这通常依赖于事务日志和备份,以便在系统崩溃后重新执行未完成的事务或回滚已完成的不一致事务。 5. **操作系统安全性**: - 安全的操作...
6. 故障类型:数据库可能遭遇事务故障、系统故障、介质故障和计算机病毒等问题。介质故障通常指硬件损坏,更难以恢复。 7. 并发控制:采用封锁机制来管理并发操作,包括共享锁(允许多个事务同时读取数据)和排它锁...
数据库镜像则是通过创建数据库的实时副本,当主数据库出现问题时,可以立即切换到镜像数据库,保证服务连续性。 SQL Server的数据恢复机制体现了上述理论,它提供了多种恢复模型,如简单恢复模型、完整恢复模型和大...
3. **维护控制文件的多个并发备份**:确保即使其中一个控制文件损坏也能迅速恢复。 4. **时常备份物理数据文件**:建议定期备份数据文件,并将备份文件存放在安全的位置。 #### 五、备份与恢复操作 ##### 5.1 常见...
- 数据库可能会遭遇事务内部故障、系统故障、介质故障甚至恶意攻击。故障恢复机制旨在快速恢复系统到正常状态,确保数据的完整性和一致性。 - 日志记录和备份:通过记录事务操作日志和定期备份,可以在系统崩溃后...
6. **数据库故障**:数据库可能遭遇事务故障、系统故障、介质故障和计算机病毒等,需要有相应的恢复策略。 7. **并发控制**:通过封锁机制防止并发操作导致的数据不一致,封锁分为共享锁(读锁)和排它锁(写锁)。...
当前,为解决高并发问题,有多种手段可采用。硬件升级是最直观的方法,但成本较高且不是根本解决方案。除了硬件升级,提升服务器的并发能力还可以通过参数调优等软件优化手段进行,但最为关键的还是对服务器架构的...
在当前互联网环境中,尤其对于提供公共服务如高考分数查询的系统,高并发问题显得尤为重要,因为这类服务往往会在短时间内面临成千上万的访问请求。 在设计高并发Web系统时,首先要考虑的是软硬件架构的选择。文章...
15. **故障类型**:数据库系统可能遭遇事务故障、系统故障和介质故障,需要有恢复机制来应对这些故障。 这些知识点涵盖了数据库的基础理论、SQL语法、数据模型、关系数据库设计、事务处理和并发控制等多个方面,是...
但随着游戏的规模和复杂度不断增加,关系模型可能会遭遇性能瓶颈,因此对数据库的优化就显得尤为重要。例如,使用索引来加速数据检索,合理设计表结构来优化存储空间,使用缓存机制来减少数据库的压力,以及采用...
19. 数据库系统可能遭遇事务故障、系统故障、介质故障和计算机病毒等,备份策略包括完全备份、事务日志备份和增量备份。 20. 备份操作可在线或离线进行,封锁类型包括排他锁和共享锁,控制并发访问。 以上内容详尽...
2. 数据库可能遭遇**事务失败**、**系统崩溃**和**磁盘故障**。 3. 视图是从**基本表**中导出的虚表,仅存储其**定义**,不存储**具体数据**。 4. 关系操作具有**集合操作**的特点。 **简答题部分**: 1. 创建表...
热备份允许在不影响数据库服务的情况下进行,但冷备份更为安全,因为它不会引入潜在的并发问题。 - 逻辑备份则通过Oracle的导出工具(如Expdp, Export)将数据抽取到二进制文件中,便于在需要时导入数据库。 ...
数据库可能会遭遇各种故障,包括事务故障、系统故障和介质故障,每种故障都需要采取不同的恢复策略。 1. **事务故障**:当某个事务在执行过程中突然中断,系统需要通过回滚该事务,即撤销其对数据库的所有改动,以...
2. **数据库机器众多**:为了支持海量数据和高并发访问,通常会部署多台数据库服务器。 3. **多地部署**:为了提高可用性和容灾能力,数据库不仅在本地数据中心部署,也会在远程数据中心进行部署。 4. **多种数据库...
MySQL 数据恢复是数据库管理中的一项重要任务,尤其是在遭遇意外数据丢失、硬件故障或软件错误时。以下是三种常用的数据恢复方式的详细说明: 1. **通过表备份的方式**: 当数据表因各种原因如误删除、软件故障或...
尽管上述调整能提升数据库的抗压能力,但解决根本问题需要分析连接压力的来源和为何需要大量并发连接。可能的解决方案包括: - 使用缓存层,如Redis,作为数据库前端,以缓冲突如其来的连接请求,降低对数据库的压力...
1. **并发处理**:当大量请求同时涌入,如果序列号生成逻辑没有做好并发控制,可能会导致数据库锁竞争,从而引发超时。 2. **数据库查询效率**:如果序列号依赖于数据库自增字段,频繁的读写操作可能导致数据库响应...