Я разрабатываю систему, которая использует объект доступа к базе данных (DAO) для связи между программой и базой данных. Все соединения должны быть сделаны через этот класс, используя getConnection()
. Однако у меня есть опция сброса, которая переопределяет файл базы данных в файловой системе пользователя на файл внутри самого приложения (т. Е. В его jar при развертывании). Эта функция reset()
вызывает исключение, сообщающее, что база данных уже используется.
java.nio.file.FileSystemException: C:\iMProve\improveDB.accdb: The process cannot access the file because it is being used by another process.
С исследованием это означает, что соединения не были закрыты должным образом. Тем не менее, я покажу вам весь код для этого класса DAO, если вы сможете определить, в чем проблема.
public class DAO {
private static final String dbDir = "C://iMProve";
private static final String dbName = "improveDB.accdb";
private static final String dbUrl = "jdbc:ucanaccess://" + dbDir + "//"+ dbName;
private ObservableList<Connection> allConnections = FXCollections.observableArrayList();
public DAO() { //constructor - called when object is made
try {
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
} catch(ClassNotFoundException e) {
System.out.println("Cannot load ucanaccess driver");
e.printStackTrace();
}
File directory = new File(dbDir);
if(!directory.exists()) //create directory if not already
directory.mkdir();
File database = new File(dbDir + "//" + dbName);
if(!database.exists()) { //copy the database file into user's file system - if not already
try {
Files.copy(DAO.class.getResourceAsStream(dbName), database.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch(IOException ex) {ex.printStackTrace();}
}
}
public void reset() {
File database = new File(dbDir + "//" + dbName);
try {
Files.copy(DAO.class.getResourceAsStream(dbName), database.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
}
public Connection getConnection() { //create a connection to the database
Connection conn = null;
try {
conn = DriverManager.getConnection(dbUrl);
} catch (SQLException e) {
e.printStackTrace();
}
allConnections.add(conn);
return conn;
}
public void closeConnections() {
for(Connection conn: allConnections) {
if(conn!=null) {
try {
conn.close();
System.out.println("closed");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Конструктор просто копирует базу данных из приложения в файловую систему пользователя, если ее там еще нет.
Метод getConnection()
подключается к базе данных.
Вызов reset()
сам по себе вызывает эту ошибку, поэтому, добавляя соединения в статическую коллекцию, мы можем закрыть каждое соединение, используя closeConnections()
.
Примечание: Эти соединения уже должны быть закрыты в любом случае, потому что мы всегда пытаемся использовать ресурсы.
Например:
try (
Connection conn = dao.getConnection();
PreparedStatement stmt = conn.prepareStatement("SELECT Title FROM Theory WHERE Grade <= ?");
) {
И хотя у нас есть два уровня для закрытия соединений
- примерочный с-ресурсами
closeConnections()
метод
Они все еще неэффективны. При вызове closeConnections () мы по-прежнему получаем выходные данные
closed
closed
даже когда соединения использовались внутри блоков try-with-resources.
И даже с closeConnections()
, мы все равно получаем ту же ошибку:
java.nio.file.FileSystemException: C:\iMProve\improveDB.accdb: The process cannot access the file because it is being used by another process.