jcs*_*ter 4 java timezone spring cassandra spring-data-cassandra
我试图java.time.LocalDateTime在我的 Cassandra 数据库中保留一个对象并使其与时区无关。我正在使用 Spring Data Cassandra 来做到这一点。
问题是,沿着这条线的某个地方,有些东西将这些LocalDateTime对象视为在我的服务器的时区中,并在将它们存储在数据库中时将它们偏移到 UTC 时间。
这是错误还是功能?我可以以某种方式解决它吗?
配置:
@Configuration
@EnableCassandraRepositories(
basePackages = "my.base.package")
public class CassandraConfig extends AbstractCassandraConfiguration{
@Override
protected String getKeyspaceName() {
return "keyspacename";
}
@Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster =
new CassandraClusterFactoryBean();
cluster.setContactPoints("127.0.0.1");
cluster.setPort(9142);
return cluster;
}
@Bean
public CassandraMappingContext cassandraMapping()
throws ClassNotFoundException {
return new BasicCassandraMappingContext();
}
}
Run Code Online (Sandbox Code Playgroud)
我希望保留的预订记录:
@Table("booking")
public class BookingRecord {
@PrimaryKeyColumn(
ordinal = 0,
type = PrimaryKeyType.PARTITIONED
)
private UUID bookingId = null;
@PrimaryKeyColumn(
ordinal = 1,
type = PrimaryKeyType.CLUSTERED,
ordering = Ordering.ASCENDING
)
private LocalDateTime startTime = null;
...
}
Run Code Online (Sandbox Code Playgroud)
简单的存储库接口:
@Repository
public interface BookingRepository extends CassandraRepository<BookingRecord> { }
Run Code Online (Sandbox Code Playgroud)
保存通话:
...
@Autowired
BookingRepository bookingRepository;
...
public void saveBookingRecord(BookingRecord bookingRecord) {
bookingRepository.save(bookingRecord);
}
Run Code Online (Sandbox Code Playgroud)
这是用于填充 BookingRecord 中的开始时间的字符串:
"startTime": "2017-06-10T10:00:00Z"
Run Code Online (Sandbox Code Playgroud)
这是时间戳被持久化后 cqlsh 的输出:
cqlsh:keyspacename> select * from booking ;
bookingid | starttime
--------------------------------------+--------------------------------
8b640c30-4c94-11e7-898b-6dab708ec5b4 | 2017-06-10 15:00:00.000000+0000
Run Code Online (Sandbox Code Playgroud)
Cassandra 将 Date( timestamp)存储为自纪元以来的毫秒数,没有特定的时区信息。时区数据在 Cassandra 之上的层中处理。
LocalDate/LocalDateTime表示相对于您当地时间的时间点。在可以保存日期/时间之前,需要使用时区对其进行增强以计算可以保存的通用表示。
Spring Data 使用您的系统默认时区 ( Date.from(source.atZone(systemDefault()).toInstant()))。
如果您需要时区精度并希望省略任何隐式时区转换,请java.util.Date直接使用与 Cassandra 的(准确地说是 Datastax 驱动程序)存储格式表示相对应的。
我确实想在我的项目中使用LocalDateTime和LocalDate,而不是java.util.Date,因为它们更新并且具有更具吸引力的功能。
经过大量搜索,我找到了解决方法。
首先,您必须创建 SpringConverter接口的自定义实现,如下所示:
一个用于Date给LocalDateTime:
public class DateToLocalDateTime implements Converter<Date, LocalDateTime> {
@Override
public LocalDateTime convert(Date source) {
return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneOffset.UTC);
}
}
Run Code Online (Sandbox Code Playgroud)
一个用于LocalDateTime到Date:
public class LocalDateTimeToDate implements Converter<LocalDateTime, Date> {
@Override
public Date convert(LocalDateTime source) {
return source == null ? null : Date.from(source.toInstant(ZoneOffset.UTC));
}
}
Run Code Online (Sandbox Code Playgroud)
最后,您必须按如下customConversions方式覆盖该方法CassandraConfig:
@Configuration
@EnableCassandraRepositories(basePackages = "my.base.package")
public class CassandraConfig extends AbstractCassandraConfiguration{
@Override
protected String getKeyspaceName() {
return "keyspacename";
}
@Override
public CustomConversions customConversions() {
List<Converter> converters = new ArrayList<>();
converters.add(new DateToLocalDateTime());
converters.add(new LocalDateTimeToDate());
return new CustomConversions(converters);
}
@Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster =
new CassandraClusterFactoryBean();
cluster.setContactPoints("127.0.0.1");
cluster.setPort(9142);
return cluster;
}
@Bean
public CassandraMappingContext cassandraMapping()
throws ClassNotFoundException {
return new BasicCassandraMappingContext();
}
}
Run Code Online (Sandbox Code Playgroud)
感谢 mp911de 让我知道在哪里寻找解决方案!
| 归档时间: |
|
| 查看次数: |
6246 次 |
| 最近记录: |