在web应用中,每次请求都是不同的线程,因此,当对统一数据进行访问更新的时候,有可能会引发数据问题。
举个例子:有一个apple表,里面有个字段count,表示某种apple的数量。同时,后台提供获取这种苹果的服务,获取苹果之后,就需要将count的值修改。
假设apple表中有这么一条数据
id count
12345 100
----------
class Apple{
int count;
}
public interface AppleMapper{
@Select("select count from apple")
Apple getApple();
@Update("update apple set count = #{count}")
void updateCount(int count);
}
service:
public void getApple(int num) {
//step1
Apple apple = appleMapper.getApple();
//取走num个苹果后剩下count个苹果,假设num<getCount()
int count = apple.getCount() - num;
//step2
appleMapper.updateCount(count);
}
现在,有两条请求,都想获得苹果,req1.getApple(5)和req2.getApple(6);如果req1在step2完成后,req2才到达step1,那么数据库结果没有任何问题,但是,一旦req2在req1执行万step2时,就执行了step1,那么此时,req2.getCount() = 100,req1.count = 95,req2.count = 94,此时,无论哪个count存入数据库,都将是错误的,实际的count应该是89。
解决办法:
不要在业务逻辑中计算,然后将计算结果传入数据库,可传入需要改变的值,数据库sql改为”update apple set count = count + #{num}”。
还有种不推荐的方法:以在stept1处获得的值作为条件,如果数据库的值和我在step1处取出的值一致,说明没有人修改这个值,那么就更新,否则不更新。
这样的场景其实也不是很常见,一般前端将最终结果传入,只更新最终结果,就没这种问题了。最后,切记,遇到更新数值的操作时,不要在逻辑里计算,并将结果作为最终值更新,应该交由数据库去处理。