我发现无法在UTC等标准区域中将日期/时间插入MySQL数据库。
以下代码段使用Apache DBCP对用户进行身份验证。
public final class AuthenticationDAO {
public boolean isAuthenticated(String userName, String password) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
boolean status = false;
try {
connection = DatabaseConnection.getConnection();
preparedStatement = connection.prepareStatement("select * from admin_tbl where lower(admin_id)=lower(?) and BINARY password=?");
preparedStatement.setString(1, userName);
preparedStatement.setString(2, password);
resultSet = preparedStatement.executeQuery();
status = resultSet.next();
if (status) {
preparedStatement = connection.prepareStatement("update admin_tbl set last_login=? where lower(admin_id)=lower(?) and BINARY password=?");
preparedStatement.setTimestamp(1, new Timestamp(new Date().getTime())); // java.util.Date / java.sql.Timestamp
preparedStatement.setString(2, userName);
preparedStatement.setString(3, password);
preparedStatement.executeUpdate();
}
} finally {
if (connection != null) {connection.close();}
if (resultSet != null) {resultSet.close();}
if (preparedStatement != null) {preparedStatement.close();}
}
return status;
}
}
此代码中只有一行符合我们的利益。
preparedStatement.setTimestamp(1, new Timestamp(new Date().getTime()));
当用户/ admin的登录尝试成功时,此行会更新登录日期/时间。 MySQL中的last_login
列的类型为DATETIME
。
我想在MySQL中的UTC区域中插入未发生的日期/时间。它似乎需要一个本地区域。
无论如何,是否可以在UTC区域中将日期/时间插入MySQL?可以建议使用Java和/或MySQL中的任何数据类型 - 不仅仅是我在这里提供的数据类型。
答案 0 :(得分:1)
您可以在两个位置设置mySQL数据的时区:全局配置和会话配置。你不能指定mysql'这个日期是GMT,但这个日期是EST'。你必须将它们转换为一个共同的时区。
最佳做法是将服务器设置为特定时区[例如:GMT],并确保在存储期间相应地转换日期/时间。实际上,您的所有后端数据应该使用单个时区,并且任何转换都应该在输出之前立即进行。
答案 1 :(得分:1)
Date
在Java中与时区无关。它始终需要UTC(默认情况下始终为)。因此,Date
或Timestamp
本身不是原因,但当Date
/ Timestamp
通过JDBC驱动程序传递给数据库时,它会根据JVM解释日期/时间时区,依次默认为系统时区(本机操作系统区域)。
因此,除非明确强制MySQL JDBC驱动程序使用UTC区域或JVM本身设置为使用该区域,否则它不会使用UTC将Date
/ Timestamp
存储到目标数据库中虽然MySQL本身被配置为使用default_time_zone='+00:00'
中的my.ini
或my.cnf
部分中的[mysqld]
来使用UTC。像Oracle这样的某些数据库可能会支持带时区的时间戳,这可能是我不熟悉的例外情况(未经测试,因为我目前没有这种环境)。
void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException
将指定参数设置为给定的
java.sql.Timestamp
值, 使用给定的Calendar对象。驱动程序使用Calendar对象 构造一个SQLTIMESTAMP
值,然后驱动程序发送给它 数据库。使用Calendar对象,驱动程序可以计算 时间戳考虑到自定义时区。 如果没有Calendar
个对象 如果指定,则驱动程序使用默认时区,即时区 运行应用程序的虚拟机。
在java.sql.PreparedStatement
类中处理日期时间的其他相关getter和setter方法也提到了同样的事情。
通过检查MySQL JDBC驱动程序实现的setTimestampInternal()
方法的调用,可以进一步澄清这一点。
在setTimestampInternal()
方法的两个重载版本中查看对setTimestamp()
方法的以下two次调用。
/** * Set a parameter to a java.sql.Timestamp value. The driver converts this * to a SQL TIMESTAMP value when it sends it to the database. * * @param parameterIndex the first parameter is 1... * @param x the parameter value * * @throws SQLException if a database access error occurs */ public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { setTimestampInternal(parameterIndex, x, this.connection.getDefaultTimeZone()); } /** * Set a parameter to a java.sql.Timestamp value. The driver converts this * to a SQL TIMESTAMP value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... * @param x the parameter value * @param cal the calendar specifying the timezone to use * * @throws SQLException if a database-access error occurs. */ public void setTimestamp(int parameterIndex, java.sql.Timestamp x,Calendar cal) throws SQLException { setTimestampInternal(parameterIndex, x, cal.getTimeZone()); }
因此,当使用Calendar
方法未指定PreparedStatement#setTimestamp()
实例时,将使用默认时区(this.connection.getDefaultTimeZone()
)或指定的时区与提供的Calendar
实例将被使用(cal.getTimeZone()
)。
因此,只需将java.util.Calendar
或其子类java.util.GregorianCalendar
的实例传递给PreparedStatement#setTimestamp()
,并使用您感兴趣的相应时区(我们感兴趣的UTC)。
Timestamp timestamp = new Timestamp(new java.util.Date().getTime());
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
preparedStatement.setTimestamp(1, timestamp, calendar);
指定的时区将用于生成在提供给基础数据库之前提供的Timestamp
的字符串表示。
如果您碰巧处理了像Hibernate,EclipseLink这样的ORM框架,并使用适当的数据源在应用程序服务器/ Servlet容器中创建连接池,那么请参考this answer这个答案所依据的是什么?直接复制自。