为什么删除SQLite数据库JAR后java.sql.DriverManager.getConnection()仍在工作?
我在Java中使用单独JAR文件中提供的SQLITE数据库时遇到困难。 令人惊讶的是,即使在删除JAR文件、退出并重新启动程序之后,甚至在重新启动机器之后,sqlite数据库似乎也会被访问 我正在使用Xerial驱动程序为什么删除SQLite数据库JAR后java.sql.DriverManager.getConnection()仍在工作?,java,sqlite,jdbc,jar,Java,Sqlite,Jdbc,Jar,我在Java中使用单独JAR文件中提供的SQLITE数据库时遇到困难。 令人惊讶的是,即使在删除JAR文件、退出并重新启动程序之后,甚至在重新启动机器之后,sqlite数据库似乎也会被访问 我正在使用Xerial驱动程序sqlite-jdbc-3.7.2.jar(用于org.sqlite.jdbc)。 编辑:与sqlite-jdbc-3.8.6.jar的问题非常相似。 Xerial JDBC驱动程序发布于此处: 我真的很困惑。这个特定的JDBC驱动程序是否有某种持久缓存?或者是我在JDBC方面
sqlite-jdbc-3.7.2.jar
(用于org.sqlite.jdbc
)。编辑:与
sqlite-jdbc-3.8.6.jar的问题非常相似。
Xerial JDBC驱动程序发布于此处:
我真的很困惑。这个特定的JDBC驱动程序是否有某种持久缓存?或者是我在JDBC方面遗漏了什么
代码示例:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SqliteJDBCTest {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite::resource:jar:file:doesntexistJAR.jar!/doesntexistDB.sqlite");
System.out.println("connection = " + connection);
statement = connection.createStatement();
System.out.println("statement = " + statement);
rs = statement.executeQuery(" SELECT * FROM nonexistentTable WHERE key = 'nonexistentKey'");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
上面的代码示例显示了问题的第一步:在第一次运行时,DriverManager.getConnection(..)
按预期抛出异常:
$ java -jar sqliteJDBCTest.jar
java.sql.SQLException: failed to load jar:file:doesntexistJAR.jar!/doesntexistDB.sqlite: java.io.FileNotFoundException: doesntexistJAR.jar (Aucun fichier ou dossier de ce type)
at org.sqlite.Conn.open(Conn.java:92)
at org.sqlite.Conn.<init>(Conn.java:57)
at org.sqlite.JDBC.createConnection(JDBC.java:77)
at org.sqlite.JDBC.connect(JDBC.java:64)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at SqliteJDBCTest.main(SqliteJDBCTest.java:18)
在本例中,SQLException
“SQL错误或缺少数据库”不是我们期望的错误
不仅数据库丢失了,甚至连应该包含它的JAR文件也丢失了!
那么为什么getConnection()
一开始就不会抛出异常呢?简单回答:因为Xerial JDBC驱动程序中有一个bug
当通过调用DriverManager.getConnection(jdbc:sqlite::resource:jar:file:!/)
向Xerial驱动程序请求连接时,驱动程序在Java系统属性Java.io.tmpdir
指定的临时目录上创建数据库文件的副本,然后对该副本进行操作
问题是,当原始JAR被移除时,驱动程序在下次使用相同的getConnection()
调用时加载副本。对我来说,这是一个错误;驱动程序至少应该检查URL指向的(可能是远程)JAR文件是否仍然存在
第二个问题(本文代码示例中描述的问题):当原始JAR文件不存在时,将创建(不存在的)数据库的“副本”,下次使用相同的参数调用getConnection(),驱动程序直接返回一个到这个空数据库的虚拟连接,而这个空数据库从未找到
我在Xerial JIRA网站上的bug报告中提交了这个故事:
您是否尝试过在数据库中插入内容,并在下次尝试时将其读回?如果这是可行的,DB是在某处创建的。是的,我有。然后,在删除数据库后,我仍然可以看到我插入的内容。注意:我使用Sourceforge的sqlite db编辑器在我的应用程序之外手动插入了JAR文件。很明显,JAR文件或它的另一个版本在类路径上的某个地方仍然可用。但是JAR已从文件系统中正确删除。所以我真的很困惑,Java已经向您保证它仍然找到了一个。继续找。
>java -jar sqliteJDBCTest.jar
connection = org.sqlite.Conn@3fee733d
statement = org.sqlite.Stmt@5acf9800
java.sql.SQLException: [SQLITE_ERROR] SQL error or missing database (no such table: nonexistentTable)
at org.sqlite.DB.newSQLException(DB.java:383)
at org.sqlite.DB.newSQLException(DB.java:387)
at org.sqlite.DB.throwex(DB.java:374)
at org.sqlite.NativeDB.prepare(Native Method)
at org.sqlite.DB.prepare(DB.java:123)
at org.sqlite.Stmt.executeQuery(Stmt.java:121)
at SqliteJDBCTest.main(SqliteJDBCTest.java:23)