【问题标题】:Java ora-01830 date format picture ends before converting entire input string Timestamp SQLJava ora-01830 日期格式图片在转换整个输入字符串之前结束 Timestamp SQL
【发布时间】:2018-11-20 19:13:35
【问题描述】:

我在通过 java 使用 Oracle 时从数据库中获取日期时遇到问题。如果我在 Java 中使用它:

SELECT * 
from HA2_BOOKINGS 
WHERE ROOM like 'R1' 
  AND BEGINNING >= (TO_TIMESTAMP('2018-06-11 15:11:43.208', 'YYYY-MM-DD HH24:MI:SSXFF')) 
  AND END <=  (TO_TIMESTAMP('2018-06-11 15:11:43.208', 'YYYY-MM-DD HH24:MI:SSXFF'))

我收到 oracle-01830 错误,但是当我在 oracle 本身中使用完全相同的东西时,代码可以正常工作。有谁知道为什么?

我的java代码:

public Collection<Booking> getAllBookingsForRoomInPeriod(Room r, String startDate, String endDate) {
        Collection<Booking> bookingsForRoomInPeriod = new ArrayList<Booking>();
        SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        parser.setLenient(false);

        Date dateBeginning = new Date();
        Date dateEnd = new Date();
        try {
            dateBeginning = parser.parse(startDate);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            dateEnd = parser.parse(endDate);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        Timestamp tsBeginning = new Timestamp(dateBeginning.getTime());
        Timestamp tsEnd = new Timestamp(dateEnd.getTime());

        bookingList.clear();

        Connection aCon = Persistence.getConnection();
        ResultSet resultSet = null;

        // Raeume lesen
        try {
            resultSet = Persistence.executeQueryStatement(aCon, "SELECT * from HA2_BOOKINGS WHERE ROOM like '" + r.getRoomNr() + "' AND BEGINNING >= (TO_TIMESTAMP('" + tsBeginning + "', 'YYYY-MM-DD HH24:MI')) AND END <=  (TO_TIMESTAMP('" + tsEnd + "', 'YYYY-MM-DD HH24:MI'))");
            while (resultSet.next()) {
                Booking a = new Booking();
                a.setRoom(resultSet.getString("ROOM"));
                a.setUsername(resultSet.getString("USERNAME"));
                a.setDescription(resultSet.getString("DESCRIPTION"));
                a.setBeginning(resultSet.getTimestamp("BEGINNING"));
                a.setEnd(resultSet.getTimestamp("END"));
                this.bookingList.add(a);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Persistence.closeConnection(aCon);
        }
        System.out.println(bookingList);

        return bookingList;
}

【问题讨论】:

  • 你在 Java 中使用这个字符串?或者您实际上是使用准备好的语句还是使用字符串构建语句?
  • @a_horse_with_no_name 我添加了我的 java 代码
  • 啊哈。使用准备好的语句。不要从字符串构建语句。使用 setTimestamp 设置您的时间戳,您将不需要任何 TO_TIMESTAMP 或格式。
  • @RealSkeptic 我也添加了我的 java 代码

标签: java sql oracle timestamp ora-01830


【解决方案1】:

不要不要这样传递参数。

"' AND BEGINNING &gt;= (TO_TIMESTAMP('" + tsBeginning + "', 'YYYY-MM-DD HH24:MI')) 将使用 Java 的 toString() 方法将 Timestamp 实例转换为字符串 - 这很可能与您指定的格式掩码不匹配。

使用占位符并直接传递Timestamp 实例:

首先你需要一个使用占位符?而不是直接使用值的SQL查询:

String sql = "SELECT * from HA2_BOOKINGS WHERE ROOM = ? AND BEGINNING >= ? and END <= ?"

然后准备语句:

PreparedStatement pstmt = aCon.prepareStatement(sql);

或者在没有变量的情况下使用它:

PreparedStatement pstmt = aCon.prepareStatement("SELECT * from HA2_BOOKINGS WHERE ROOM = ? AND BEGINNING >= ? and END <= ?");

提供值:

pstmt.setString(1, 'R1');
pstmt.setTimestamp(2, tsBeginning);
pstmt.setTimestamp(3, tsEnd);

执行查询(使用提供的值)并处理结果集。

resultSet = pstmt.executeQuery();
while (resultSet.next()) {
  ..
}

除了性能改进(因为您避免了 Oracle 中代价高昂的硬解析)之外,这也是一种安全的方法,因为它可以防止 SQL 注入。

请注意,我将无用的LIKE 运算符替换为=,因为LIKE 'R1'= 'R1' 相同。

【讨论】:

  • 谢谢,我以前从没用过这个,因为我还是一个初学者,我应该在preparedstatement中使用什么“sql”?
  • 啊,好吧,它有效,但由于某种原因,它现在只给我一个预订,即使应该有多个
  • 我不知道出了什么问题,但现在似乎可以正常工作了,非常感谢!
【解决方案2】:

您的格式模型is the local radix character 中的X。您的 Java 和“oracle”(无论是指哪个客户端)会话似乎具有不同的 NLS 设置。

如果你先运行它,你会在 SQL*Plus 中看到同样的东西:

alter session set nls_numeric_characters=',.';

您可以修改设置以使 Java 行为相同,可能是通过语言环境;但如果可以避免它们,最好不要依赖或假设 NLS 设置。如果你的文字总是有句号,你也可以在格式模型中使用它们,而不是依赖 NLS 的X

SELECT * 
from HA2_BOOKINGS 
WHERE ROOM like 'R1' 
  AND BEGINNING >= TO_TIMESTAMP('2018-06-11 15:11:43.208', 'YYYY-MM-DD HH24:MI:SS.FF')
  AND END <= TO_TIMESTAMP('2018-06-11 15:11:43.208', 'YYYY-MM-DD HH24:MI:SS.FF')

或者更好的是,使用绑定变量并直接传递时间戳值,正如@a_horse_with_no_name 建议的那样。


现在已经了解了您的 Java 代码以及如何通过串联嵌入文字,肯定遵循该建议;这只是解释了您收到错误的原因...

【讨论】:

  • @Hola - 它修复了即时错误;但你真的应该使用准备好的语句和绑定变量。
  • 我尝试使用另一种方法,但它只返回一个预订,而不是此间隔内的所有预订,我用我当前的代码更新了我的帖子
猜你喜欢
  • 2019-04-25
  • 2010-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
相关资源
最近更新 更多