我正在尝试通过 Java 在 postgres 表中插入一个值。列类型是时间戳。
代码是这样的:
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
String gameStartedTime = format.format(new Date());
String query= "UPDATE gameStatus g SET g.status ='" + gameStatus
+ g.gameStartTime= to_date('"
+ gameStartedTime + "','yyyy-MM-dd HH:mm:ss')"
// Doesn't matter much
+ " WHERE g.status = 'STARTED' AND " + "g.condition="+ game.getCondition();
现在,当我尝试执行此语句时,它失败了,我收到如下消息:
错误:格式字符串中“mm”字段的值冲突。 详细信息:此值与同一字段类型的先前设置相矛盾。
我不知道出了什么问题!!
对此的任何帮助都会很有用。 提前致谢。 -乙脑
mm
是 to_date()
功能的月份。
mm
和
MM
之间没有区别(与 Java 的 SimpleDateFormat 不同)。
您需要使用
mi
来表示分钟数。手册中提供了所有模式的完整列表:http://www.postgresql.org/docs/current/static/functions-formatting.html#FUNCTIONS-FORMATTING-DATETIME-TABLE
但是您一开始就不应该使用“动态”SQL。最好使用
PreparedStatement
、
java.sql.Timestamp
和
setTimestamp()
来代替。这可以帮助您避免任何格式问题并防止 SQL 注入。这样做。
java.sql.Date date=new Date();
Timestamp timestamp = new Timestamp(date.getTime());
this.date = timestamp;
然后将
this.date
添加到数据库中..尝试一下:
ps.setTimestamp(position, new Timestamp(System.currentTimeMillis()));
尝试从查询中分离日期部分并尝试比较这些值。 看来(至少从我看来)代表分钟的mm, 不符合
g.gameStartTime= to_date
。如果您将这部分拉到查询之外,您可以检查这些值,也许您会发现问题所在。
使用当前时间,这种方式对我有用:
String query = "INSERT INTO table1 (id,t) VALUES (?, ?)";
//update table1 set t=? where id=?
Connection con = null;
PreparedStatement ps = null;
try{
con = dataSource.getConnection();
ps = con.prepareStatement(query);
ps.setLong(1, 1234); // update ps.setLong(2, 1234);
Calendar cal = Calendar.getInstance();
Timestamp timestamp = new Timestamp(cal.getTimeInMillis());
ps.setTimestamp(2,timestamp); // ps.setTimestamp(1,timestamp);
int out = ps.executeUpdate();
if(out !=0){
System.out.println("Record saved");
}
}catch(SQLException e){
e.printStackTrace();
}finally{
try {
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
或者,您可以使用以下几行建立特定的时间戳:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2015);
cal.set(Calendar.MONTH, 0); // 0 january
cal.set(Calendar.DAY_OF_MONTH, 26);
cal.set(Calendar.HOUR_OF_DAY, 10);
cal.set(Calendar.MINUTE, 47);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Timestamp timestamp = new Timestamp(cal.getTimeInMillis());
列类型为时间戳。
TIMESTAMP WITHOUT TIME ZONE
,在 Postgres 中也称为
TIMESTAMP
,是记录时间轴上某个时刻的错误数据类型。
要记录某个时刻,您必须使用
TIMESTAMP WITH TIME ZONE
类型,因为它在 Postgres 和 SQL 标准中都是已知的。Java 中存在严重缺陷的日期时间类已被 JSR 310 中定义并内置于 Java 8+ 中的现代 java.time
类所取代。
切勿使用
Date
、
Calendar
、
Timestamp
、
SimpleDateFormat
等
要在 Java 中捕获当前时刻,我们可以使用
java.time.Instant
。
Instant
表示与 UTC 的偏移量为零时-分-秒的时刻。Instant instant = Instant.now() ; // Current moment as seen in UTC.
但是,虽然 JDBC 4.2 及更高版本要求每个 JDBC 驱动程序都支持 java.time
类,但
Instant
未映射。相反,JDBC 将
java.time.OffsetDateTime
类映射到 SQL 标准类型
TIMESTAMP WITH TIME ZONE
。OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
术语:偏移量仅仅是 UTC 时间子午线之前/之后的小时数、分钟数、秒数。时区是一个命名的(
Continent/Region
,例如:
Europe/Paris
)历史,记录了特定地区的人民所使用的偏移量的过去、现在和未来的变化,由他们的政治家决定。 SQL 标准的作者并没有很好地理解日期时间处理,并且误用了术语“时区”,而他们真正的意思是“偏移”。
避免SQL注入
你说:String query= "UPDATE gameStatus g SET g.status ='" + gameStatus
+ g.gameStartTime= to_date('"
+ gameStartedTime + "','yyyy-MM-dd HH:mm:ss')"
不要像这样连接文本来生成 SQL。这个坏习惯会让你容易受到
SQL注入攻击。相反,使用传递到
prepared 语句中的参数。 使用对象,而不是文本
并使用智能对象而不是哑字符串。我们将 Java 中的日期时间对象映射到 SQL 和 Postgres 中的日期时间类型。因此,请勿将文本转换为文本。文本块
来减轻编写 SQL 的繁琐工作。