废话不说了。直接贴代码
package com.test.concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConcurrentAsset {
private static Lock lock = new ReentrantLock();
public static void update(Asset asset,double newMoney) {
try{
//lock.lock();之所以注释掉,是发现问题,
//假设用户从界面查看的产品,在这个时候界面是有产品对应的乐观所版本号的.所以即使加锁,在并发的情况下,乐观所的问题还是存在
//查询资产目前价值
Double money = JDBCUtil.queryAsset().getMoney();
//比对资产剩余价值是否还可以减少,模拟,固定每次资产少于1千,总资产为1万
//这里其实说白了就类似于抢购,更新库存,多人并发操作数据库中的一条数据
if(money>=newMoney){
Object[] params = {newMoney,asset.getId(),asset.getVersion()};
//更新资产表(库存表,+了乐观所机制,每次更新版本递增+1),
StringBuilder sql = new StringBuilder();
sql.append("update asset set ");
sql.append("money=money-?,");
sql.append("version=version+1 ");
sql.append("where id = ? and version = ?");
int r = JDBCUtil.update(sql.toString(),params);
if (r == 0) {
//模拟环境,加入执行结果为0就抛出异常
throw new RuntimeException("乐观所异常");
}else{
JDBCUtil.commint();
}
}else{
throw new RuntimeException("余额不足");
}
}finally{
//释放JDBC相关..ThreadLocal..
JDBCUtil.release();
//lock.unlock();释放锁
}
}
public static void main(String[] args) {
//模拟并发操作,创建15个大小的线程池
ExecutorService executorService = Executors.newFixedThreadPool(15);
//模拟5个用户并发购买资产
for (int i = 0; i < 5; i++) {
//并发操作
executorService.execute(new Runnable() {
@Override
public void run() {
try{
//模拟页面客户刚刚检索出的数据,包含数据ID,和乐观所版本号
Asset asset = JDBCUtil.queryAsset();
update(asset, 1000);
}catch(Exception e){
System.err.println(e.getMessage());
}
}
});
}
//关闭线程池...
executorService.shutdown();
}
}
不知道大家伙能看明白我这段代码的意思么?
实际上,我是想说,怎样处理并发情况下,乐观所的异常。
场景案例,腾讯的红包,
n个人抢1份数量为10的红包,金额肯定是有限的。。
每抢一次,金额必然减少,数量肯也会减少。
假设内置了乐观所,在更新红包金额和数量的时候,
为了保证处理中数据的一致性,先从数据库读取数据对应的 乐观所版本号。
然后逻辑校验..可能中间调用了其他组件..经过一系列处理校验通过,更新数据,戴上版本号。但是发现版本号已经过时了..实际上红包的数量和金额还是可以抢的。
这个问题具体应该怎么解决呢?
哪位有经验的大神给讲讲?
package com.test.concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConcurrentAsset {
private static Lock lock = new ReentrantLock();
public static void update(Asset asset,double newMoney) {
try{
//lock.lock();之所以注释掉,是发现问题,
//假设用户从界面查看的产品,在这个时候界面是有产品对应的乐观所版本号的.所以即使加锁,在并发的情况下,乐观所的问题还是存在
//查询资产目前价值
Double money = JDBCUtil.queryAsset().getMoney();
//比对资产剩余价值是否还可以减少,模拟,固定每次资产少于1千,总资产为1万
//这里其实说白了就类似于抢购,更新库存,多人并发操作数据库中的一条数据
if(money>=newMoney){
Object[] params = {newMoney,asset.getId(),asset.getVersion()};
//更新资产表(库存表,+了乐观所机制,每次更新版本递增+1),
StringBuilder sql = new StringBuilder();
sql.append("update asset set ");
sql.append("money=money-?,");
sql.append("version=version+1 ");
sql.append("where id = ? and version = ?");
int r = JDBCUtil.update(sql.toString(),params);
if (r == 0) {
//模拟环境,加入执行结果为0就抛出异常
throw new RuntimeException("乐观所异常");
}else{
JDBCUtil.commint();
}
}else{
throw new RuntimeException("余额不足");
}
}finally{
//释放JDBC相关..ThreadLocal..
JDBCUtil.release();
//lock.unlock();释放锁
}
}
public static void main(String[] args) {
//模拟并发操作,创建15个大小的线程池
ExecutorService executorService = Executors.newFixedThreadPool(15);
//模拟5个用户并发购买资产
for (int i = 0; i < 5; i++) {
//并发操作
executorService.execute(new Runnable() {
@Override
public void run() {
try{
//模拟页面客户刚刚检索出的数据,包含数据ID,和乐观所版本号
Asset asset = JDBCUtil.queryAsset();
update(asset, 1000);
}catch(Exception e){
System.err.println(e.getMessage());
}
}
});
}
//关闭线程池...
executorService.shutdown();
}
}
不知道大家伙能看明白我这段代码的意思么?
实际上,我是想说,怎样处理并发情况下,乐观所的异常。
场景案例,腾讯的红包,
n个人抢1份数量为10的红包,金额肯定是有限的。。
每抢一次,金额必然减少,数量肯也会减少。
假设内置了乐观所,在更新红包金额和数量的时候,
为了保证处理中数据的一致性,先从数据库读取数据对应的 乐观所版本号。
然后逻辑校验..可能中间调用了其他组件..经过一系列处理校验通过,更新数据,戴上版本号。但是发现版本号已经过时了..实际上红包的数量和金额还是可以抢的。
这个问题具体应该怎么解决呢?
哪位有经验的大神给讲讲?