数据库里面 stock 字段是 int unsign ,
这条sqlupdate table_1 set stock = stock - 1
,
如果当 stock = 50 ,并发的时候,会不会导致超出50个请求 执行成功 (正常情况下当stock=0的时候再执行就会报错)?
这条语句涉及mysql的锁的什么知识 ?
数据库里面 stock 字段是 int unsign ,
这条sqlupdate table_1 set stock = stock - 1
,
如果当 stock = 50 ,并发的时候,会不会导致超出50个请求 执行成功 (正常情况下当stock=0的时候再执行就会报错)?
这条语句涉及mysql的锁的什么知识 ?
REPEATABLE READ隔离级别下,如果stock上有索引,这条语句会锁住整个索引,如果没有索引,则会锁住全表,所以即使是50个并发,执行起来也是一个一个顺序执行的,当语句顺序执行到51次的时候应该就会报错了
结合你的业务场景来分析,本身这条 sql 是没问题的。stock
为非负数,减到 0 时候回报错。
如果是一个商品的库存,然后做类似抢购业务场景,你是不是只允许减一次呢,那就要做幂等处理。
对应 MySQL 如果是 innodb 引擎,这个是加上排它锁的。
没有问题,因为update会先用当前读查出要修改的记录,然后再进行修改操作,而当前读是会对这些数据行加排它锁的,所以可以保证并发安全。下面是我写的一个小例子,有兴趣的可以自己实验一下,c1虽然早早就完成了更新,但是必然要等到c1睡眠时间结束后提交事务释放了排它锁,c2才能成功更新,在这之前c2是阻塞等待c1释放排它锁的
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection c1 = null;//获取连接1
Connection c2 = null;//获取连接2
c1.setAutoCommit(false);
c2.setAutoCommit(false);
new Thread() {
public void run() {
System.out.println("c1开始更新");
try {
PreparedStatement ps = c1.prepareStatement("update test set num = num -1 where id = 1");
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("c1完成更新");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("c1睡眠结束");
try {
c1.commit();
c1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
new Thread() {
public void run() {
System.out.println("进入线程2");
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("c2开始更新");
try {
PreparedStatement ps = c2.prepareStatement("update test set num = num -1 where id = 1");
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("c2完成更新");
try {
c2.commit();
c2.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
5 回答3.2k 阅读✓ 已解决
3 回答3.6k 阅读✓ 已解决
2 回答2.8k 阅读✓ 已解决
5 回答1.4k 阅读
3 回答1.2k 阅读✓ 已解决
2 回答2k 阅读
3 回答2k 阅读
你这问题涉及的是数据库的4个隔离等级。而锁是并发控制的手段,两者是不同层次的概念。如果你把隔离等级设到最高(串行化)则应该没有并发的问题,但是吞吐会降低