Springboot解决业务并发问题 | 您所在的位置:网站首页 › springboot500错误总结 › Springboot解决业务并发问题 |
一、业务需求(大家有类似的也可以参考我的解决方案)
实现一种类似于医院预约的预约功能,在同一个时间段,可能大家都看得到这个预约的按钮,大家都点进去了,这个时候真正提交预约信息的时候,就会可能出现多个请求同一个时间段的预约,在service层中,有可能会造成并发问题:几个线程可能都读到时间段的status(数据库中字段)为1,大家都能提交预约了 二、解决方案 方案一:select for update + @Transactional在对应的service层方法中加上这个注解,手动开启事务,这会导致我们这个方法全部执行完毕之后,才会进行事务的提交,不然则不会提交事务,途中如果有异常,则会rollback,出现状态码500 select for update 这句话会将数据库查到的数据进行加上悲观锁(查到多少就加多少行的锁,会导致更大的问题,大家请精确到一行数据进行加锁),加上锁之后,其他线程想要执行这条语句的时候就会被阻塞的 什么时候会释放锁呢?要等到我们这个方法完成了,事务提交了就会进行释放锁(正常情况下) 这里简单跟大家说select for update加的行级锁知识和该注解的知识 select for update:for update是一种行级锁,又叫排它锁,一旦用户对某个行施加了行级加锁,则该用户可以查询也可以更新被加锁的数据行,其它用户只能查询但不能更新被加锁的数据行.如果其它用户想更新该表中的数据行,则也必须对该表施加行级锁.即使多个用户对一个表均使用了共享更新,但也不允许两个事务同时对一个表进行更新,真正对表进行更新时,是以独占方式锁表,一直到提交或复原该事务为止。行锁永远是独占方式锁。 只有当出现如下之一的条件,才会释放共享更新锁: 1、执行提交(COMMIT)语句 2、退出数据库(LOG OFF) 3、程序停止运行 @Transactional:实现原理: 1) 事务开始时,通过AOP机制,生成一个代理connection对象, 并将其放入 DataSource 实例的某个与 DataSourceTransactionManager 相关的某处容器中。 在接下来的整个事务中,客户代码都应该使用该 connection 连接数据库, 执行所有数据库命令。 [不使用该 connection 连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚] (物理连接 connection 逻辑上新建一个会话session; DataSource 与 TransactionManager 配置相同的数据源) 2) 事务结束时,回滚在第1步骤中得到的代理 connection 对象上执行的数据库命令, 然后关闭该代理 connection 对象。 (事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用) 方案二(方案一改进版):update + @Transactional(update数据库表中时间段的status)该方法用update直接上独占锁(悲观锁),对比上一个方案,我们的范围缩小了 update完了之后可以返回数字1 or 0,如果1则表示更新成功,0则表示更新失败 0则返回controller,表示提交预约失败,以此来防止我们的并发问题 三、总结1、得进行学习springboot得一些注解 2、学习进阶mysql锁的知识 3、有时候不进行正式的公司开发流程,真的不知道高级并发处理该咋搞 4、准备学习一下MybatisPlus 5、方案二的做法对比与方案一其实像乐观锁,大家可以细细品一下 6、update完status之后如果update成功的话就会submit我们的预约 |
CopyRight 2018-2019 实验室设备网 版权所有 |