删除SQLite数据库JAR后,为什么java.sql.DriverManager.getConnection()仍然有效?

时间:2014-11-26 20:59:42

标签: 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驱动程序在这里发布: https://bitbucket.org/xerial/sqlite-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)

但是,从那以后,每次运行我得到以下输出:

>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)

在此示例中,SQLException&#34; SQL错误或缺少数据库&#34;这不是我们期待的错误!

不仅缺少数据库,而且甚至JAR文件都应该包含它! 那么getConnection()怎么不首先抛出异常呢?

1 个答案:

答案 0 :(得分:1)

简短回答:因为Xerial JDBC驱动程序中存在错误。

当通过调用DriverManager.getConnection(jdbc:sqlite::resource:jar:file:<local_location_of_JAR>!/<name_of_database_file>)请求Xerial驱动程序建立连接时,驱动程序会在Java系统属性 {{指定的临时目录上创建数据库文件的副本。 1}} 然后对此副本进行操作。

问题在于,当删除原始JAR时,驱动程序会在下次使用相同java.io.tmpdir调用时加载副本。对我来说,这是一个错误;驱动程序至少应该检查URL指向的(可能是远程的)JAR文件是否仍然存在...

第二个问题(本文的CODE SAMPLE中描述的问题):当原始JAR文件不存在时,创建(不存在的)数据库的“ copy ”,并且使用相同的参数调用下一次getConnection()时,驱动程序直接返回一个幻像连接到这个从未找到的空数据库......

我在Xerial JIRA网站的错误报告中提交了这个故事: https://bitbucket.org/xerial/sqlite-jdbc/issue/158/drivermanagergetconnection-not-returning