利用nginx集群式部署服务器中,数据同步问题

针对在nginx集群服务器部署环境下,因并发请求导致的MySQL数据库重复更新问题,通过使用悲观锁成功避免了账户余额变为负数的情况,并探讨了悲观锁与乐观锁的应用场景。

最近在项目中遇到了一个数据同步的问题

项目部署背景:利用nginx集群式服务器部署,使用唯一的一台数据库服务器,数据库为mysql

问题描述:对一个账户进行更新操作,一个未查明的原因,用户点击更新操作后,未知的原因在后台同时产生了两个request请求,这两个请求并发进行,同时调用存储过程对数据库进行操作,造成了对数据库的重复操作,等于说操作了两次,账户余额变成了负值。

为了重新问题,写了个测试类,多线程调用此存储过程,重现了这个问题

final TaskThreadExecution t = new TaskThreadExecution();
    	 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 3000, 3,  
                 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5000),  
                 new ThreadPoolExecutor.DiscardOldestPolicy());  
    	 for(int i=0;i<2000;i++){
    		
    		 
    		if(i<200){
    			try {
    				Random random = new Random();
    				System.out.println(random.nextInt(100));
					Thread.sleep(random.nextInt(100));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
    		}
    			 threadPool.execute(new Runnable() {
						@Override
						public void run() {
							// TODO Auto-generated method stub
							try {
								//调用存储过程,对数据进行操作
								t.oper();
								
								
							} catch (Exception e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
				});
    			 
    		 }

  

因为是集群部署,所有将调用存储过程的方法设置为同步方法也不起作,最后想到了mysql的悲观锁,设置行级别的悲观锁,然后再获取锁的下一步进行数据判断,来进行处理

//加悲观锁的语句

SELECT usableSum INTO @usableSum FROM t_user WHERE id=in_uid FOR UPDATE;
SET @usableSum = IFNULL(@usableSum,0);
IF @usableSum <=0 THEN
ROLLBACK;
SET out_ret = -7;
SET out_desc = '余额不足';
LEAVE _return;
END IF;

IF @usableSum <in_money THEN
ROLLBACK;
SET out_ret = -8;
SET out_desc = 余额不足';
LEAVE _return;
END IF;

经过测试,完美的解决了数据同步的问题,

如果使用的Hibernate进行数据库操作,可以使用以下方式对数据库进行加锁

 String hqlStr ="from TUser as user where user.name='Erica'";

 Query query = session.createQuery(hqlStr);

  query.setLockMode("user",LockMode.UPGRADE); // 加锁

  List userList = query.list();// 执行查询,获取数据

query.setLockMode 对查询语句中,特定别名所对应的记录进行加锁(我们为 TUser 类指定了一个别名 “user” ),这里也就是对返回的所有 user 记录进行加锁。

但是使用悲观锁对数据库的性能开销影响比较大,如果是大量的多线程并发的话,会造成数据库性能开销营销太大,这个时候推荐使用乐观锁来进行加锁,乐观锁相对于悲观锁采取了更加宽松的加锁机制,悲观锁属于排他的,当对数据进行加锁后,其他人无法获取此数据,只能当上个操作释放掉锁,悲观锁是利用字段来进行加锁的,可以在表中添加一个字段version,每次获取version,同时更新数据的时候,将此version进行+1操作,对version进行对比

转载于:https://www.cnblogs.com/muxiaozi/p/5035776.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值