You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java Bolt驱动向AWS Neptune添加带日期属性边的报错问题

问题描述

我想用Java Bolt驱动给AWS Neptune图数据库添加边,边的一个属性需要存储日期时间信息。发现Neptune支持java.util.Date对象,但Bolt驱动不支持该类型,仅兼容java.time.LocalDateTime,但使用LocalDateTime时触发了内部错误,寻求解决办法。

环境信息

  • Bolt驱动版本:4.3.3
  • Java版本:Java 11(运行在AWS Lambda,无法升级更高版本)

示例代码

Maven依赖

<dependency>
    <groupId>org.neo4j.driver</groupId>
    <artifactId>neo4j-java-driver</artifactId>
    <version>4.3.3</version>
</dependency>

写入数据的Java代码

Driver boltDriver = GraphDatabase.driver(neptuneConnectionString,
                Config.builder().withConnectionTimeout(30, TimeUnit.SECONDS)
                        .withEncryption()
                        .withTrustStrategy(Config.TrustStrategy.trustSystemCertificates())
                        .build());

Map<String, Object> parameters = new HashMap<>();
parameters.put("locationId", "dsfsdf3453");
parameters.put("deviceId", "fdfdf4534");
parameters.put("edgeId", "dfdf45345");
parameters.put("loginAt", LocalDateTime.now());

var query = "MERGE (l:Location_J {locationId: $locationId}) MERGE (d:Device_J {deviceId: $deviceId}) MERGE (l)-[a:ACCESSES_J {loginAt: $loginAt}]->(d)";

boltDriver.session().run(query, parameters);

触发的异常

WARNING: [0x06247997][uat-niyothon-neptune-2023.cluster-cfg5tfk5qker.ap-south-1.neptune.amazonaws.com:8182][021cdffffe623928-000035fc-0000b02d-f131b528da33cefe-05e79a93] Fatal error occurred in the pipeline
org.neo4j.driver.exceptions.DatabaseException: "Unexpected server exception 'Operation terminated (internal error)'"
at org.neo4j.driver.internal.util.ErrorUtil.newNeo4jError(ErrorUtil.java:90)
at org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher.handleFailureMessage(InboundMessageDispatcher.java:108)
at org.neo4j.driver.internal.messaging.common.CommonMessageReader.unpackFailureMessage(CommonMessageReader.java:83)
at org.neo4j.driver.internal.messaging.common.CommonMessageReader.read(CommonMessageReader.java:59)
at org.neo4j.driver.internal.async.inbound.InboundMessageHandler.channelRead0(InboundMessageHandler.java:83)
at org.neo4j.driver.internal.async.inbound.InboundMessageHandler.channelRead0(InboundMessageHandler.java:35)
at org.neo4j.driver.internal.shaded.io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
at org.neo4j.driver.internal.async.inbound.MessageDecoder.channelRead(MessageDecoder.java:47)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at org.neo4j.driver.internal.shaded.io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1368)
at org.neo4j.driver.internal.shaded.io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1234)
at org.neo4j.driver.internal.shaded.io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1280)
at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:507)
at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:446)
at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at org.neo4j.driver.internal.shaded.io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at org.neo4j.driver.internal.shaded.io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at org.neo4j.driver.internal.shaded.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at org.neo4j.driver.internal.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at org.neo4j.driver.internal.shaded.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at org.neo4j.driver.internal.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Unknown Source)
解决办法

方案1:将LocalDateTime转换为Instant(带时区的时间戳)

Neptune对带时区的时间类型支持更稳定,LocalDateTime无时区信息容易引发解析错误。将其转换为Instant后传入参数:

// 替换原有的loginAt参数设置
parameters.put("loginAt", LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());

可配合修改Cypher查询明确类型转换(更稳妥):

MERGE (l:Location_J {locationId: $locationId}) 
MERGE (d:Device_J {deviceId: $deviceId}) 
MERGE (l)-[a:ACCESSES_J {loginAt: datetime($loginAt)}]->(d)

方案2:使用java.util.Date配合驱动自定义类型映射

通过自定义类型转换器让Bolt驱动兼容java.util.Date:

  1. 实现TypeAdapter接口处理Date与Neptune时间类型的转换:
public class DateTypeAdapter implements TypeAdapter<Date> {
    @Override
    public Value toValue(Date value) {
        return Values.value(value.toInstant());
    }

    @Override
    public Date fromValue(Value value) {
        return Date.from(value.asInstant());
    }
}
  1. 创建Driver时注册该适配器:
Config config = Config.builder()
        .withConnectionTimeout(30, TimeUnit.SECONDS)
        .withEncryption()
        .withTrustStrategy(Config.TrustStrategy.trustSystemCertificates())
        .withCustomTypeAdapter(Date.class, new DateTypeAdapter())
        .build();

Driver boltDriver = GraphDatabase.driver(neptuneConnectionString, config);
  1. 直接使用java.util.Date作为参数:
parameters.put("loginAt", new Date());

方案3:转换为ISO-8601字符串传递

将时间转为标准ISO-8601字符串,在Cypher查询中转换为datetime类型:

// 生成ISO-8601格式字符串
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
parameters.put("loginAt", LocalDateTime.now().format(formatter));

修改Cypher查询:

MERGE (l:Location_J {locationId: $locationId}) 
MERGE (d:Device_J {deviceId: $deviceId}) 
MERGE (l)-[a:ACCESSES_J {loginAt: datetime($loginAt)}]->(d)

关键原因说明

Neptune的Bolt兼容层对无时区的LocalDateTime处理存在兼容性问题,带时区的Instant或标准ISO字符串能更好匹配Neptune的datetime类型要求,避免内部解析错误。


内容的提问来源于stack exchange,提问作者Vishal Jamdade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 15:07:00