并发控制 集群 分布式

并发事务的定义:多个事务同时发生,会产生5中并发问题(3个读,两个更新),但其实在数据库的某一个时刻,只会执行一个sql,但一个事务可能包含多个步骤(sql),这样可能多个事务的多个步骤交叉执行,而产生并发问题。

并发一般可以采取锁和隔离级别进行处理。

那锁和隔离级别的区别在于哪里:

隔离级别----解决看的问题--select

锁----解决更新的问题。

例如spring的事务就可以配置隔离级别,不同的隔离级别会影响事务在select时所查询的结果。

不过我们一般很少使用,一般使用数据库默认的隔离级别ReadCommitted,即只能查看已经提交的事务的数据。

锁一般可以分为:共享锁,独占锁。

按记录分又分为:表锁,行锁

我们在select时即取的是表的共享锁,那么独占锁,使用select...forupdate实现

如果一个事务取得了独占锁,那么其他事务必须等待,等待那个事务提交后释放独占锁才能继续执行。

我们常见的锁解决方案如乐观锁:解决多个事务修改相同资源造成的不可重复读和第二类更新丢失。如hibernate的version或timestamp

那么如果在如下场景,比如有golf场地,每个预订可以选择一个时间段,那么场地的可用要受时间的影响,在每次预订前,都要检查在该时间段是否有可用场地。在多线程情况下,控制这样并发insert乐观锁是做不到的,只能使用悲观锁,控制事务的并发。

如何使用悲观锁呢?

可以使用hibernate的Session的Objectload(ClasstheClass,Serializableid,LockOptionslockOptions);方法,新建一个T_LOCKS表,用来实现悲观锁,

XXXServiceImpl.java

  
lockDao.getLock();
     //一系列dao操作
     .......

hibernate的Query和Criteria都支持锁:

   
Criteria criteria = session.createCriteria(TLock.class);
         criteria.add(Restrictions.eq("lockName", "facilitylock"));
         criteria.setLockMode(LockMode.UPGRADE);
         criteria.uniqueResult() ;
         
         Query query = session.createQuery("from TLock where lockName= :lockName");
         query.setParameter("lockName", "facilitylock");
         query.setLockOptions(LockOptions.UPGRADE);
         query.uniqueResult();

注意:select...fromtableNameforupdate必须保证一定能查到记录,不然,不会有独占锁。因此,可以专门设计一张表t_locks用来存储各个需要使用独占锁的情况下去取对应的记录行的独占锁

个人感觉,数据库悲观锁类似于java的同步synchronized概念和作用,但在集群环境下java的synchronized不行,可以使用数据库悲观锁代替。

但是经使用发现mysql的并发处理性能在线程数到达100-200的时候明显降低,对于这种情况使用分布式锁,比如zookeeper是非常好的一个解决方案,zookeeper的应用场景之一就是分布式锁,而且性能经验证比mysql强很多。

分布式锁是同一进程内所有的线程共享的,所以分布式锁是用来控制集群环境中各节点的访问;

java的Synchronized是线程同步锁,只能允许一个进程的一个线程访问;

因此在分布是环境中,要控制同步,要加两个锁:一个是分布式锁,一个是线程锁(java的Synchronize方法就可以)。

Curator是zoookeeper客户端框架,提供zookeeper的各种应用场景的封装API.

相关推荐