linux+mysql+Javajava代码里用到一个sql select * from a where id in (23,234,3434,343...) for update加入现在有2个mysql链接 session1 session21
加入session1 先执行这个select * from a where id in (23,234,3434,343...) for update
            他产生了行极锁session2这个时候是不能对 id in (23,234,3434,343...)所在的行进行update/delete的
            想知道跟session1相同的时间点,session2能对他的id锁定行 进行select 吗???  不知道sqlserver  oracle也相同吗??2 sqlserver我可以用事务 + delay(拖延时间)来实现这个情况的模拟
如何模拟测试实现这个行极锁的判断

解决方案 »

  1.   

    1
    加入session1 先执行这个select * from a where id in (23,234,3434,343...) for update
      他产生了行极锁session2这个时候是不能对 id in (23,234,3434,343...)所在的行进行update/delete的
      想知道跟session1相同的时间点,session2能对他的id锁定行 进行select 吗???   
    ===》
    session2可以对锁定的行进行普通读取 但是不允许进行加了lock in share mode命令的SELECT 读取2
    如何模拟测试实现这个行极锁的判断
    ==》
    开2个窗口不就可以了?
      

  2.   

    session2可以对锁定的行进行普通读取 但是不允许进行加了lock in share mode命令的SELECT 读取也得到过结果了。2
    如何模拟测试实现这个行极锁的判断
    ==》
    开2个窗口不就可以了?
    在 qlserver我可以用事务 + delay(拖延时间)来实现这个情况的模拟
    mysql 如何做 ,写点sql 好吗  (最好有 类似slqsever 的 delay拖延时间函数)
      

  3.   

    sqlserver  有这个 waitfor delay
    不知道哦啊mysql有没有类似函数
      

  4.   

    现在我想办法把这个select   for update 的 悲观锁 换成 乐观锁 
      

  5.   

    悲观锁:
      1. CREATE PROCEDURE tfer_funds  
      2. (from_account INT, to_account INT,tfer_amount NUMERIC(10,2),  
      3. OUT status INT, OUT message VARCHAR(30))  
      4. BEGIN  
      5. DECLARE from_account_balance NUMERIC(10,2);  
      6.  
      7. START TRANSACTION;  
      8.  
      9.  
      10. SELECT balance  
      11. INTO from_account_balance  
      12. FROM account_balance  
      13. WHERE account_id=from_account  
      14. FOR UPDATE;  
      15.  
      16. IF from_account_balance>=tfer_amount THEN  
      17.  
      18. UPDATE account_balance  
      19. SET balance=balance-tfer_amount  
      20. WHERE account_id=from_account;  
      21.  
      22. UPDATE account_balance  
      23. SET balance=balance+tfer_amount  
      24. WHERE account_id=to_account;  
      25. COMMIT;  
      26.  
      27. SET status=0;  
      28. SET message='OK';  
      29. ELSE  
      30. ROLLBACK;  
      31. SET status=-1;  
      32. SET message='Insufficient funds';  
      33. END IF;  
      34. END;  
    乐观锁:
      1. CREATE PROCEDURE tfer_funds  
      2. (from_account INT, to_account INT, tfer_amount NUMERIC(10,2),  
      3. OUT status INT, OUT message VARCHAR(30) )  
      4.  
      5. BEGIN  
      6.  
      7. DECLARE from_account_balance NUMERIC(8,2);  
      8. DECLARE from_account_balance2 NUMERIC(8,2);  
      9. DECLARE from_account_timestamp1 TIMESTAMP;  
      10. DECLARE from_account_timestamp2 TIMESTAMP;  
      11.  
      12. SELECT account_timestamp,balance  
      13. INTO from_account_timestamp1,from_account_balance  
      14. FROM account_balance  
      15. WHERE account_id=from_account;  
      16.  
      17. IF (from_account_balance>=tfer_amount) THEN  
      18.  
      19. -- Here we perform some long running validation that  
      20. -- might take a few minutes */  
      21. CALL long_running_validation(from_account);  
      22.  
      23. START TRANSACTION;  
      24.  
      25. -- Make sure the account row has not been updated since  
      26. -- our initial check  
      27. SELECT account_timestamp, balance  
      28. INTO from_account_timestamp2,from_account_balance2  
      29. FROM account_balance  
      30. WHERE account_id=from_account  
      31. FOR UPDATE;  
      32.  
      33. IF (from_account_timestamp1 <> from_account_timestamp2 OR  
      34. from_account_balance <> from_account_balance2) THEN  
      35. ROLLBACK;  
      36. SET status=-1;  
      37. SET message=CONCAT("Transaction cancelled due to concurrent update",  
      38. " of account" ,from_account);  
      39. ELSE  
      40. UPDATE account_balance  
      41. SET balance=balance-tfer_amount  
      42. WHERE account_id=from_account;  
      43.  
      44. UPDATE account_balance  
      45. SET balance=balance+tfer_amount  
      46. WHERE account_id=to_account;  
      47.  
      48. COMMIT;  
      49.  
      50. SET status=0;  
      51. SET message="OK";  
      52. END IF;  
      53.  
      54. ELSE  
      55. ROLLBACK;  
      56. SET status=-1;  
      57. SET message="Insufficient funds";  
      58. END IF;  
      59. END$$   
      

  6.   

    上面的例子错误
    下面用程序来实现
    乐观锁是个什么东西
    在学习hibernate配置时,遇到所谓乐观锁(optimistic-lock )属性,是个什么东西,他的配置对应用有什么影响啊?heyitang 发表于 2009-11-3 11:58
    楼主可以参考一下如下文章
          hibernate中经常用到当多个人对同一数据同时进行修改的时候,会发生脏数据,造成数据的不一致性,解决办法是可以通过悲观锁和乐观锁来实现。
    悲观锁:在数据有加载的时候就给其进行加锁,直到该锁被释放掉,其他用户才可以进行修改,优点:数据的一致性保持得很好,缺点:不适合多个用户并发访问。当一个锁住的资源不被释放掉的时候,这个资源永远不会被其他用户进行修改,容易造成无限期的等待。
    乐观锁:就是在对数据进行修改的时候,对数据才去版本或者时间戳等方式来比较,数据是否一致性来实现加锁。优点比较好。
    1、在悲观锁中,只要在加载的时候,才去session中的load方法,进行枷锁,session.load(****.class,1,LockMode.UPDATE);
          Hibernate将事务管理委托给底层的JDBC或者JTA,默认是基于JDBC Transaction的。
          Hibernate支持“悲观锁(Pessimistic Locking)”和“乐观锁(Optimistic Locking)”。
          悲观锁对数据被外界修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制。Hibernate通过使用数据库的for update子句实现了悲观锁机制。Hibernate的加锁模式有:
          1. LockMode.NONE:无锁机制
          2. LockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取
          3. LockMode.READ:Hibernate在读取记录的时候会自动获取
          4. LockMode.UPGRADE:利用数据库的for update子句加锁
          5. LockMode.UPGRADE_NOWAIT:Oracle的特定实现,利用Oracle的for update nowait子句实现加锁
    2、乐观锁大多是基于数据版本(Version)记录机制实现。Hibernate在其数据访问引擎中内置了乐观锁实现,可以通过class描述符的optimistic-lock属性结合version描述符指定。optimistic-lock属性有如下可选取值:
          1. none:无乐观锁
          2. version:通过版本机制实现乐观锁
          3. dirty:通过检查发生变动过的属性实现乐观锁
          4. all:通过检查所有属性实现乐观锁
    例子:
    1、悲观锁:
    [code]
    1>POJO类
    public class PersimisticLocking {
    private int id;private String Item;private int price;
    //省略setter、getter方法
    }
    [/code]
    2>、POJO类的映射文件
    [code]
    1<?xml version="1.0"?>
    2<!DOCTYPE hibernate-mapping PUBLIC
    3    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    4    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    5<hibernate-mapping package="org.apple.hibernate">
    6    <class name="PersimisticLocking" table="t_persimisticLocking">
    7        <id name="id">
    8            <generator class="native"/>
    9        </id>
    10        <property name="item"/>
    11        <property name="price"/>
    12    </class>
    13</hibernate-mapping>
    [/code]3>、加载测试方法
    [code]
    1public void testLoad1()
    2    {
    3        Session session = null;
    4        try {
    5            session = HibernateUtil.getSession();
    6            session.beginTransaction();
    7            OptimisticLocking o = (OptimisticLocking)session.load(OptimisticLocking.class, 1);
    8            System.out.println("o.item="+o.getItem());
    9            System.out.println("o.price="+o.getPrice());
    10            System.out.println("o.version="+o.getVersion());
    11            o.setPrice(o.getPrice()-10);
    12            session.update(o);
    13            session.beginTransaction().commit();
    14        } catch (Exception e) {
    15            // TODO: handle exception
    16            e.printStackTrace();
    17            session.beginTransaction().rollback();
    18        }finally{
    19            HibernateUtil.closeSession(session);
    20        }
    21        
    22    }
    [/code]PS:可以设置另外类似的方法,不枷锁,先对上面的测试代码设置断点,点debug一部分,再运行不枷锁的,可以看到,如果上面方法不释放锁的话,下面的数据就会造成无限期的等待。
    2、乐观锁:
    1>在悲观锁的基础上加入private int version;和相关的setter、getter方法。
    2>映射文件配置在class标签里面加入optimistic-lock="version",然后在的id标签后面加入<version name="version"/>
    3>测试方法:
    [code]
    1public void testLoad1()
    2    {
    3        Session session = null;
    4        try {
    5            session = HibernateUtil.getSession();
    6            session.beginTransaction();
    7            OptimisticLocking o = (OptimisticLocking)session.load(OptimisticLocking.class, 1);
    8            System.out.println("o.item="+o.getItem());
    9            System.out.println("o.price="+o.getPrice());
    10            System.out.println("o.version="+o.getVersion());
    11            o.setPrice(o.getPrice()-10);
    12            session.update(o);
    13            session.beginTransaction().commit();
    14        } catch (Exception e) {
    15            // TODO: handle exception
    16            e.printStackTrace();
    17            session.beginTransaction().rollback();
    18        }finally{
    19            HibernateUtil.closeSession(session);
    20        }
    21        
    22    }
    [/code]
    PS:在初始数据的时候,version为0,在没更新一次version都会在原来的基础上加1,通过version的版本来实现乐观锁。
    在上面的测试方法里面复制成另外一个方法,对上面的方法进行设置断点,然后单步调试几部,到NO.11行的时候暂停,此时对复制的另外方法运行,然后再运行完上面的方法,就会抛出异常,所以,在实际的项目开发中,可以通过对异常进行出来,这样就会实现并发访问。
      

  7.   

    楼主看这个http://blog.csdn.net/ldb2741/archive/2010/02/25/5325161.aspx
      

  8.   

    SLEEP(duration) 测试发现是势失败的 ???? sleep(5);
    ERROR 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sleep(5)' at line 1