【问题标题】:Can't move MS Access file after opening JDBC connection on it打开 JDBC 连接后无法移动 MS Access 文件
【发布时间】:2015-04-21 02:43:05
【问题描述】:

我有一个 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();
}

【问题讨论】:

    标签: java jdbc spring-boot spring-batch ucanaccess


    【解决方案1】:

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

    【讨论】:

    • 这帮助我找到了解决方案。我无意中在上述问题中发布了错误的数据源,因此我进行了编辑和更正。我正在做的另一件事是将DataSource 上的setSuppressClose 选项设置为true。一旦我设置删除该语句并将您建议的参数应用于 URL,然后我就可以在我的应用程序中移动文件。感谢您的帮助。
    • 作为后续,一旦我将我抛出的异常用于测试目的,我遇到了从 Spring 抛出的异常,因为数据源在后续步骤中被关闭,也需要该数据源,所以我不得不将suppress close 设置回true。我在关闭应用程序时解决了这个问题,方法是将其设置回 false,然后在执行文件移动之前在数据源上调用 destroy()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    • 2019-06-10
    • 2020-08-07
    • 1970-01-01
    相关资源
    最近更新 更多