如何解决超卖问题?
超卖问题:就是多个线程并发执行,目前唯一方案是加锁。
如图:悲观锁其实还有数据库的互斥锁。悲观锁是最常见的

乐观锁实现的原理:
版本号:

这种方案就是:扣款库存的时候首先先查询版本号,然后再修改库存的时候把查询的库存号当做条件并把版本号进行+1,库存-1。
CAS发

和第一种一样只是把版本号换成库存了。很好理解
优点:性能比悲观锁好。
缺点:高并发情况下依然存在超卖的问题。
乐观锁的如何使用:
如图上面是支付宝回调出现的扣减库存的。这里的扣减库存。
sysProductMapper.deductionOfInventory(sysProduct.getCode());
这个就是乐观锁的一种实现方案:

在不添加版本号的前提下还有一种就是

可以这也理解我举一个例子
有的人会提出这个疑问。mysql的隔离级别是读已提交。但是update会进行获取写如果code不是索引则会全表锁,如果是索引会行锁这样下来就不会出现那种情况了。事务A拿到后会对这条数据进行行锁的。
悲观锁:直接可以加上synchronized在方法上,不过关键字加载方法上代表是当前这个对象进行锁
性能过低

当前也可以这样。因为是在同一个code加锁,所以我的锁是库存编码

还有一点一定要注意,如果你的锁对象是string那无所谓常量池是同一个。
但是如果你是Long类型转换为toString就不一样了看下源码
这是Long类型转换为toString的源码
java
/**
* Returns a {@code String} object representing this
* {@code Long}'s value. The value is converted to signed
* decimal representation and returned as a string, exactly as if
* the {@code long} value were given as an argument to the
* {@link java.lang.Long#toString(long)} method.
*
* @return a string representation of the value of this object in
* base 10.
*/
public String toString() {
return toString(value);
}
/**
* Returns a {@code String} object representing the specified
* {@code long}. The argument is converted to signed decimal
* representation and returned as a string, exactly as if the
* argument and the radix 10 were given as arguments to the {@link
* #toString(long, int)} method.
*
* @param i a {@code long} to be converted.
* @return a string representation of the argument in base 10.
*/
public static String toString(long i) {
if (i == Long.MIN_VALUE)
return "-9223372036854775808";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
看到toString了吗?他会进行一直new所以尽可能是看着是同一个对象,但是锁的值不同。
java
Long a = 2L;
String s1 = a.toString(); // String@123
String s2 = s1.intern(); // 常量池中的"2"(引用为String@789)
Long b = 2L;
String s3 = b.toString(); // String@456
String s4 = s3.intern(); // 同样返回常量池中的"2"(String@789)
所以如果是转换为string类型一定要进行intern

一般并发量特别大的情况下一般别进行锁表