将特定区域中的日期/时间插入MySQL数据库

时间:2013-10-16 21:53:51

标签: java mysql jdbc timezone utc

我发现无法在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中的任何数据类型 - 不仅仅是我在这里提供的数据类型。

2 个答案:

答案 0 :(得分:1)

您可以在两个位置设置mySQL数据的时区:全局配置和会话配置。你不能指定mysql'这个日期是GMT,但这个日期是EST'。你必须将它们转换为一个共同的时区。

最佳做法是将服务器设置为特定时区[例如:GMT],并​​确保在存储期间相应地转换日期/时间。实际上,您的所有后端数据应该使用单个时区,并且任何转换都应该在输出之前立即进行。

答案 1 :(得分:1)

Date在Java中与时区无关。它始终需要UTC(默认情况下始终为)。因此,DateTimestamp本身不是原因,但当Date / Timestamp通过JDBC驱动程序传递给数据库时,它会根据JVM解释日期/时间时区,依次默认为系统时区(本机操作系统区域)。

因此,除非明确强制MySQL JDBC驱动程序使用UTC区域或JVM本身设置为使用该区域,否则它不会使用UTC将Date / Timestamp存储到目标数据库中虽然MySQL本身被配置为使用default_time_zone='+00:00'中的my.inimy.cnf部分中的[mysqld]来使用UTC。像Oracle这样的某些数据库可能会支持带时区的时间戳,这可能是我不熟悉的例外情况(未经测试,因为我目前没有这种环境)。

void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException

  

将指定参数设置为给定的java.sql.Timestamp值,   使用给定的Calendar对象。驱动程序使用Calendar对象   构造一个SQL TIMESTAMP值,然后驱动程序发送给它   数据库。使用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这个答案所依据的是什么?直接复制自。