java - 打开 JDBC 连接后无法移动 MS Access 文件

标签 java jdbc spring-boot spring-batch ucanaccess

我有一个 Spring Batch 作业正在读取指定的 Access 数据库文件。我正在使用 uncanaccess JDBC 库来执行此操作。一旦作业退出,无论作业是否成功完成,我都需要让我的应用程序将访问文件移动到另一个文件夹。目前,我收到一个 java.nio.file.FileSystemException ,表明它无法移动,因为它已被另一个进程使用。我假设其他进程是由于 JDBC 连接已打开而导致的。

Exception in thread "main" com.mycompany.weeklyimport.FileException: Failed to move file [C:\temp\hold\temp.mdb] to [C:\temp\error\temp.mdb]
    at com.mycompany.weeklyimport.WeeklyImportApplication.moveFile(WeeklyImportApplication.java:365)
    at com.mycompany.weeklyimport.WeeklyImportApplication.main(WeeklyImportApplication.java:91)
Caused by: java.nio.file.FileSystemException: C:\temp\hold\temp.mdb -> C:\temp\error\temp.mdb: The process cannot access the file because it is being used by another process.

    at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
    at sun.nio.fs.WindowsFileCopy.move(WindowsFileCopy.java:387)
    at sun.nio.fs.WindowsFileSystemProvider.move(WindowsFileSystemProvider.java:287)
    at java.nio.file.Files.move(Files.java:1395)
    at com.mycompany.weeklyimport.WeeklyImportApplication.moveFile(WeeklyImportApplication.java:363)
    ... 1 more

这是我的主程序(通过 Spring Boot 运行 Spring 作业):

@SpringBootApplication
@EnableBatchProcessing
@Slf4j
public class WeeklyImportApplication extends DefaultBatchConfigurer {
    ...
    private static String inputFile;
    private static boolean exceptionEncountered = false;

    public static void main(String[] args) throws Throwable {
        handleArguments(args);

        ConfigurableApplicationContext context = new SpringApplicationBuilder(WeeklyImportApplication.class).listeners(new CustomLoggingConfigurationApplicationListener(logConfigurer)).run(args);

        if (exceptionEncountered) {
            moveFile("error");
        } else {
            moveFile("complete");
        }

        finished();
    }

    private static void moveFile(String folderName) {
        File file = new File(inputFile);
        File newPath = new File(file.getParentFile().getParentFile().getPath() + File.separator + folderName);

        if (!newPath.exists()) {
            if (!newPath.mkdirs()) {
                throw new FileException("Failed to create folder [" + newPath.getPath() + "]");
            }
        }

        File newFile = new File(newPath.getPath() + File.separator + file.getName());

        try {
            Files.move(file.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException ex) {
            throw new FileException("Failed to move file [" + file.getPath() + "] to [" + newFile.getPath() + "]", ex);
        }
    }

    ...

我的数据源配置。我还分配给一个静态变量,以便在 Spring 退出后尝试关闭连接。

@Configuration
public class DataSourceConfiguration {

    public static SingleConnectionDataSource legacyDataSource;

    @Bean(name = "importDataSource")
    public DataSource importDataSource() {
        SingleConnectionDataSource dataSource = new SingleConnectionDataSource();
        dataSource.setDriverClassName(this.importDriver.trim());
        dataSource.setSuppressClose(true);
        dataSource.setUrl("jdbc:ucanaccess://" + WeeklyImportApplication.getInputFile());

        return dataSource;
    }

    ...

我尝试过以下方法:

    DataSourceConfiguration.legacyDataSource.getConnection().close();
    DataSourceConfiguration.legacyDataSource.destroy();
    DataSourceConfiguration.legacyDataSource = null;

不知何故,某些东西仍然锁定了该文件。有没有人遇到过类似的事情或者对如何强制真正关闭文件读取有任何想法?

已解决

jamadei 下面的回答帮助我找到了这个解决方案。相关解决方案代码:

@Bean(name = "importDataSource")
public DataSource importDataSource() {
    SingleConnectionDataSource dataSource = new SingleConnectionDataSource();
    dataSource.setDriverClassName(this.importDriver.trim());
    dataSource.setSuppressClose(true);
    dataSource.setUrl("jdbc:ucanaccess://" + WeeklyImportApplication.getInputFile() + ";SingleConnection=true");

    importDataSource = dataSource;

    return dataSource;
}

public static void main(String[] args) throws Throwable {
    handleArguments(args);

    new SpringApplicationBuilder(WeeklyImportApplication.class).listeners(new CustomLoggingConfigurationApplicationListener(logConfigurer)).run(args);

    DataSourceConfiguration.importDataSource.setSuppressClose(false);
    DataSourceConfiguration.importDataSource.destroy();

    if (exceptionEncountered) {
        moveFile("error");
        System.exit(1);
    } else {
        moveFile("complete");
    }

    finished();
}

最佳答案

这不仅仅是 Spring 的问题,而且是 UCanAccess 优化/缓存的副作用。 你所做的似乎不错,但还不够。 在 jdbc url 中使用 SingleConnection=true 参数应该可以解决该问题。

关于java - 打开 JDBC 连接后无法移动 MS Access 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28611721/

相关文章:

spring - 如何使用 Spring Cloud Security 实现 OAuth2 "Token Exchange"

java - 将 JDBC ResultSet 转换为泛型类型?

java - 如何在一个类中为不同的测试获取不同的上下文?

java - 使用 ant 启动 fork 的 java 进程

java - XSD : Large schema validation

mysql - JDBC 和 Hibernate 查询性能缓慢(与 PhpMyAdmin 相比)

ssl - 如何在 Spring 中通过数据库配置 SSL?

java - Spring调度不运行多线程

java - Gradle 中的 Sun JPEGImageEncoder 编译

java - 构建后的 Gradle 复制任务