Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 选择更新以在迁移期间锁定数据库_Java_Mysql_Sql_Jdbc_Transactions - Fatal编程技术网

Java 选择更新以在迁移期间锁定数据库

Java 选择更新以在迁移期间锁定数据库,java,mysql,sql,jdbc,transactions,Java,Mysql,Sql,Jdbc,Transactions,我试图在数据库迁移期间阻止并发修改,我的方法是使用SELECT锁定现有表t(prereq)。。。用于更新,并在锁定期间实现迁移 因此,我创建了一个简单的示例,如下所示: Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/testdb", "root", ""); conn.setAutoCommit(false); statement = conn.createStatement(); Resu

我试图在数据库迁移期间阻止并发修改,我的方法是使用
SELECT锁定现有表
t
(prereq)。。。用于更新
,并在锁定期间实现迁移

因此,我创建了一个简单的示例,如下所示:

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主键的伪表

我设置了一个
线程。sleep(10000)以模拟长流程。在
线程睡眠期间(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
创建表t2之后…
事务(会话2)被提交以释放锁,但我在
自动提交(false)
为什么MySQL强制
提交

我可能也不明白如何选择
。。。对于更新
works


更新:使用mysql客户端在没有Java和JDBC的情况下测试

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)

似乎是
选择了。。。对于UPDATE
,with DLL语句不能像我预期的那样工作

如果您的存储引擎是MyISAM,您将观察到这种行为。MyISAM不支持事务,因此,您的第一个代码不会设置任何锁,因为所有语句都是自动提交的,所以您的第二个代码将愉快地游过它们自己的SELECT FOR UPDATE并直接进入SELECT ID

长话短说:将数据库切换到InnoDB存储以使其正常工作

参考资料:


最后,在独占锁定期间不可能创建类似于
创建表
的DLL语句(
选择…进行更新

然而,为了满足我的需求,我将使用与之相同的策略。实际上,flyway使用两个会话:

  • 要锁定的元表会话(元表是flyway的核心表)
  • 要执行迁移的对象会话
  • 因此具有不同会话锁定机制的作品,可以用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)
    

    是的,但两个表都使用innodb。第二个
    SELECT FOR UPDATE
    Thread.sleep
    过程中被卡住了,直到第一个会话创建表我才编辑我的问题来添加更多信息。我正在使用innodb(在mysql cli示例中强制使用),这是mysql 5.6上的默认设置