1. 程式人生 > >mysql innodb 行鎖

mysql innodb 行鎖

共享鎖 S 允許一個事務去讀取一個行,阻止其他事務獲取相同資料集的排它鎖

排它鎖 X 允許獲得排它鎖的事務更新資料,阻止其他事務獲取相同資料集的共享鎖和排他鎖

mysql InnoDB引擎預設的修改資料語句,update,delete,insert都會自動給涉及到的資料加上排他鎖,select語句預設不會加任何鎖型別,

如果加排他鎖可以使用select ...for update語句,加共享鎖可以使用select ... lock in share mode語句。

所以加過排他鎖的資料行在其他事務種是不能修改資料的,也不能通過for update和lock in share mode鎖的方式查詢資料,但可以直接通過select ...from...查詢資料,

因為普通查詢沒有任何鎖機制。

ext-align: -webkit-auto; text-indent: InnoDB 行鎖是通過給索引上的索引項加鎖來實現的,這一點 MySQL Oracle 不同,後者是
通過在資料塊中對相應資料行加鎖來實現的。InnoDB這種行鎖實現特點意味著:只有通過
索引條件檢索資料,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖!

1 沒有索引使用表鎖

CREATE TABLE `tab_no_index` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;



import java.sql.*;

/**
 * Created by fd on 2016/9/19.
 */
public class JDBC {
    public static final String url = "jdbc:mysql://127.0.0.1/e2e?serverTimezone=UTC&characterEncoding=utf8&useSSL=true";
    public static final String name = "com.mysql.cj.jdbc.Driver";
    public static final String user = "root";
    public static final String password = "root";

    public static void main(String[] args) {
        try {
            Class.forName(name);
            Connection connection1 = DriverManager.getConnection(url, user, password);
            connection1.setAutoCommit(false);
            Statement statement1 = connection1.createStatement();
            ResultSet set1 = statement1.executeQuery("select * from tab_no_index where id = 1 for update");
            while (set1.next()) {
                System.out.println(set1.getInt("id")+" "+set1.getString("name"));
            }
//            System.out.println(connection1.getTransactionIsolation());


            Connection connection2 = DriverManager.getConnection(url, user, password);
            connection2.setAutoCommit(false);
            Statement statement2 = connection2.createStatement();
            ResultSet set2 = statement2.executeQuery("select * from tab_no_index where id = 2 for update");
            while (set2.next()) {
                System.out.println(set2.getInt("id")+" "+set2.getString("name"));
            }

            connection1.close();
            connection2.close();

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
        }
    }
}

只會輸出1 1,然後阻塞。

2 有索引使用行鎖,鎖住的是索引,不是針對紀錄。

CREATE TABLE `tab_no_index` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(10) DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


import java.sql.*;

/**
 * Created by fd on 2016/9/19.
 */
public class JDBC {
    public static final String url = "jdbc:mysql://127.0.0.1/e2e?serverTimezone=UTC&characterEncoding=utf8&useSSL=true";
    public static final String name = "com.mysql.cj.jdbc.Driver";
    public static final String user = "root";
    public static final String password = "root";

    public static void main(String[] args) {
        try {
            Class.forName(name);
            Connection connection1 = DriverManager.getConnection(url, user, password);
            connection1.setAutoCommit(false);
            Statement statement1 = connection1.createStatement();
            ResultSet set1 = statement1.executeQuery("select * from tab_no_index where id = 1 and name = '1' for update");
            while (set1.next()) {
                System.out.println(set1.getInt("id")+" "+set1.getString("name"));
            }
//            System.out.println(connection1.getTransactionIsolation());


            Connection connection2 = DriverManager.getConnection(url, user, password);
            connection2.setAutoCommit(false);
            Statement statement2 = connection2.createStatement();
            ResultSet set2 = statement2.executeQuery("select * from tab_no_index where id = 1 and name = '2' for update");
            while (set2.next()) {
                System.out.println(set2.getInt("id")+" "+set2.getString("name"));
            }

            connection1.close();
            connection2.close();

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
        }
    }
}

結果還是會阻塞,鎖住的是id=1這個索引。

還有一個參考

http://www.cnblogs.com/boblogsbo/p/5602122.html