Mysql数据库数据更新失效的原因和解决方法
发布时间:2020-06-12 12:20:09
来源:亿速云
阅读:486
作者:Leah
这篇文章将为大家详细讲解有关Mysql数据库数据更新失效的原因和解决方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
1. 背景
最近的项目中遇到一项问题,并发更新某一单据的时候,出现了更新失效的情况。比如:@Transactional(rollbackFor = Exception.class)
public void update(Integer id){
//1.按id查询
//2.更新某一字段的值
}
生成的SQL大概是这样的:UPDATE table
SET field = #{field,jdbcType=INTEGER}
WHERE id= 1
那么以上代码产生的问题就是:
对于同一个id=1来说,请求A与请求B都进到了update方法中,此时按id查询得到的信息是相同的,那么请求A更新了id=1的这条记录之后,此时,请求B又对id=1的记录进行更新,此时注意请求B更新id=1的记录的时候,请求B按id查询到的数据已经是旧数据了,请求B执行完之后,请求A的更新被请求B覆盖了。如果更新的是状态,那倒无所谓,如果库存量呢?
如果更新的是库存,是在这条记录的原始值上进行+或者-操作,是不是就出问题了?
2. 分析产生的原因
事后写了个小demo来复现问题,代码大致如下:需求: 某个分类每被访问一次,排序就+1;
开启两个客户端同时访问@Transactional(rollbackFor = Exception.class)
public void updateStatusTest(Integer id) {
System.out.println(“start:”+Thread.currentThread().getName());
Category category = categoryMapper.selectById(id);
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+”:”+category);
category.setSort(category.getSort()+1);
categoryMapper.updateById(category);
category = categoryMapper.selectById(id);
System.out.println(Thread.currentThread().getName()+”:”+category);
System.out.println(“end:”+Thread.currentThread().getName());
}
DAO层使用的mybatis,生成日志大致如下:
需要更新的sort值数据库初始为:0start:http-nio-8062-exec-1
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6df7e3e9]
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2d5c951c] will be managed by Spring
==> Preparing: SELECT cid,category_name,parent_id,image_url,icon_url,sort,status FROM t_admin_category WHERE cid=?
==> Parameters: 6(Integer)
<== Columns: cid, category_name, parent_id, image_url, icon_url, sort, status
<== Row: 6, 1, 0, 11111, 1, 0, 1111
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6df7e3e9]
Time:27 ms – ID:com.sxl.simple.shop.admin.category.mapper.CategoryMapper.selectById
Execute SQL:
SELECT
cid,
category_name,
parent_id,
image_url,
icon_url,
sort,
status
FROM
t_admin_category
WHERE
cid=6
start:http-nio-8062-exec-2
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7af43046]
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@700c5b36] will be managed by Spring
==> Preparing: SELECT