在PreparedStatement中使用setDate

时间:2013-09-04 13:12:27

标签: java sql oracle jdbc prepared-statement

为了使我们的代码更加标准化,我们被要求将我们将SQL变量硬编码的所有位置更改为预处理语句并改为绑定变量。

然而,我遇到setDate()的问题。

以下是代码:

        DateFormat dateFormatYMD = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        DateFormat dateFormatMDY = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        Date now = new Date();
        String vDateYMD = dateFormatYMD.format(now);
        String vDateMDY = dateFormatMDY.format(now);
        String vDateMDYSQL =  vDateMDY ;
        java.sql.Date date = new java.sql.Date(0000-00-00);

   requestSQL = "INSERT INTO CREDIT_REQ_TITLE_ORDER (REQUEST_ID," + 
                " ORDER_DT, FOLLOWUP_DT) " +  "values(?,?,?,)";


                prs = conn.prepareStatement(requestSQL);

                prs.setInt(1,new Integer(requestID));

                prs.setDate(2,date.valueOf(vDateMDYSQL));
                prs.setDate(3,date.valueOf(sqlFollowupDT));

执行SQL时出现此错误:

    java.lang.IllegalArgumentException
    at java.sql.Date.valueOf(Date.java:138)
    at com.cmsi.eValuate.TAF.TAFModuleMain.CallTAF(TAFModuleMain.java:1211)

我应该使用setString()代替to_date()吗?

6 个答案:

答案 0 :(得分:127)

❐使用java.sql.Date

如果您的表格中有DATE类型的列:

  • <强> java.lang.String

    方法java.sql.Date.valueOf(java.lang.String)收到一个字符串,表示格式为yyyy-[m]m-[d]d的日期。 e.g:

    ps.setDate(2, java.sql.Date.valueOf("2013-09-04"));
    
  • <强> java.util.Date

    假设您有endDate类型的变量java.util.Date,则可以进行转换:

    ps.setDate(2, new java.sql.Date(endDate.getTime());
    
  • 当前

    如果要插入当前日期:

    ps.setDate(2, new java.sql.Date(System.currentTimeMillis()));
    
    // Since Java 8
    ps.setDate(2, java.sql.Date.valueOf(java.time.LocalDate.now()));
    

❐使用java.sql.Timestamp

如果您的表格中包含TIMESTAMPDATETIME类型的列:

  • <强> java.lang.String

    方法java.sql.Timestamp.valueOf(java.lang.String)收到一个字符串,表示格式为yyyy-[m]m-[d]d hh:mm:ss[.f...]的日期。 e.g:

    ps.setTimestamp(2, java.sql.Timestamp.valueOf("2013-09-04 13:30:00");
    
  • <强> java.util.Date

    假设您有endDate类型的变量java.util.Date,则可以进行转换:

    ps.setTimestamp(2, new java.sql.Timestamp(endDate.getTime()));
    
  • 当前

    如果您需要当前时间戳:

    ps.setTimestamp(2, new java.sql.Timestamp(System.currentTimeMillis()));
    
    // Since Java 8
    ps.setTimestamp(2, java.sql.Timestamp.from(java.time.Instant.now()));
    ps.setTimestamp(2, java.sql.Timestamp.valueOf(java.time.LocalDateTime.now()));
    

答案 1 :(得分:15)

TL;博士

使用JDBC 4.2或更高版本以及Java 8或更高版本:

myPreparedStatement.setObject( … , myLocalDate  )

...和...

myResultSet.getObject( … , LocalDate.class )

详细

Vargas的回答很好地提到了java.time类型,但仅指转换为java.sql.Date。如果您的驱动程序已更新,则无需转换。

java.time

java.time框架内置于Java 8及更高版本中。这些类取代了旧的麻烦日期时间类,例如java.util.Date.Calendar和&amp; java.text.SimpleDateFormatJoda-Time团队还建议迁移到java.time。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。

大部分java.time功能都被反向移植到Java 6&amp; ThreeTen-Backport中的7,并在ThreeTenABP中进一步适应Android。

LocalDate

在java.time中,java.time.LocalDate类表示没有时间且没有时区的仅限日期的值。

如果使用符合JDBC driver或更新规范的JDBC 4.2,则无需使用旧的java.sql.Date课程。您可以通过PreparedStatement::setObjectResultSet::getObject直接向/从数据库传递/获取LocalDate个对象。

LocalDate localDate = LocalDate.now( ZoneId.of( "America/Montreal" ) );
myPreparedStatement.setObject( 1 , localDate  );

...和...

LocalDate localDate = myResultSet.getObject( 1 , LocalDate.class );

在JDBC 4.2之前,转换

如果您的驱动程序无法直接处理java.time类型,请回退到转换为java.sql类型。但是最小化它们的使用,只使用java.time类型的业务逻辑。

旧类中添加了新方法,用于转换为/从java.time类型转换。对于java.sql.Date,请参阅valueOftoLocalDate方法。

java.sql.Date sqlDate = java.sql.Date.valueOf( localDate );

......和......

LocalDate localDate = sqlDate.toLocalDate();

占位符值

警惕使用0000-00-00作为占位符值,如问题代码中所示。并非所有数据库和其他软件都能及时处理。我建议使用1970年常用的Unix/Posix epoch reference date 1970-01-01之类的东西。

LocalDate EPOCH_DATE = LocalDate.ofEpochDay( 0 ); // 1970-01-01 is day 0 in Epoch counting.

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 2 :(得分:3)

您遇到的问题是您从格式化的java.util.Date传递不兼容的格式以构造java.sql.Date的实例,这些实例在使用{{1}时的行为方式不同因为他们使用不同的格式。

我也可以看到你的目标是坚持几小时和几分钟,我认为你最好将数据类型更改为valueOf(),它支持小时和分钟,同时将数据库字段更改为DATETIME或类似的(取决于您的数据库供应商)。

无论如何,如果你想从java.sql.Timestamp改变,我建议使用

java.util.Date to java.sql.Date

答案 3 :(得分:2)

docs明确表示java.sql.Date会抛出:

  
      
  • IllegalArgumentException - 如果给定的日期不是JDBC日期转义格式(yyyy-[m]m-[d]d
  •   

此外,您不需要将日期转换为String然后转换为sql.date,这似乎是多余的(并且容易出错!)。相反,你可以:

java.sql.Date sqlDate := new java.sql.Date(now.getTime());
prs.setDate(2, sqlDate);
prs.setDate(3, sqlDate);

答案 4 :(得分:1)

如果要将当前日期添加到数据库中,我将避免在Java中计算日期。如果客户端配置错误,时间错误,时区错误等,确定Java(客户端)端的“now”会导致数据库中出现不一致的情况。相反,日期可以在服务器端设置为方式如下:

requestSQL = "INSERT INTO CREDIT_REQ_TITLE_ORDER ("   +
                "REQUEST_ID, ORDER_DT, FOLLOWUP_DT) " +
                "VALUES(?, SYSDATE, SYSDATE + 30)";

...

prs.setInt(1, new Integer(requestID));

这样,只需要一个绑定参数,并且在服务器端计算的日期将是一致的。更好的方法是向CREDIT_REQ_TITLE_ORDER添加插入触发器并让触发器插入日期。这有助于强制不同客户端应用程序之间的一致性(例如,有人试图通过sqlplus进行修复。

答案 5 :(得分:-1)

不确定,但我认为您正在寻找的是从String创建java.util.Date,然后将该java.util.Date转换为java.sql.Date。

试试这个:

private static java.sql.Date getCurrentDate(String date) {

    java.util.Date today;
    java.sql.Date rv = null;
    try {

        SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
        today = format.parse(date);
        rv = new java.sql.Date(today.getTime());
        System.out.println(rv.getTime());

    } catch (Exception e) {
        System.out.println("Exception: " + e.getMessage());
    } finally {
        return rv;
    }

}    

将返回setDate();

的java.sql.Date对象

上面的函数将打印出一个长值:

1375934400000