为什么hibernate关闭连接后,h2的数据库文件仍然会锁定一段时间?

Why could database files of h2 be still locked for some time after hibernate closes connection?

在为我的应用程序编写 JUnit 测试时,我遇到了一个问题,当我关闭 EntityManagerEntityManagerFactory 时,它需要一些时间才能完成,而且我无法复制数据库 (H2) 文件夹。

让我更详细地解释一下:

这是我的单个 JUnit 测试中的内容(我只是在 DatabaseManager 上调用这个静态方法):

DatabaseManager.createBackupNoAlert(new File(DatabaseManager.getConnectedDatabasePath()), new File(TESTDBBACKUPPATH));

这里两个文件都不为空,并且使用 EntityManagerEntityManagerFactory.

成功创建了数据库连接

createBackupNoAlert方法:

public static void createBackupNoAlert(final File actualDb, final File destination)
{
    try
    {
        if (!destination.exists())
        {
            destination.mkdir();
        }
        DatabaseManager.disconnect();
        FileUtils.copyDirectoryToDirectory(actualDb, destination);
        String now = LocalDateTime.now().toString();
        now = now.substring(0, now.indexOf('.')).replaceAll(":", "_");
        File newFile = new File(destination.getAbsolutePath() + "\" + now);
        boolean renamedToCurrentDateTime = new File(destination, actualDb.getName()).renameTo(newFile);
        if (!renamedToCurrentDateTime)
        {
            logger.warn("Could not rename backup directory to current datetime");
        }
        DatabaseManager.renewConnection();
    }
    catch (IOException e)
    {
        logger.error(ExceptionUtils.getStackTrace(e));
    }
}

为了复制数据库文件夹,我使用了 commons-io 中的 FileUtils.copyDirectoryToDirectory() 方法 https://mvnrepository.com/artifact/commons-io/commons-io/2.11.0

disconnect方法:

public static void disconnect()
{
    if (entityManager != null && entityManager.isOpen())
    {
        entityManager.close();
    }
    if (entityManagerFactory != null && entityManagerFactory.isOpen())
    {
        entityManagerFactory.close();
    }
    logger.info("Disconnected from db");
}

两个 .close() 方法都被调用。

当此测试为 运行:

FileUtils.copyDirectoryToDirectory(actualDb, destination); 发生异常

java.nio.file.FileSystemException: testdb\testdb.mv.db -> backuptestdb\testdb\testdb.mv.db: The process cannot access the file because another process has locked a portion of the file

disconnect() 完成后,不再有数据库连接。

上述陈述的证明以及我尝试和发现的内容:

当我在 FileUtils.copyDirectory... 和 运行 处插入断点时,在调试模式下测试 (DatabaseManager.createBackupNoAlert()),请稍等,继续,目录已复制,一切正常很好,测试完成。我在想的是 Hibernate 运行s EntityManager.close()EntityManagerFactory.close() 在另一个线程上,在我调用该复制操作之前它没有完成,但在我查看实现之后它没有完成.

此外,当我在 DatabaseManager.disconnect()FileUtils.copyDirectoryToDirectory() 之间插入 Thread.sleep(100) 时,测试完成 OK!

其他人遇到过这个吗?是否有任何修复程序可以让我在关闭数据库连接后立即复制数据库文件夹?

我在连接中使用的 Hibernate 属性:

hibernateProps.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
hibernateProps.put("hibernate.connection.pool_size", "1");
hibernateProps.put("hibernate.connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider");
hibernateProps.put("hibernate.c3p0.min_size", "1");
hibernateProps.put("hibernate.c3p0.max_size", "1");
hibernateProps.put("hibernate.c3p0.acquireRetryAttempts", "3");
hibernateProps.put("hibernate.c3p0.acquireRetryDelay", "400");
hibernateProps.put("hibernate.connection.isolation", String.valueOf(Connection.TRANSACTION_SERIALIZABLE));
hibernateProps.put("javax.persistence.schema-generation.database.action", "create");

此问题不是由 h2 数据库文件锁定引起的 https://www.h2database.com/html/features.html#database_file_locking。尝试使用 FILE_LOCK=SOCKETFILE_LOCK=NO,但没有帮助。 看起来使用 Hikari 连接提供程序而不是 C3P0 解决了我的问题。要使用它,我必须在休眠属性中定义它:

hibernateProps.put("hibernate.connection.provider_class","org.hibernate.hikaricp.internal.HikariCPConnectionProvider");

并在 pom.xml(Maven 项目)中包含依赖项:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-hikaricp</artifactId>
    <version>5.6.1.Final</version>
</dependency>

https://github.com/brettwooldridge/HikariCP

https://github.com/brettwooldridge/HikariCP/wiki/Hibernate4

注意:“从 Hibernate 4.3.6 开始,Hibernate 有一个官方的 ConnectionProvider class,应该使用它来代替 HikariCP 实现。class 被称为org.hibernate.hikaricp.internal.HikariCPConnectionProvider"