在AWS上从MySQL 5.5升级到5.6时,Hibernate的java问题和日期
我有一个非常旧的带有hibernate3的传统Java 6应用程序,它连接到AWS RDS MySQL 5.5数据库
一切正常,但AWS现在MySQL 5.5的生命已经结束,我正在升级到5.6。 我一升级到5.6,就开始出现以下错误:
ERROR org.hibernate.util.JDBCExceptionReporter - Data truncation: Incorrect datetime value: '' for column 'date' at row 1
org.hibernate.exception.DataException: could not insert: [thebusiness.core.history.History]
对于hibernate模型,我有:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="thebusiness.core.history.History" table="history">
<id name="id" type="int" column="id">
<generator class="native" />
</id>
<property name="objectType" type="int" column="object_type" not-null="true" length="3"/>
<property name="recordId" type="int" column="record_id" not-null="true" length="7"/>
<property name="initialValue" type="java.lang.String" column="initial_value" not-null="true" />
<property name="setValue" type="java.lang.String" column="set_value" not-null="true" />
<property name="initialValueId" type="int" column="initial_value_id" not-null="true" />
<property name="setValueId" type="int" column="set_value_id" not-null="true" />
<property name="date" type="java.util.Date" column="date" not-null="true"/>
<property name="fieldName" type="java.lang.String" column="field_name" length="255"/>
<property name="fieldNameArg0" type="java.lang.String" column="field_name_arg0" length="255"/>
<property name="comment" type="java.lang.String" column="comment" />
<property name="finalComment" type="java.lang.String" column="final_comment" />
<many-to-one name="contact" class="thebusiness.core.contact.Contact" not-null="false" lazy="false">
<column name="contact_id"/>
</many-to-one>
</class>
</hibernate-mapping>
我调试发送的日期值,但我有一个java日期值,而不是空值
5.5到5.6之间是否存在任何可能导致应用程序崩溃的因素
显示为历史记录表创建表
CREATE TABLE `history` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`object_type` tinyint(3) NOT NULL DEFAULT '0',
`record_id` int(11) NOT NULL DEFAULT '0',
`initial_value` varchar(255) NOT NULL,
`initial_value_id` int(11) NOT NULL DEFAULT '0',
`set_value` varchar(255) NOT NULL,
`set_value_id` int(11) NOT NULL DEFAULT '0',
`field_name` char(255) DEFAULT NULL,
`date` datetime DEFAULT NULL,
`contact_id` int(11) NOT NULL DEFAULT '0',
`comment` text,
`field_name_arg0` char(255) DEFAULT NULL,
`final_comment` text,
PRIMARY KEY (`id`),
KEY `IX_history_record_id` (`record_id`,`field_name`,`object_type`),
KEY `IX_date` (`date`),
KEY `IX_object_type` (`object_type`)
) ENGINE=MyISAM AUTO_INCREMENT=82991415 DEFAULT CHARSET=utf8
2021年3月23日更新
通过将表hibernate配置文件上的date属性类型从java.util.Date
更改为java.sql.Date
,我可以使它部分工作,但这只保存了日期,在我还保存了时间之前:
<property name="date" type="java.sql.Date" column="date" not-null="true"/>
2021年3月25日更新
版本:
- MySQL:5.6.49
- MySQL连接器:5.1.49
- 休眠:3.1.3
2021年3月26日更新
如何填充日期:
在表示对象的类上,我有如下内容:
public class History extends ModelBase implements java.io.Serializable {
// ...
private Date date;
// ...
public Date getDate() {
return this.date;
}
public void setDate(Date date) {
this.date = date;
}
// ...
}
要设置日期,我只需使用:
history.setDate(new Date());
# 1 楼答案
Stackoverflow中出现了与您指出的问题类似的问题
这些问题似乎与通过Hibernate到新版MySQL执行DML语句时提供的不同处理有关
为了解决这个问题,首先,如注释中所建议的,请考虑使用一个最近的mysql connector/j 5.1 version,它看起来是supported in Java 1.6 and is suitable for mysql 5.6。
您使用的是一个非常过时的Hibernate版本:请考虑将Hibernate依赖项升级到一个更为新近的版本。我认为3.x和4.x分支都适合你的问题
正如您所指出的,使用
java.sql.Date
而不是java.util.Date
似乎可以解决数据截断问题,但结果是丢失了时间信息正如在对你的问题的不同评论中所指出的,possible duplicate的链接,以及@RickJames的后续答案,当你使用
java.sql.Date
时,你失去了时间信息。为了保存它,试着使用java.sql.Timestamp
对于您的评论,您有很多表,更改将涉及在保存之前将所有日期转换为时间戳
为了避免这种级别的转换,可以尝试的一件事是,当基础列的类型为
DATETIME
时,将属性定义更改为使用timestamp
而不是date
,就像您的示例中那样。例如:java.util.Date
已经包含了必要的时间信息,在使用MySQL时,Hibernate默认将timestamp
类型映射到DATETIME
更新
对于您的评论,实际的问题似乎是,如果您以任何方式使用
Timestamp
,无论如何,您都会面临截断错误您可以尝试执行一个快速测试:请从头开始创建一个带有
DATETIME
字段的新表,并查看在新表中插入数据时问题是否仍然存在,可能问题与迁移本身有关。我不知道您实际上是如何迁移数据库的,但正如您在upgrade guide中看到的,在mysql 5.6中存储时间相关类型的实际信息的方式之间有重要的变化为了验证最后一点,您可以尝试将应用程序配置为针对本地数据库运行,并执行一些测试,看看问题是否仍然存在。正如我在评论中告诉你的,我尝试了你的设置,使用了相同的库版本和相同的MySQL数据库版本,我创建了一个与你提供的表非常相似的表,只需执行一个快速测试,无论我使用
java.util.Date
还是type="timestamp"
,它都能正常工作。与您的设置唯一不同的是JDK版本,我无法使用JDK 1.6,我用版本1.8测试了代码我的代码如下
冬眠。cfg。xml
简化类
历史。哈佛商学院。xml
测试
我用docker运行数据库,并使用以下命令:
通过这种设置,使用JDK1.8,测试总是正常运行
# 2 楼答案
你可能需要
java.sql.Timestamp
,它会给你日期和时间。请注意,时区可能存在问题同时,请从MyISAM搬到InnoDB。(原因有很多;在过去十年中,人们反复讨论过这一点。)
将
set_value
和set_value_id
放在同一个表中的逻辑是什么,而不是一个只有这两列的表# 3 楼答案
较新版本的mysql启用了STRICT_TRANS_TABLES模式,当您试图插入的内容不是最终存储在表中的内容时,该模式基本上会出现错误。在这里,您有一个未设置的日期字段,因此它尝试插入“”,当转换为日期时,该字段将变为0000-00-00
您应该适当地设置sql_模式;执行
select @@sql_mode
并查看您可能想要保留哪些新值,然后在aws参数组中设置它如果这个日期字段真的是可选的,我建议您允许它为NULL,并使用NULL作为非现值,而不是0000-00-00。我还鼓励您升级到当前版本(mysql 8或mariadb 10.5);虽然这可能会导致更多的升级问题,但它将使您不必很快再次升级,并为您提供大量新功能