sqlite preparedstatement最终确定

时间:2016-10-21 20:06:26

标签: java sqlite

我有一个错误 java.sql.SQLException:准备好的语句已经完成 当我第二次调用相同的preparedStatement时会发生这种情况。我在一种方法中称呼它。

这是数据库Java类(相关部分)

//create the charge table. (ps is PreparedStatement)
try{
   statement.executeUpdate("CREATE TABLE charge(username TEXT NOT NULL, date DATETIME DEFAULT CURRENT_TIMESTAMP, charge REAL, PRIMARY KEY(username, date));");
} catch (SQLException ex) {
   System.out.println("charge table creation failed. exception" + ex);
}

创建费用的方法:

 public void createCharge(String username, double amount){
    try {
        System.out.println(username + amount);

        ps = connection.prepareStatement("INSERT INTO charge VALUES(?, ?, ?);");
        ps.setString(1, username);
        ps.setDate(2, DateConvert.toSQLDate(Date.valueOf(LocalDate.MIN)));
        ps.setDouble(3, amount);
        ps.executeUpdate();
        ps.clearParameters();

        System.out.println("Complete");

    } catch (SQLException ex) {
        Logger.getLogger(MontsRentalDatabase.class.getName()).log(Level.SEVERE, null, ex);
    }
}

这是在创建费用的类中:

public void createCharge(String username, double amount){
    try {
        System.out.println(username + amount);

        ps = connection.prepareStatement("INSERT INTO charge VALUES(?, ?, ?);");
        ps.setString(1, username);
        ps.setDate(2, DateConvert.toSQLDate(Date.valueOf(LocalDate.MIN)));
        ps.setDouble(3, amount);
        ps.executeUpdate(); //Line 170
        ps.clearParameters();

        System.out.println("Complete");

    } catch (SQLException ex) {
        Logger.getLogger(MontsRentalDatabase.class.getName()).log(Level.SEVERE, null, ex);
    }
}

将普通日期转换为sqldate的类:     公共类DateConvert {

public static java.sql.Date toSQLDate(java.util.Date date){
    return new java.sql.Date(date.getTime());
}

public static java.util.Date toJavaDate(java.sql.Date date){
    return new java.util.Date(date.getTime());
}
}

错误在创建费用的第170行,即ps.executeUpdate运行时。第一次运行成功,第二次运行失败。 经度:

450100.0
Complete
450150.0
SEVERE: null
java.sql.SQLException: The prepared statement has been finalized
    at org.sqlite.core.NativeDB.throwex(NativeDB.java:429)
    at org.sqlite.core.NativeDB.reset(Native Method)
    at org.sqlite.core.DB.executeUpdate(DB.java:878)
    at org.sqlite.jdbc3.JDBC3PreparedStatement.executeUpdate(JDBC3PreparedStatement.java:99)
at server.RentalDatabase.createCharge(RentalDatabase.java:170)

感谢您的帮助, Ĵ

2 个答案:

答案 0 :(得分:7)

我认为这是SQLite JDBC驱动程序3.14.2.1版中的一个错误。

在我看来,你正在获得一个唯一的约束违规异常,但是SQLite JDBC驱动程序试图报告这个异常并试图报告这个异常而引起攻击。

如果我尝试多次插入相同的数据,我可以使用sqlite-jdbc版本3.14.2.1重现您的异常,例如通过重新运行您的代码。我将SQLite JDBC驱动程序降级到3.8.11.2,运行代码后出现以下异常:

java.sql.SQLException: [SQLITE_CONSTRAINT]  Abort due to constraint violation (UNIQUE constraint failed: charge.username, charge.date)
    at org.sqlite.core.DB.newSQLException(DB.java:890)
    at org.sqlite.core.DB.newSQLException(DB.java:901)
    at org.sqlite.core.DB.execute(DB.java:810)
    at org.sqlite.core.DB.executeUpdate(DB.java:847)
    at org.sqlite.jdbc3.JDBC3PreparedStatement.executeUpdate(JDBC3PreparedStatement.java:86)
    at com.example.MontsRentalDatabase.createCharge(MontsRentalDatabase.java:40)
    at com.example.Main.main(Main.java:17)

当然,重新运行程序时,我试图插入的数据已经在表中了。因此,可以预期唯一的约束违规。

然后我添加了一行

        statement.execute("DROP TABLE IF EXISTS charge");

createChargeTable(),位于创建表格的行上方。然后使用任一版本的SQLite JDBC驱动程序多次成功运行代码。

此错误现已在sqlite-jdbc 3.15.1版本中修复,因此修复程序将升级到此版本或更高版本。

答案 1 :(得分:-2)

创建预准备语句后,应关闭它并不再使用它。我在你的代码中没有看到它,但你说:"当我第二次调用相同的preparedStatement时会发生这种情况"。 你的' ps'变量应该是一个局部变量,在try-with-resource块中声明,例如:

  try (PreparedStatement ps = connection.prepareStatement("INSERT INTO charge VALUES(?, ?, ?);")) {
        ps.setString(1, username);
        ps.setDate(2, DateConvert.toSQLDate(Date.valueOf(LocalDate.MIN)));
        ps.setDouble(3, amount);
        ps.executeUpdate(); //Line 170
        ps.clearParameters();
        System.out.println("Complete");
  }

这样一来,它就无法在关闭后使用。