并发控制 集群 分布式

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


并发一般可以采取锁和隔离级别进行处理。
那锁和隔离级别的区别在于哪里:
      隔离级别----解决看的问题--select
      锁----解决更新的问题。
例如spring的事务就可以配置隔离级别,不同的隔离级别会影响事务在select时所查询的结果。
不过我们一般很少使用,一般使用数据库默认的隔离级别Read Committed,即只能查看已经提交的事务的数据。
     
     锁一般可以分为:共享锁,独占锁。
     按记录分又分为:表锁,行锁
     我们在select时即取的是表的共享锁,那么独占锁,使用select ...for update实现
如果一个事务取得了独占锁,那么其他事务必须等待,等待那个事务提交后释放独占锁才能继续执行。
    
     我们常见的锁解决方案如乐观锁:解决多个事务修改相同资源造成的不可重复读和第二类更新丢失。如hibernate的version 或timestamp
    
     那么如果在如下场景,比如有golf场地,每个预订可以选择一个时间段,那么场地的可用要受时间的影响,在每次预订前,都要检查在该时间段是否有可用场地。在多线程情况下,控制这样 并发 insert乐观锁是做不到的,只能使用悲观锁,控制事务的并发。

     如何使用悲观锁呢?
     可以使用hibernate的Session 的Object load(Class theClass, Serializable id, LockOptions lockOptions);方法,新建一个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 ...from tableName for update 必须保证一定能查到记录,不然,不会有独占锁。因此,可以专门设计一张表t_locks用来存储各个需要使用独占锁的情况下去取对应的记录行的独占锁
    个人感觉,数据库悲观锁类似于java的同步synchronized概念和作用,但在集群环境下java的synchronized不行,可以使用数据库悲观锁代替。

     但是经使用发现mysql的并发处理性能在线程数到达100-200的时候明显降低,对于这种情况使用分布式锁,比如zookeeper是非常好的一个解决方案,zookeeper的应用场景之一就是分布式锁,而且性能经验证比mysql强很多。
    分布式锁是同一进程内所有的线程共享的,所以分布式锁是用来控制集群环境中各节点的访问;
    java的Synchronized是线程同步锁,只能允许一个进程的一个线程访问;

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

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

猜你喜欢

转载自xls9577087.iteye.com/blog/2241796