使用Redis锁处理数据库并发问题
缘起
数据库描述:
字段 | 类型 | 约束 | 备注 |
---|---|---|---|
id | int | PK | 自增主键 |
当前系统客户id | 字符串 | UNIQUE_INDEX | 由当前系统生成 |
调用方系统客户id | 字符串 | UNIQUE_INDEX | 由调用方生成 |
姓名 | 字符串 | NOT NULL | |
性别 | 字符串 | NOTNULL | F-女 N-男 |
其它业务字段 | 问题无关,不再描述 |
存在此场景:某个用户接口提供查询和保存功能,调用方传入用户信息查询条件,若是存在此用户,则返回查询到的业务主键(此主键在应用内生成),如果未查询到用户信息,先保存,然后返回业务主键信息。在并发调用此接口的时候,当传入的信息一致会出现两条相同的情况。
传入信息包含:调用方系统客户id,姓名,性别,其它业务字段
业务流程:
- 接收参数
- 根据调用方系统客户id查库,如果查得,则返回,未查得,走步骤3
- 生成当前系统客户id,并保存
- 返回当前生成的客户id
当调用方以15个线程同时请求此接口,存在两个线程携带同一用户信息查此接口的场景,日志中出现调用方系统客户id唯一索引不满足错误,换句话说,出现了两个相同的调用方系统客户id要保存。
分析
出现两个相同的调用方系统客户id猜测业务流程中有两个请求同时到达,在查库的时候发现数据库中不存在,然后走到保存步骤,其中一个保存成功了,然后另一个因为唯一索引失败了。然后我删除在调用方系统客户id建立的唯一索引,然后发现了两条数据,除了自增id和当前系统客户id不一致,其余都是一致的,其中保存时间也是一样的,因为自增id是数据库保证唯一,当前系统客户id在生成时用锁保证唯一,这两个理论上不存在重复情况,是正常的,但是两个一样的客户返回不同的当前系统客户id在逻辑上是讲不通的,要想办法让上面的业务流程在两个相同客户数据同时到达的时候要有一定的顺序,其中一个处理完以后另一个再处理,解决方案就是加锁。
解决
借用Redis实现Redis锁,在业务流程步骤2之前尝试获取锁,锁住调用方系统客户id,如果锁定成功,就处理3步骤,如果锁不住,自旋继续加锁,直到加锁成功,锁设定超时时间,超过这个时间锁就过期。
测试
20个线程,200次请求,用同一个报文,结果数据库中未发现脏数据,响应时长也可以接受
本文地址:https://blog.csdn.net/u013014691/article/details/107408262