mysql innodb 行鎖
阿新 • • 發佈:2019-02-09
共享鎖 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