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

Posted

技术标签:

【中文标题】为啥hibernate关闭连接后h2的数据库文件仍然会被锁定一段时间?【英文标题】:Why could database files of h2 be still locked for some time after hibernate closes connection?为什么hibernate关闭连接后h2的数据库文件仍然会被锁定一段时间? 【发布时间】:2021-11-10 13:51:14 【问题描述】:

在为我的应用程序编写 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 https://mvnrepository.com/artifact/commons-io/commons-io/2.11.0 中的 FileUtils.copyDirectoryToDirectory() 方法。

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:进程无法访问文件 因为另一个进程锁定了文件的一部分

disconnect() 完成后,没有更多与数据库的连接。

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

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

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

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

我在连接中使用的 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");

【问题讨论】:

您使用连接池 (C3P0),它将保持连接打开(我不确定在这种情况下 C3P0 是否也被释放,但这可能会在实际关闭时引入额外的延迟)。如果您将 DB_CLOSE_DELAY 设置为 0 以外的任何值,还要检查您的 JDBC URL 或连接属性。 【参考方案1】:

这个问题不是由 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 类,应该使用它来代替 HikariCP 实现。该类称为 org.hibernate.hikaricp.internal.HikariCPConnectionProvider” em>

【讨论】:

以上是关于为啥hibernate关闭连接后h2的数据库文件仍然会被锁定一段时间?的主要内容,如果未能解决你的问题,请参考以下文章

为啥人们继续使用 xml 映射文件而不是注释? [关闭]

连接关闭后 H2 模式消失

即使关闭连接后,数据仍然存在于h2数据库表中

Java Hibernate - 无法连接到 H2

为啥我们的 Spring/Hibernate/JDBC/Websphere 系统中的连接过早关闭?

Ace oledb连接关闭文件仍在使用中错误