为什么 mybatis 将 java.util.Date 值插入到 Mysql 日期时间列然后获取它们不相等?

Why mybatis insert java.util.Date value to Mysql datetime column then fetch it they are not equal?

Mybatis insert java.util.Date to mysql datetime column, 然后 fetch 发现不匹配

Table

CREATE TABLE `t` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`create_time` datetime DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

代码

@Insert("insert into t(create_time) values(#{0})")
int insertT(Date date);
@Select("select create_time from t order by id desc limit 1")
Date getLatestCreateTime();

单元测试

    Date date1 = new Date();
    mapper.insertT(date1);

    Date date2 = mapper.getLatestCreateTime();

    Assert.assertEquals(date1, date2);

断言失败

java.lang.AssertionError: 
Expected :Tue Aug 02 22:10:35 CST 2016
Actual   :Tue Aug 02 22:10:36 CST 2016

为什么会这样?

因为TimeUtilmysql-connector中将Timstamp转换为Date时,会执行下面的代码

    Timestamp ts = new Timestamp(tsAsMillis1 + (long)offsetDiff);
    ts.setNanos(secondsPart); 

并且secondsPart是0。

@Test
public void test_date_compare_date_from_timestamp() {
    Date date1 = new Date();

    Timestamp ts = new Timestamp(date1.getTime());
    System.out.println(ts);  // 2016-08-08 22:37:37.078
    Date date2 = new Date(ts.getTime());
    Assert.assertEquals(date1, date2);
    ts.setNanos(0);
    System.out.println(ts); // 2016-08-08 22:37:37.0
    Date date3 = new Date(ts.getTime());
    Assert.assertNotEquals(date1, date3);
}

而秒数比原来的多,是因为

insert into t select 1,'2016-08-08 22:42:44.676';
select * from t;
+----+---------------------+
| id | create_time         |
+----+---------------------+
|  1 | 2016-08-08 22:42:45 |
+----+---------------------+

所以,我正在使用这个 mysql table:-(忽略 object/class 名称。)

CREATE TABLE `user_access` (
`user_id` INT NOT NULL,
`access_datetime` DATETIME NOT NULL,
FOREIGN KEY (user_id)  REFERENCES users (user_id) ON DELETE CASCADE
);

然后控制器调用 mybatis 映射器。

import java.sql.Timestamp;
import java.util.Date;

cardsMapper.updateUserAccess(user.getEmail(), new Timestamp(new Date().getTime()));

并且映射器接口有如下代码:-

import java.sql.Timestamp;
@Insert("INSERT INTO user_access VALUES ( (select user_id from users where email = #{email}) , #{dateValue} )")
void updateUserAccess(String email, Timestamp dateValue);

并且当代码 运行 时,table 获得了存储在 access_datetime 列中的日期和时间。

希望这对某人有所帮助。 谢谢