在通过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'))
我得到了ora-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;
}
答案 0 :(得分:6)
不传递这样的参数。
"' AND BEGINNING >= (TO_TIMESTAMP('" + tsBeginning + "', 'YYYY-MM-DD HH24:MI'))
将使用Java的toString()
方法将Timestamp
实例转换为String - 这很可能与您指定的格式掩码不匹配。
使用占位符并直接传递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'
相同。
答案 1 :(得分:2)
格式模型is the local radix character中的X
。你的Java和#oracle&#39; (无论哪个客户端引用)会话似乎都有不同的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代码,以及你如何使用连接嵌入文字,肯定遵循这个建议;这只是解释了为什么你得到错误......