使用 JDBC 插入 PostgreSQL 时间类型时出错

Posted

技术标签:

【中文标题】使用 JDBC 插入 PostgreSQL 时间类型时出错【英文标题】:Error inserting into PostgreSQL time type using JDBC 【发布时间】:2012-02-11 21:27:52 【问题描述】:

我在 postgres 数据库中有一个具有“没有时区的时间”数据类型的表,在尝试使用准备好的语句插入时出现语法错误。我尝试创建一个新的 java.sql.Time 对象,而不是使用来自网页的输入,但我仍然遇到同样的错误。我做错了什么?

错误:

org.postgresql.util.PSQLException: ERROR: invalid input syntax for type time: "1970-01-01 +01:00:00"

表:

                                     Table "public.reservation"
   Column   |          Type          |                          Modifiers
------------+------------------------+--------------------------------------------------------------
 res_id     | integer                | not null default nextval('reservation_res_id_seq'::regclass)
 cust_id    | character varying(50)  | not null
 date       | date                   | not null
 time       | time without time zone | not null
 num_people | integer                | not null
Indexes:
    "reservation_pkey" PRIMARY KEY, btree (res_id)
Foreign-key constraints:
    "reservation_cust_id_fkey" FOREIGN KEY (cust_id) REFERENCES customer(cust_id)
Referenced by:
    TABLE "reservation_table" CONSTRAINT "reservation_table_res_id_fkey" FOREIGN KEY (res_id) REFERENCES reservation(res_id)

预订Java:

 public static boolean createReservation(String custID, Date date, Time time, int numPeople) throws ServletException 

    //TODO add checking
    //TODO need to add determing table and if reservation time is free

    boolean succeeded = false;

    //checks if reservation is possible to be booked
    if(checkReservationPossible())

        //convet date to correct format for database
        //SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd");
        //String formattedDate = dateFormatter.format(date);

        //convert time to correct format for database
        //SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm");
        //String formattedTime = timeFormatter.format(time);

        DatabaseAccess db = new DatabaseAccess();
        String sql = "INSERT INTO reservation (cust_id, date, time, num_people)"
                + "VALUES (?,?,?,?)";

        LinkedList<Object> params = new LinkedList<Object>();
        params.add(custID);
        params.add(date);
        params.add(time);
        params.add(numPeople);

        succeeded = db.runUpdateQuery(sql,params);

        db.close();
    

    return succeeded;

数据库访问 Java:

public boolean runUpdateQuery(String sql, LinkedList<Object> params) throws ServletException

    // Using try ... catch ... for error control
    try
        // Create a statement variable to be used for the sql query
        //Statement statement = this.connection.createStatement();

        // Perform the update

        PreparedStatement pst = this.connection.prepareStatement(sql);

        Iterator iter = params.iterator();

        for(int i = 1;iter.hasNext(); i++)
            Object curr = iter.next();
            //TODO may need to add more for different types
            if(curr instanceof String)
                pst.setString(i, curr.toString());
            else if (curr instanceof Integer)
                pst.setInt(i, (Integer)curr);
            else if (curr instanceof java.util.Date)
                //convert to sql date
                java.util.Date tempDate = (java.util.Date)curr;
                java.sql.Date sqlDate = new java.sql.Date(tempDate.getTime());
                pst.setDate(i, sqlDate);
            else if (curr instanceof Time)
                pst.setTime(i, Time.valueOf("11:30:00"));
            
        

        int numRows = pst.executeUpdate();

        pst.close();

        if(numRows > 0)
            return true;
        else
            return false;
        
     catch (SQLException e)
        // Deal with the error if it happens
        throw new ServletException(String.format("Error: Problem running query... "), e);
    

【问题讨论】:

对于它的价值,我看不出你的代码有什么问题。确保您导入的是 java.sql.Time,而不是其他类。 【参考方案1】:

您不需要所有这些检查。我建议您将代码更改为:

for (int i = 1; iter.hasNext(); i++) 
    Object curr = iter.next();    
    pst.setObject(i, curr);

JDBC 知道如何处理所有各种常用的 java 类型 - 无需转换。

您需要检查类型的唯一时间是如果您想使用一些自定义类并且想从中获取一些符合 JDBC 的类型。这不是这里的情况。

【讨论】:

@Chris 你试过了吗?另外,您的 JDBC 驱动程序是您的数据库服务器版本的正确版本吗?我知道这段代码有效,因为我已经在 postgres 中使用过它并且它有效。 我有,我创建了另一个没有时间字段的表,以确保它正常工作。我不知道服务器上的版本,但我使用的是 8.3-603。 只是确认 - 所以你尝试只使用 setObject() 方法,就像我建议的代码一样? 今天似乎在工作,不知道我之前做错了什么,但谢谢:) 时间不早了:P 没有做所有检查修复了我完全相同的问题 +1【参考方案2】:

我认为问题在于 java 正在发送日期和时间,而不仅仅是时间。解决此问题的一个好方法是创建一个派生自 Time 的类并覆盖 toString() 方法,JDBC 内部使用该方法将 ? 替换为参数值:

public class PosgreSqlTime inherits java.sql.Time

     private static SimpleDateFormat SDF = new SimpleDateFormat("HH:mm:ss:SSS");
     @Override
     public String toString()
     
          return SDF.format(this);
     

【讨论】:

它不会让我将它设置为字符串,因为它需要一个 Time 对象

以上是关于使用 JDBC 插入 PostgreSQL 时间类型时出错的主要内容,如果未能解决你的问题,请参考以下文章

使用 Postgresql JDBC 时,将导致插入 0 行的 INSERT 语句

java.jdbc clojure 执行!插入数量

如果插入语句给出重复键异常(在表中找到行 id=1)如何更新 JDBC(Postgresql)中的语句

Kafka JDBC Sink Connector,批量插入值

如何做批处理 jdbc/insert!和 jdbc/更新!在 Clojure 中使用 postgresql?

Spark SQL - PostgreSQL JDBC 类路径问题