Java实体Date类型属性值无法保存到数据表对应字段的问题

本文探讨了使用Java的util.Date类型作为实体属性时,在MyBatis框架下保存至MySQL数据库时遇到的问题及解决办法。当数据库字段类型为date时,发现无法正确保存,通过调整字段类型为datetime成功解决了这一问题。

Java实体Date类型属性值无法保存到数据表对应字段的问题


项目框架:

maven+springMVC+mybatis


实体属性:

//推荐时间
private java.util.Date recommendDate;


数据库字段:

ALTER TABLE `resource`
ADD COLUMN `RECOMMEND_DATE`  date NULL COMMENT '推荐时间';


属性赋值:

resource.setRecommendDate(DateUtils.getNowDate());

相关方法:

获取现在时间

	/**
	 * 获取现在时间
	 * 
	 * @return 返回时间类型 yyyy-MM-dd HH:mm:ss
	 */
	public static Date getNowDate() {
		Date currentTime = new Date();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String dateString = formatter.format(currentTime);
		ParsePosition pos = new ParsePosition(8);
		Date currentTime_2 = formatter.parse(dateString, pos);
		return currentTime_2;
	}

问题:执行保存时跟踪MySql日志发现字段值是NULL

resourceManager.saveOrUpdate(resource);


RECOMMEND_DATE = null


原因分析:

产生此问题的原因估计是类型不匹配的问题!

但即没有异常,也没有警告;


解决方法:

后来由于需要保存日期时间,所以将数据库类型改为datetime;

实体属性映射为:

//推荐时间
private java.sql.Timestamp recommendDate;





<think> 我们正在处理Oracle数据库中的TIMESTAMP类型Java实体类的映射问题。根据之前的讨论,我们知道TIMESTAMP类型在Oracle中存储日期和时间(包括小数秒),而Java中与之对应的合适类型是`java.time.LocalDateTime`,因为它可以示日期和时间而不包含时区信息。然而,在实际映射过程中可能会遇到一些问题,需要正确的配置和处理。 ### 解决方案 #### 1. **基本映射** 在Java实体类中,对于Oracle的TIMESTAMP类型,最直接和推荐的是使用`java.time.LocalDateTime`。这个类可以精确到纳秒,与Oracle TIMESTAMP的精度(默认为微秒,但可以指定为纳秒)相匹配。 示例实体类: ```java import java.time.LocalDateTime; public class MyEntity { private Long id; private LocalDateTime createTime; // 对应Oracle的TIMESTAMP // 省略getter和setter } ``` #### 2. **使用JPA注解** 如果使用JPA(例如Hibernate)进行ORM映射,可以通过`@Column`注解指定数据类型,但通常不需要,因为Hibernate会自动映射。为了确保正确,可以加上`@Temporal`注解吗?注意:在Java 8日期时间API中,一般不使用`@Temporal`,因为它是为旧的`java.util.Date`和`java.util.Calendar`设计的。 正确的方式是直接使用`LocalDateTime`,不需要额外的注解。但如果需要指定精度,可以使用`@Column`的`columnDefinition`属性。 ```java import javax.persistence.Column; import java.time.LocalDateTime; public class MyEntity { @Column(name = "CREATE_TIME") private LocalDateTime createTime; } ``` #### 3. **MyBatis映射** 如果使用MyBatis,则需要一个类型处理器(TypeHandler)来处理`LocalDateTime`和Oracle TIMESTAMP之间的转换。在MyBatis 3.4.5及以上版本,已经内置了对Java 8日期时间类型的支持,但可能需要额外的配置。 在mybatis配置文件中注册类型处理器: ```xml <configuration> <typeHandlers> <typeHandler handler="org.apache.ibatis.type.LocalDateTimeTypeHandler"/> </typeHandlers> </configuration> ``` #### 4. **MyBatis Plus映射** MyBatis Plus在3.0及以上版本已经支持Java 8日期时间类型,无需额外配置。在实体类中直接使用`LocalDateTime`即可。 ```java import com.baomidou.mybatisplus.annotation.TableField; import java.time.LocalDateTime; public class MyEntity { @TableField("CREATE_TIME") private LocalDateTime createTime; } ``` #### 5. **处理时区问题** 注意:`LocalDateTime`不包含时区信息。如果数据库中的TIMESTAMP是带时区的(例如TIMESTAMP WITH TIME ZONE),那么应该使用`java.time.OffsetDateTime`或`java.time.ZonedDateTime`。但问题中指定的是TIMESTAMP(不带时区),所以使用`LocalDateTime`是合适的。 #### 6. **精度匹配** Oracle的TIMESTAMP默认精度是微秒(6位小数秒),而Java的`LocalDateTime`可以精确到纳秒(9位)。如果数据库列的精度不足,在保存时可能会四舍五入或截断。可以在实体类中使用`@Column`注解指定精度(如果使用JPA): ```java @Column(name = "CREATE_TIME", precision = 6) // 指定小数秒的位数 private LocalDateTime createTime; ``` ### 完整示例(使用MyBatis Plus) ```java import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableField; import java.time.LocalDateTime; public class LogRecord { @TableId(type = IdType.AUTO) private Long id; @TableField("LOG_CONTENT") private String logContent; @TableField("CREATE_TIME") private LocalDateTime createTime; // getters and setters } ``` ### 注意事项 - **驱动版本**:确保使用较新的Oracle JDBC驱动(如ojdbc8及以上版本),以支持Java 8日期时间类型。 - **时区设置**:虽然`LocalDateTime`没有时区,但在应用与数据库交互时,数据库会话的时区设置可能会影响时间值的解释。建议在数据库连接字符串中指定时区,例如: ``` jdbc:oracle:thin:@localhost:1521:XE?user=scott&password=tiger&oracle.jdbc.timezoneAsRegion=false ``` 设置`oracle.jdbc.timezoneAsRegion=false`可以避免驱动尝试将数据库时间转换为当前会话时区,从而保持时间值不变。 ### 相关问题 §§相关问题§§: 1. 如果Oracle数据库中的字段类型是TIMESTAMP WITH TIME ZONE,Java实体类应该用什么类型? 2. 在使用MyBatis时,如何处理数据库中的DATE类型Java中LocalDate的映射? 3. 在保存LocalDateTime到数据库时,如何配置MyBatis Plus以自动填充创建时间? 4. 如何确保在不同时区的服务器和数据库之间正确传递时间信息? </think> ### Oracle TIMESTAMP 类型Java 实体类的正确映射 在 Oracle 数据库中,`TIMESTAMP` 类型字段应该对应 Java 实体类中的 `java.time.LocalDateTime` 类型。这是 Java 8 引入的日期时间 API 中最适合的类型,它能精确示日期和时间(不含时区信息)。 #### 完整实体类示例 ```java import java.time.LocalDateTime; public class OracleEntity { private Long id; // 核心映射:TIMESTAMP -> LocalDateTime private LocalDateTime timestampField; // 带时区的特殊处理(如果需要) private LocalDateTime timestampWithTZField; // 其他字段... // Getter 和 Setter public Long getId() { return id; } public void setId(Long id) { this.id = id; } public LocalDateTime getTimestampField() { return timestampField; } public void setTimestampField(LocalDateTime timestampField) { this.timestampField = timestampField; } public LocalDateTime getTimestampWithTZField() { return timestampWithTZField; } public void setTimestampWithTZField(LocalDateTime timestampWithTZField) { this.timestampWithTZField = timestampWithTZField; } } ``` ### 不同场景下的配置建议 #### 1. 标准 TIMESTAMP 类型映射 ```java // 最简单的映射 - 不需要额外注解 private LocalDateTime createTime; ``` #### 2. 带有时区的 TIMESTAMP ```java import com.fasterxml.jackson.annotation.JsonFormat; // 处理 TIMESTAMP WITH TIME ZONE @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") private LocalDateTime lastModified; ``` #### 3. MyBatis Plus 注解配置 ```java import com.baomidou.mybatisplus.annotation.TableField; import java.time.LocalDateTime; @TableField(value = "LOG_TIMESTAMP", jdbcType = JdbcType.TIMESTAMP) private LocalDateTime logTimestamp; ``` #### 4. JPA/Hibernate 实体映射 ```java import javax.persistence.*; import java.time.LocalDateTime; @Entity @Table(name = "ORACLE_TABLE") public class OracleEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "EVENT_TIME", columnDefinition = "TIMESTAMP(6)") private LocalDateTime eventTime; } ``` ### 为什么选择 LocalDateTime? 1. **精度匹配**: - Oracle `TIMESTAMP`:存储日期和时间,精度可达纳秒(默认微秒) - `LocalDateTime`:纳秒级精度(最大 9 位小数秒) 2. **时区处理**: - `TIMESTAMP` 不存储时区信息(与 `TIMESTAMP WITH TIME ZONE` 不同) - `LocalDateTime` 是无时区的时间示,完美匹配 3. **类型安全**: - 比传统的 `java.util.Date` 更精确、更安全 - 避免 `java.sql.Timestamp` 的时区转换问题 ### 不同类型对比 | Oracle 类型 | 推荐 Java 类型 | 替代方案 | 适用场景 | |------------|---------------|---------|---------| | TIMESTAMP | LocalDateTime | java.time.OffsetDateTime | 标准日期时间 | | TIMESTAMP(0) | LocalDateTime | java.time.Instant | 仅需秒级精度 | | TIMESTAMP(6) | LocalDateTime | java.sql.Timestamp | 需要纳秒精度 | | TIMESTAMP WITH TIME ZONE | java.time.ZonedDateTime | java.time.OffsetDateTime | 需要时区信息 | | TIMESTAMP WITH LOCAL TIME ZONE | java.time.OffsetDateTime | java.time.ZonedDateTime | 自动时区转换 | ### 日期格式序列化示例 ```java import com.fasterxml.jackson.annotation.JsonFormat; public class TimestampEntity { // 数据库存储格式 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSS") private LocalDateTime dbFormat; // API 返回格式 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "UTC") private LocalDateTime apiFormat; } ``` ### 最佳实践建议 1. **数据库精度配置**: ```sql -- 创建时指定 TIMESTAMP(6) 支持纳秒 CREATE TABLE event_log ( id NUMBER PRIMARY KEY, event_time TIMESTAMP(6) DEFAULT SYSTIMESTAMP ); ``` 2. **JVM 时区统一**: ```bash # 启动应用时设置统一时区 java -Duser.timezone=UTC -jar yourapp.jar ``` 3. **MyBatis 全局配置**: ```xml <!-- mybatis-config.xml --> <configuration> <settings> <!-- 处理日期类型 --> <setting name="jdbcTypeForNull" value="NULL"/> </settings> </configuration> ``` 4. **Spring Boot 配置**: ```properties # application.properties spring.jackson.time-zone=UTC spring.jackson.serialization.write-dates-as-timestamps=false ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值