2015-08-04 5 views
2

Я пытаюсь заблокировать одновременную модификацию во время миграции базы данных, мой подход заключается в блокировке существующей таблицы t (prereq) с использованием SELECT ... FOR UPDATE и достижения миграции во время блокировки.SELECT FOR UPDATE для блокировки базы данных во время миграции

Таким образом, я создал простой образец, как следующее:

Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/testdb", "root", ""); 

conn.setAutoCommit(false); 
statement = conn.createStatement(); 
ResultSet rs = statement.executeQuery("SELECT id FROM t FOR UPDATE"); 
rs.next(); 
System.out.println(rs.getInt(1)); 

System.out.println("Sleeping..."); 
Thread.sleep(10000); 

statement.executeUpdate("CREATE TABLE t2 (id int PRIMARY KEY)"); 
// Release lock 
statement.executeUpdate("UPDATE t SET id = 2 WHERE id = 1"); 

conn.commit(); 

statement.close(); 
conn.close(); 

t, где находится фиктивный таблица с только id int PRIMARY KEY.

Я установил Thread.sleep(10000);, чтобы имитировать длительный процесс. Во время Thread.sleep(10000); я бегу второй (аналогичный кусок кода) для имитации параллелизм

Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/testdb", "root", ""); 

Statement statement = conn.createStatement(); 
conn.setAutoCommit(false); 
statement = conn.createStatement(); 
ResultSet rs = statement.executeQuery("SELECT id FROM t FOR UPDATE"); 
rs.next(); 
System.out.println(rs.getInt(1)); 

conn.commit(); 

statement.close(); 
conn.close(); 

Но я ожидал, что код печати 2 .. напечатанное 1.

Когда я проверять MySQL общего журнал я вижу, что вещь

438 Query SET autocommit=0 
438 Query SELECT id FROM t FOR UPDATE 
439 Query /* mysql-connector-java-5.1.35 (Revision: 5fb9c5849535c13917c2cf9baaece6ef9693ef27) */SHOW VARIABLES WHERE Variable_name ='language' OR Variable_name = 'net_write_timeout' OR Variable_name = 'interactive_timeout' OR Variable_name = 'wait_timeout' OR Variable_name = 'character_set_client' OR Variable_name = 'character_set_connection' OR Variable_name = 'character_set' OR Variable_name = 'character_set_server' OR Variable_name = 'tx_isolation' OR Variable_name = 'transaction_isolation' OR Variable_name = 'character_set_results' OR Variable_name = 'timezone' OR Variable_name = 'time_zone' OR Variable_name = 'system_time_zone' OR Variable_name = 'lower_case_table_names' OR Variable_name = 'max_allowed_packet' OR Variable_name = 'net_buffer_length' OR Variable_name = 'sql_mode' OR Variable_name = 'query_cache_type' OR Variable_name = 'query_cache_size' OR Variable_name = 'license' OR Variable_name = 'init_connect' 
439 Query /* mysql-connector-java-5.1.35 (Revision: 5fb9c5849535c13917c2cf9baaece6ef9693ef27) */SELECT @@session.auto_increment_increment 
439 Query SET character_set_results = NULL 
439 Query SET autocommit=1 
439 Query SET sql_mode='NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES' 
439 Query SET autocommit=0 
439 Query SELECT id FROM t FOR UPDATE 
438 Query CREATE TABLE t2 (id int PRIMARY KEY) 
439 Query commit 
439 Query rollback 
439 Quit  
438 Query UPDATE t SET id = 2 WHERE id = 1 
438 Query commit 
438 Query rollback 

После CREATE TABLE t2... сделки (сессия 2) поручена эта блокировка выпуска, но я в autoCommit(false) почему MySQL сила commit на этом.

я могу также missunderstand как SELECT ... FOR UPDATE работы ...


UPDATE: испытываться без Java и JDBC с использованием MySQL клиенту

SESSION1> CREATE TABLE t (id int PRIMARY KEY) ENGINE=INNODB; 
SESSION1> INSERT INTO t VALUES (1); 
SESSION1> BEGIN; 
SESSION1> SELECT id FROM t FOR UPDATE; 

SESSION2> BEGIN; 
SESSION2> SELECT id FROM t FOR UPDATE; 
--> HERE SESSION2 is stuck (expected behavior) 

SESSION1> CREATE TABLE t2 (id int PRIMARY KEY) ENGINE=INNODB; 
--> HERE SESSION2 is unlock returning 
+----+ 
| id | 
+----+ 
| 1 | 
+----+ 
1 row in set (4.15 sec) 

кажется, SELECT ... FOR UPDATE с DLL заявление не работает как я ожидал

ответ

0

Наконец это невозможно создать DLL заявление, как CREATE TABLE во время эксклюзивной блокировки (SELECT ... FOR UPDATE).

Однако для выполнения своих задач я буду использовать ту же стратегию, что и flyway.Действительно пролетный путь использует две сессии:

  1. Метастабильной сессии для блокировки (Метастабильный являются основным столом для пролета) сессии
  2. Объекта для выполнения миграции

Таким образом, с различным механизмом блокирования сеанса работы, может быть смоделирована с использованием mysql cli

SESSION-METATABLE> CREATE TABLE t (id int PRIMARY KEY) ENGINE=INNODB; 
SESSION-METATABLE> INSERT INTO t VALUES (1); 
SESSION-METATABLE> BEGIN; 
SESSION-METATABLE> SELECT id FROM t FOR UPDATE; 

SESSION-CONCURRENT> BEGIN; 
SESSION-CONCURRENT> SELECT id FROM t FOR UPDATE; 
--> HERE SESSION-CONCURRENT is stuck (expected behavior) 

SESSION-OBJECT> BEGIN; 
SESSION-OBJECT> CREATE TABLE t2 (id int PRIMARY KEY); 
--> HERE SESSION-CONCURRENT is not unlock 
SESSION-OBJECT> COMMIT; 
--> SESSION-CONCURRENT still stuck even after COMMIT; 

SESSION-METATABLE>UPDATE t SET id=2 WHERE id=1; 
SESSION-METATABLE>COMMIT; 
--> HERE SESSION-CONCURRENT is unlock and print 
+----+ 
| id | 
+----+ 
| 2 | 
+----+ 
1 row in set (23.33 sec) 
0

Вы будете наблюдать за этим поведением, если ваш механизм хранения i s MyISAM. MyISAM не поддерживает транзакции, в результате ваш первый код не будет помещать какие-либо блокировки, так как все операторы автоматически фиксируются, поэтому ваш второй код будет с удовольствием проплывать через свой собственный SELECT FOR UPDATE и перейти непосредственно к SELECT ID.

Короткий рассказ: переведите свою базу данных в хранилище InnoDB, чтобы она работала.

Ссылки:

https://dev.mysql.com/doc/refman/5.0/en/myisam-storage-engine.html

https://dev.mysql.com/doc/refman/5.5/en/innodb-storage-engine.html

+0

Да, но обе таблицы используют innodb. И второй 'SELECT FOR UPDATE' действительно застревает во время' Thread.sleep' до первого сеанса create table – Kakawait

+0

Я только что редактировал мой вопрос, чтобы добавить дополнительную информацию. И я использую innodb (принудительный пример mysql cli), это по умолчанию для моего MySQL 5.6 – Kakawait

Смежные вопросы