H2交易总是自动提交为什么?

时间:2019-10-02 12:15:16

标签: java transactions h2

我的应用程序只有Java和Maven(没有其他框架)

在pom.xml中,我对H2数据库有依赖性:

 <dependencies>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.199</version>
        </dependency>
    </dependencies>

我以这种方式创建了一个连接,您可以看到我将autocommit设置为false。并且我的H2数据库在内存中。

public class ConnectionManager {

    public static Connection getConnectionManager() throws SQLException {

        Properties myProp = new Properties();
        myProp.put("user"    , "sa");
        myProp.put("password", "");
        myProp.put("autocommit", "false");

       return DriverManager.getConnection("jdbc:h2:mem:test", myProp);
    }

    public static void closeConnection(Connection connection) throws SQLException {
        connection.close();
    }

}

我创建了示例表:

public class InitDatabaseManager {

        private static final String CREATE_TABLE_SQL =
                "CREATE TABLE IF NOT EXISTS users ("
                + "ID INT NOT NULL AUTO_INCREMENT,"
                + "EMAIL VARCHAR(45) NOT NULL,"
                + "PRIMARY KEY (ID))";

        private static final String DROP_TABLE_USERS = "drop table if exists users;";

        public static void initStarterTable (Connection connection) throws SQLException {
            Statement stmt = connection.createStatement();
            stmt.executeUpdate(DROP_TABLE_USERS);
            stmt.executeUpdate(CREATE_TABLE_SQL);
        }
    }

我的问题是,为什么在下面的代码中,尽管我禁用了自动提交,但我还是插入了H2数据库中的记录?

 public static void insertUsers(Connection connection) throws SQLException {

    connection.setAutoCommit(false);

    System.out.println("[INSERT]");

    String sqlInsert1 = "INSERT INTO users (email) VALUES ('user@mail.com');";
    PreparedStatement psInsert = connection.prepareStatement(sqlInsert1);

    System.out.println(connection.getAutoCommit());

    psInsert.execute();
    psInsert.close();

}

2 个答案:

答案 0 :(得分:0)

执行INSERT命令时,它会将指定的行插入到表中。该行仅对执行此操作的事务可见,而对其他事务(如果它们使用默认的“读取已提交”隔离级别)则不可见。在隐式(由于自动提交)或显式手动提交之后,插入的行对于所有事务都是可见的。如果您回滚事务而不是提交,则该行会消失。

其他数据修改操作以相同的方式工作。未提交的更改仅对执行它们的事务可见,已提交的更改对所有人可见。

交易的隔离级别不同,但是H.2的默认存储引擎在1.4.199中尚不支持它们(1.4.200中包含这种支持)。

每个JDBC连接都有自己的会话,并且这个会话有自己的事务。我猜您使用相同的连接来读取插入的数据,因此它可以看到未提交的行。如果您不想看到它们,请使用其他连接。

H2中的数据定义命令(例如CREATE TABLE)通常会导致隐式提交,有关详细信息,请参阅H2文档。

答案 1 :(得分:0)

我添加了两个连接,然后更改了隔离级别,我的问题是为什么第二个事务看不到由第一个事务完成的更改。第一个事务未提交更改,因此,如果事务隔离级别为TRANSACTION_READ_UNCOMMITTED,则第二个事务应已看到第一个事务的更改。

我知道:

H2仅支持三个隔离级别;读未提交,读已提交和可序列化,只能在连接级别设置(不能按事务设置)。默认值为已提交读。

public class StartUseCases {

    private static Connection connection;

    private static Connection connection2;

    public StartUseCases() {
        try {

            connection = ConnectionManager.getConnectionManager();
            connection.setAutoCommit(false);
            connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);

            connection2 = ConnectionManager.getConnectionManager();
            connection2.setAutoCommit(false);
            connection2.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);

            InitDatabaseManager.initStarterTable(connection);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws SQLException {

        // init tables
        new StartUseCases();

        CRUD.getAllUsers(connection);
        CRUD.insertUsers(connection2);
        CRUD.getAllUsers(connection);
    }

}