Kni*_*ies 7 java postgresql hibernate spring-boot
Spring Boot 3 (Hibernate 6.1) in combination with PostgreSQL seems to have a problem with Instant values mapped to SQL timestamps (without time zone), as the following test case fails. Values read differ from the written values by the amount of the local time zone offset.
The test case executes successfully when using the H2 test database or when switching back to Spring Boot 2.7.6 (Hibernate 5.6).
JPA entity:
@Entity
public class MyEntity {
@Id
UUID id = UUID.randomUUID();
//@JdbcType(TimestampJdbcType.class) //work-around to get it somehow working
//(alternative: declare this globally in a custom Hibernate dialect)
//but why is this neccessary only with spring-boot-3 and postgres?
@Column(columnDefinition = "timestamp")
Instant createdTimestamp = Instant.now();
}
Run Code Online (Sandbox Code Playgroud)
Spring Data repository:
public interface MyEntityRepository extends CrudRepository<MyEntity, UUID> {
}
Run Code Online (Sandbox Code Playgroud)
JUnit integration test:
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE) //comment out to use the H2 database
class MyEntityRepositoryITest {
@Autowired
MyEntityRepository myEntityRepository;
@Test
@Transactional(propagation = NOT_SUPPORTED) //do not use a transaction
void readInstantSameAsPersisted() {
var entity = new MyEntity();
myEntityRepository.save(entity);
var read = myEntityRepository.findById(entity.id).orElseThrow();
assertEquals(entity.createdTimestamp.getEpochSecond(), read.createdTimestamp.getEpochSecond());
}
}
Run Code Online (Sandbox Code Playgroud)
Maven pom.xml:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)
Spring application.properties:
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:postgresql://localhost:5432/dbname
spring.datasource.username=username
spring.datasource.password=password
Run Code Online (Sandbox Code Playgroud)
Notes:
spring.jpa.properties.hibernate.jdbc.time_zone to any value doesn't help.LocalDateTime as an option, as I want the createdTimestamp to represent an unambiguous point in time.spring.datasource.hikari.connection-init-sql=SET TIME ZONE 'UTC' also works as a work-around, but I don't see why this is neccessary -- reading a value that is based on seconds since 1970-01-01 should give the same result as the written value, regardless of which zone is used behind the scenes.Instant, but Hibernate does.This answer says timestamp with time zone does (unlike the name suggests) in fact not carry additional zone information and just "stores a point on the UTC time line" that can be represented in different zones, which seems like a better fit for my use case.
对于
timestamp with time zone,内部存储的值始终采用 UTC...指定了显式时区的输入值将使用该时区的适当偏移量转换为 UTC。
如果您将该字段声明为timestamp with time zone或简单地声明为timestamptz,那么您将完全达到您想要的效果。它还可以满足您在数据库中不要有多个时区的要求。
| 归档时间: |
|
| 查看次数: |
3120 次 |
| 最近记录: |