数据库锁的问题 insert where 的问题 postgresql并发数据库java 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 就是公司的金钱流水表会员的金钱流动会在金钱流水添加一条记录 如: 会员存款100元记录中的 money字段就为 100会员购买商品消耗10元 上面那个回复手抖了 还没写完就发出去了 不知道为啥还不能编辑的就是公司的金钱流水表会员的金钱流动会在金钱流水添加一条记录 如: 会员存款100元 记录中的 money字段就为 100会员购买商品消耗10元 记录中的 money字段就为 -10判断会员余额时就 sum(money) 获得 90 90就是会员的余额我在 insert 的时候判断了下 如果这次插入的数据是负数 就判断 会员的余额必须比本次插入的 负数的绝对值 大(就是余额要大于本次消费的金额)但出现了 余额小于 商品金额的情况下 成功购买了商品的情况简单讲就是 一个 10元的商品 会员只有 11元的余额 会员购买该商品时 不知道怎么回事 并发了2个请求 结果两个请求判断 会员的金额都是大于10 然后 会员 购买了2个 10元的商品 余额变为 -9 不知道是不是由于2个SQL并发且在事务中并未提交 延迟提交后产生的问题?事物管理器用的 org.springframework.orm.hibernate3.HibernateTransactionManager如果是 有什么解决办法不?(纯SQL修改的方式)有没有高人来解答下疑惑.... 这个并发问题,我感觉啊 , 你在方法名加上synchronized,防止出现负数问题 上面有说明的 后来由于是生产环境就先把方法加了一个锁先解决问题主要是没搞明白为啥insert where没有效果加 synchronized 会非常影响性能 锁粒度太大了 我用了个 ConcurrentHashMap 作为锁对单个会员进行锁操作boolean flag = false;//用会员ID进行加锁String moneyLockkey = geMoneyDetails.getAccountId().toString();synchronized (LockUtil.MoneyLock){ flag = LockUtil.MoneyLock.get(moneyLockkey,true); if(flag){ LockUtil.MoneyLock.put(moneyLockkey,false); }}if(flag){ try{ //是扣除金额 if(geMoneyDetails.getMoney().compareTo(BigDecimal.ZERO)==-1 && //因为回滚操作会导致负数 回避掉回滚代码 !geMoneyDetails.getOperateType().equals(OperateType.CancelBalance.getType()) && !geMoneyDetails.getOperateType().equals(OperateType.ReconstructionBet.getType())) { //InsertMoneyDetailsByAccumulate 就是 insert where 的那段代码 List<Long> resultCount = this.getMybatis().getListByObject("InsertMoneyDetailsByAccumulate", geMoneyDetails); if(resultCount == null || resultCount.isEmpty()) throw new DaoException("余额不足!"); } else this.getHibernate().save(geMoneyDetails); }finally{ //释放锁信息 LockUtil.MoneyLock.put(moneyLockkey,true); }}else{ throw new DaoException("您当前有金钱操作未完成请稍后尝试!");} 上面有说明的 后来由于是生产环境就先把方法加了一个锁先解决问题主要是没搞明白为啥insert where没有效果加 synchronized 会非常影响性能 锁粒度太大了 我用了个 ConcurrentHashMap 作为锁对单个会员进行锁操作boolean flag = false;//用会员ID进行加锁String moneyLockkey = geMoneyDetails.getAccountId().toString();synchronized (LockUtil.MoneyLock){ flag = LockUtil.MoneyLock.get(moneyLockkey,true); if(flag){ LockUtil.MoneyLock.put(moneyLockkey,false); }}if(flag){ try{ //是扣除金额 if(geMoneyDetails.getMoney().compareTo(BigDecimal.ZERO)==-1 && //因为回滚操作会导致负数 回避掉回滚代码 !geMoneyDetails.getOperateType().equals(OperateType.CancelBalance.getType()) && !geMoneyDetails.getOperateType().equals(OperateType.ReconstructionBet.getType())) { //InsertMoneyDetailsByAccumulate 就是 insert where 的那段代码 List<Long> resultCount = this.getMybatis().getListByObject("InsertMoneyDetailsByAccumulate", geMoneyDetails); if(resultCount == null || resultCount.isEmpty()) throw new DaoException("余额不足!"); } else this.getHibernate().save(geMoneyDetails); }finally{ //释放锁信息 LockUtil.MoneyLock.put(moneyLockkey,true); }}else{ throw new DaoException("您当前有金钱操作未完成请稍后尝试!");}比如你余额50,在19行, 你执行一次取款50, 这条数据插入了,可是数据库没有提交, 你下次执行余额还是显示50 你又插入了,我觉得你的insert where 没问题 synchronized可以锁具体对象,比如synchronized(geMoneyDetails.getMoney()),这样不会太影响性能 1、有负数是正常的,电信运营商都能欠费,太严格的校验会增加负担2、应该实时计算当前最最新余额,而不是每次都sum 建议加一个UserBalance表来记录用户的余额消费时按UserId判断余额 读取数据是加 排他锁 select ××× for update with RS 请教大家比较棘手的问题:接口开发 递归的关键字是什么 js去掉某个字符,回车 系统要为第三方留接口,这个怎么做的? SSH,在一个动态验证表单中配置了ValidatorPlugIn,没有弹出提示对话框? Hibernat 怎么删除多条信息 奇怪的事务异常问题?? 我想学j2ee,可是我的电脑跑不起来jbuilder,求助 请问高手:出现如下问题该怎么解决呢?我的EJB已经发布成功了 页面生成问题(xml) Weblogic部署cxf启动不了 SSH框架下<s:iterator>标签不起作用
就是公司的金钱流水表
会员的金钱流动会在金钱流水添加一条记录
如:
会员存款100元记录中的 money字段就为 100
会员购买商品消耗10元
上面那个回复手抖了 还没写完就发出去了 不知道为啥还不能编辑的就是公司的金钱流水表
会员的金钱流动会在金钱流水添加一条记录
如:
会员存款100元 记录中的 money字段就为 100
会员购买商品消耗10元 记录中的 money字段就为 -10判断会员余额时就 sum(money) 获得 90 90就是会员的余额我在 insert 的时候判断了下 如果这次插入的数据是负数 就判断 会员的余额必须比本次插入的 负数的绝对值 大(就是余额要大于本次消费的金额)
但出现了 余额小于 商品金额的情况下 成功购买了商品的情况简单讲就是 一个 10元的商品 会员只有 11元的余额 会员购买该商品时 不知道怎么回事 并发了2个请求 结果两个请求判断 会员的金额都是大于10 然后 会员 购买了2个 10元的商品 余额变为 -9
且在事务中并未提交 延迟提交后产生的问题?事物管理器用的 org.springframework.orm.hibernate3.HibernateTransactionManager如果是 有什么解决办法不?(纯SQL修改的方式)
有没有高人来解答下疑惑....
上面有说明的 后来由于是生产环境就先把方法加了一个锁先解决问题
主要是没搞明白为啥insert where没有效果加 synchronized 会非常影响性能 锁粒度太大了 我用了个 ConcurrentHashMap 作为锁对单个会员进行锁操作boolean flag = false;
//用会员ID进行加锁
String moneyLockkey = geMoneyDetails.getAccountId().toString();
synchronized (LockUtil.MoneyLock){
flag = LockUtil.MoneyLock.get(moneyLockkey,true);
if(flag){
LockUtil.MoneyLock.put(moneyLockkey,false);
}
}
if(flag){
try{
//是扣除金额
if(geMoneyDetails.getMoney().compareTo(BigDecimal.ZERO)==-1 &&
//因为回滚操作会导致负数 回避掉回滚代码
!geMoneyDetails.getOperateType().equals(OperateType.CancelBalance.getType()) &&
!geMoneyDetails.getOperateType().equals(OperateType.ReconstructionBet.getType()))
{
//InsertMoneyDetailsByAccumulate 就是 insert where 的那段代码
List<Long> resultCount = this.getMybatis().getListByObject("InsertMoneyDetailsByAccumulate", geMoneyDetails);
if(resultCount == null || resultCount.isEmpty())
throw new DaoException("余额不足!");
}
else
this.getHibernate().save(geMoneyDetails);
}finally{
//释放锁信息
LockUtil.MoneyLock.put(moneyLockkey,true);
}
}else{
throw new DaoException("您当前有金钱操作未完成请稍后尝试!");
}
上面有说明的 后来由于是生产环境就先把方法加了一个锁先解决问题
主要是没搞明白为啥insert where没有效果加 synchronized 会非常影响性能 锁粒度太大了 我用了个 ConcurrentHashMap 作为锁对单个会员进行锁操作boolean flag = false;
//用会员ID进行加锁
String moneyLockkey = geMoneyDetails.getAccountId().toString();
synchronized (LockUtil.MoneyLock){
flag = LockUtil.MoneyLock.get(moneyLockkey,true);
if(flag){
LockUtil.MoneyLock.put(moneyLockkey,false);
}
}
if(flag){
try{
//是扣除金额
if(geMoneyDetails.getMoney().compareTo(BigDecimal.ZERO)==-1 &&
//因为回滚操作会导致负数 回避掉回滚代码
!geMoneyDetails.getOperateType().equals(OperateType.CancelBalance.getType()) &&
!geMoneyDetails.getOperateType().equals(OperateType.ReconstructionBet.getType()))
{
//InsertMoneyDetailsByAccumulate 就是 insert where 的那段代码
List<Long> resultCount = this.getMybatis().getListByObject("InsertMoneyDetailsByAccumulate", geMoneyDetails);
if(resultCount == null || resultCount.isEmpty())
throw new DaoException("余额不足!");
}
else
this.getHibernate().save(geMoneyDetails);
}finally{
//释放锁信息
LockUtil.MoneyLock.put(moneyLockkey,true);
}
}else{
throw new DaoException("您当前有金钱操作未完成请稍后尝试!");
}
比如你余额50,在19行, 你执行一次取款50, 这条数据插入了,可是数据库没有提交, 你下次执行余额还是显示50 你又插入了,我觉得你的insert where 没问题
2、应该实时计算当前最最新余额,而不是每次都sum
消费时按UserId判断余额 读取数据是加 排他锁 select ××× for update with RS