MySQl中隔离级别和悲观锁乐观锁

1.MySql的事物支持

 

MySQL的事务支持不是绑定在MySQL服务器本身,而是与存储引擎相关:

  1. MyISAM:不支持事务,用于只读程序提高性能   
  2. InnoDB:支持ACID事务、行级锁、并发   
  3. Berkeley DB:支持事务

 

2.隔离级别

隔离级别决定了一个session中的事务可能对另一个session的影响、并发session对数据库的操作、一个session中所见数据的一致性 
ANSI标准定义了4个隔离级别,MySQL的InnoDB都支持:

Java代码

  1. READ UNCOMMITTED:最低级别的隔离,通常又称为dirty read,它允许一个事务读取还没commit的数据,这样可能会提高性能,但是dirty read可能不是我们想要的   
  2. READ COMMITTED:在一个事务中只允许已经commit的记录可见,如果session中select还在查询中,另一session此时insert一条记录,则新添加的数据不可见   
  3. REPEATABLE READ:在一个事务开始后,其他session对数据库的修改在本事务中不可见,直到本事务commit或rollback。在一个事务中重复select的结果一样,除非本事务中update数据库。   
  4. SERIALIZABLE:最高级别的隔离,只允许事务串行执行。为了达到此目的,数据库会锁住每行已经读取的记录,其他session不能修改数据直到前一事务结束,事务commit或取消时才释放锁。  

可以使用如下语句设置MySQL的session隔离级别:

 

SET TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE} 

MySQL默认的隔离级别是REPEATABLE READ,在设置隔离级别为READ UNCOMMITTED或SERIALIZABLE时要小心,READ UNCOMMITTED会导致数据完整性的严重问题,而SERIALIZABLE会导致性能问题并增加死锁的机率.


 

3.乐观锁和悲观锁的策略

乐观所和悲观锁策略: 
悲观锁:在读取数据时锁住那几行,其他对这几行的更新需要等到悲观锁结束时才能继续 .
乐观所:读取数据时不锁,更新时检查是否数据已经被更新过,如果是则取消当前更新 .
一般在悲观锁的等待时间过长而不能接受时我们才会选择乐观锁
.

悲观锁的例子:

CREATE PROCEDURE tfer_funds     
       (from_account INT, to_account INT,tfer_amount NUMERIC(10,2),     
        OUT status INT, OUT message VARCHAR(30))     
BEGIN     
    DECLARE from_account_balance NUMERIC(10,2);     
    
    START TRANSACTION;     
    
    
    SELECT balance     
      INTO from_account_balance     
      FROM account_balance     
     WHERE account_id=from_account     
       FOR UPDATE;     
    
    IF from_account_balance>=tfer_amount THEN     
    
         UPDATE account_balance     
            SET balance=balance-tfer_amount     
          WHERE account_id=from_account;     
    
         UPDATE account_balance     
            SET balance=balance+tfer_amount     
          WHERE account_id=to_account;     
         COMMIT;     
    
         SET status=0;     
         SET message='OK';     
    ELSE     
         ROLLBACK;     
         SET status=-1;     
         SET message='Insufficient funds';     
    END IF;     
END;    

乐观锁的例子:

CREATE PROCEDURE tfer_funds     
    (from_account INT, to_account INT, tfer_amount NUMERIC(10,2),     
        OUT status INT, OUT message VARCHAR(30) )     
    
BEGIN     
    
    DECLARE from_account_balance    NUMERIC(8,2);     
    DECLARE from_account_balance2   NUMERIC(8,2);     
    DECLARE from_account_timestamp1 TIMESTAMP;     
    DECLARE from_account_timestamp2 TIMESTAMP;     
    
    SELECT account_timestamp,balance     
        INTO from_account_timestamp1,from_account_balance     
            FROM account_balance     
            WHERE account_id=from_account;     
    
    IF (from_account_balance>=tfer_amount) THEN     
    
        -- Here we perform some long running validation that     
        -- might take a few minutes */     
        CALL long_running_validation(from_account);     
    
        START TRANSACTION;     
    
        -- Make sure the account row has not been updated since     
        -- our initial check     
        SELECT account_timestamp, balance     
            INTO from_account_timestamp2,from_account_balance2     
            FROM account_balance     
            WHERE account_id=from_account     
            FOR UPDATE;     
    
        IF (from_account_timestamp1 <> from_account_timestamp2 OR     
            from_account_balance    <> from_account_balance2)  THEN     
            ROLLBACK;     
            SET status=-1;     
            SET message=CONCAT("Transaction cancelled due to concurrent update",     
                " of account"  ,from_account);     
        ELSE     
            UPDATE account_balance     
                SET balance=balance-tfer_amount     
                WHERE account_id=from_account;     
    
            UPDATE account_balance     
                SET balance=balance+tfer_amount     
                WHERE account_id=to_account;     
    
            COMMIT;     
    
            SET status=0;     
            SET message="OK";     
        END IF;     
    
    ELSE     
        ROLLBACK;     
        SET status=-1;     
        SET message="Insufficient funds";     
    END IF;     
END$$    

 一个讲解比较清楚的博客推荐:http://blog.csdn.net/csh624366188/article/details/7654996

posted on 2016-03-12 09:35  明静  阅读(443)  评论(0编辑  收藏  举报

导航