对于数据库的自增、自减心得

系统研发过程中会有很多地方涉及到自增、自减操作 如:加入版块时,用户版块数自增1,版块用户数自增1;退出版块时,用户版块数要减1,版块用户数也要减1

这里推荐:
  • 1.自增可以用
  • 2.自减不要用,而是用重新count结果的方式。这样可以确保数据的一致性,并且,实际用户使用过程中,自减比较少的,大多数都是自增,重新count一遍,性能并不会有多少消耗。
$map['uid']=$uid;
$map['fid']=$forum_id;
$res = self::where($map)->find();
//查看版块关注表中是否有记录
self::startTrans();
try{
	if ($res) {
		if ($res['status'] == 1) {  //若有记录并且已加入,则改为退出状态,并将该版块用户数减一
			$status = 0;
			$now_count=self::where('fid',$forum_id)->where('status',1)->count();
			ComForum::where('id', $forum_id)->setField('member_count',$now_count-1);

			$forum_count=self::getForumCount($uid);
			UserModel::where('uid',$uid)->setField('forum_count',$forum_count-1);
			//退出版块日志
			action_log($uid,2,'退出版块');
		} else {  //若有记录并且已退出版块,则改为加入,并将该版块用户数加一
			$status = 1;
			ComForum::where('id', $forum_id)->setInc('member_count');
			UserModel::where('uid',$uid)->setInc('forum_count');
			//加入版块日志
			action_log($uid,1,'加入版块');
		}
		self::update(['status'=>$status],$map); //更新操作
	} else {  //若没有记录则添加加入记录,并将该版块用户数加一
		self::add(['uid' => $uid, 'fid' => $forum_id,'status'=>1,'create_time'=>time()]);
		ComForum::where('id', $forum_id)->setInc('member_count');
		UserModel::where('uid',$uid)->setInc('forum_count');
		//加入版块日志
		action_log($uid,1,'加入版块');
	}
	UserTaskNew::newAddToForum($uid); //加入版块新手任务
	self::commitTrans();
	return true;
}catch (\Exception $e){
	self::rollbackTrans();
	self::setErrorInfo('操作失败:'.self::getErrorInfo().$e->getMessage());
	return false;
}
重点:关于事务中的update、setField、setInc、setDec的操作,执行失败,也不会报exception,事务不会回滚

事务中,对于数据库的更新操作,如果where条件查询不到结果,更新不会被执行,这样执行结果为失败,但不会抛出异常,事务继续正常向下执行。

######面对如上这种情况,该如何处理呢?有如下2中可选方案

  • 1、保证where条件肯定能查询到想要的数据。比如根据id查询,id肯定存在的,不然之前就报错了。
  • 2、获取执行结果,如果执行结果$res==0,说明更新操作影响了0行,那么可以调用exception('更新执行失败');主动抛出异常,告诉事务,回滚操作,执行失败。
注意:关于积分的自减

积分在用户体系里面尤为特殊且很重要,对于积分,不适合重新count了,这个时候只能用自减。 那么如何保证自减操作不会出现异常呢?比如,积分制不会变负值。 这里有两步:

  • 1.数据库字段设置为unsigned(非负数)
  • 2.进行自减时,where条件里面加上score>=num(score为积分字段,num为要自减的数值)

如上两步操作完成后,还有个问题要注意:涉及到积分变动,在外围调用的时候都会用事务的写法,这个时候,如果加上where条件时,虽然积分自减失败了,但是数据库执行是正常的,而实际情况应该是执行失败,并回滚所有事务。那怎么办呢?

  • 可以考虑检测自减操作影响的行数,如果影响行数为0,说明执行失败,这个时候,代码中可以加上主动抛出异常的操作,异常信息为"扣除用户积分操作失败!",提醒外围进行回滚事务。

转载于:https://my.oschina.net/zzlzheng/blog/3062152

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值