I just doing simple transactions like :
but i got Exception like this
org.springframework.dao.OptimisticLockingFailureException: Optimistic lock exception on saving entity: Document{{dataKey=A, lastValue=XXX, version=1, createdDate=Mon Apr 13 21:53:25 WIB 2020, updatedDate=Mon Apr 13 22:34:28 WIB 2020, _class=SomeData}} to collection some_data
at org.springframework.data.mongodb.core.ReactiveMongoTemplate.lambda$doUpdate$65(ReactiveMongoTemplate.java:1819)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:177)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:242)
at com.mongodb.reactivestreams.client.internal.SingleResultObservableToPublisher$1.onNext(SingleResultObservableToPublisher.java:42)
at com.mongodb.reactivestreams.client.internal.ObservableToPublisher$1.onNext(ObservableToPublisher.java:66)
at com.mongodb.async.client.AbstractSubscription.onNext(AbstractSubscription.java:142)
at com.mongodb.async.client.AbstractSubscription.processResultsQueue(AbstractSubscription.java:217)
at com.mongodb.async.client.AbstractSubscription.tryProcessResultsQueue(AbstractSubscription.java:172)
at com.mongodb.async.client.SingleResultCallbackSubscription$1.onResult(SingleResultCallbackSubscription.java:48)
at com.mongodb.async.client.MongoCollectionImpl$4.onResult(MongoCollectionImpl.java:647)
at com.mongodb.async.client.MongoCollectionImpl$4.onResult(MongoCollectionImpl.java:641)
at com.mongodb.async.client.MongoCollectionImpl$10.onResult(MongoCollectionImpl.java:1138)
at com.mongodb.async.client.MongoCollectionImpl$10.onResult(MongoCollectionImpl.java:1122)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:49)
at com.mongodb.async.client.OperationExecutorImpl$2$1$1.onResult(OperationExecutorImpl.java:140)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:49)
at com.mongodb.operation.OperationHelper$ConnectionReleasingWrappedCallback.onResult(OperationHelper.java:432)
at com.mongodb.operation.MixedBulkWriteOperation.addBatchResult(MixedBulkWriteOperation.java:527)
at com.mongodb.operation.MixedBulkWriteOperation.access$1600(MixedBulkWriteOperation.java:72)
at com.mongodb.operation.MixedBulkWriteOperation$6.onResult(MixedBulkWriteOperation.java:507)
at com.mongodb.operation.MixedBulkWriteOperation$6.onResult(MixedBulkWriteOperation.java:479)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:49)
at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor$2.onResult(DefaultServer.java:245)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:49)
at com.mongodb.internal.connection.CommandProtocolImpl$1.onResult(CommandProtocolImpl.java:85)
at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection$1.onResult(DefaultConnectionPool.java:467)
at com.mongodb.internal.connection.UsageTrackingInternalConnection$2.onResult(UsageTrackingInternalConnection.java:111)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:49)
at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:399)
at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:376)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:677)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:644)
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:514)
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:511)
at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:233)
at com.mongodb.internal.connection.InternalStreamConnection.readAsync(InternalStreamConnection.java:511)
at com.mongodb.internal.connection.InternalStreamConnection.access$1000(InternalStreamConnection.java:76)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:634)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:619)
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:514)
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:511)
at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:233)
at com.mongodb.connection.netty.NettyStream.handleReadResponse(NettyStream.java:263)
at com.mongodb.connection.netty.NettyStream.access$800(NettyStream.java:69)
at com.mongodb.connection.netty.NettyStream$InboundBufferHandler.channelRead0(NettyStream.java:322)
at com.mongodb.connection.netty.NettyStream$InboundBufferHandler.channelRead0(NettyStream.java:319)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
I have @Version already on my Entity and when i was debuging, i saw that the version is greater than the existing value in database. in database the version is 0 and exactly when i try to save(data) the version has increased to 1 which is correct.
I have already read the spring docs about Mongodb Optimistic Locking and i think i didn't do anything wrong :')
Please take a look my entity below
@Data
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
@NoArgsConstructor
@Document(collection = CollectionName.SOME_DATA)
public class SomeData implement Serializable {
private static final long serialVersionUID = 1L;
@Id
@Field(value = "_id")
private String id;
@Version
@Field(value = "version")
private Long version;
@CreatedDate
@Field(value = "createdDate")
private Date createdDate;
@LastModifiedDate
@Field(value = "updatedDate")
private Date updatedDate;
@Indexed
@Field(value = "dataKey")
private String dataKey;
@Indexed
@Field(value = "lastValue")
private String lastValue;
}
in case someone encounter the same issue, on our legacy project we using spring data mongo version org.springframework.data:spring-data-mongodb:1.10.23.RELEASE and on this legacy code we also overriding the mongo id.
And it seem the root cause is because we force the spring data mongo to _id instead id this make the mongo object converter to save id as String instead of mongo object. The solution is simply remove @Field(value = "_id") or dont modify id as other string alias. But if you want to make alias for this id I suppose you need extend the mongo object converter class MappingMongoConverter and make your own implementation.
note: the unexpected behavior happen because on the new version of spring data mongo have different implementation on mongo object converter MappingMongoConverter class when handling alias for mongo id. If the alias not exactly id then when saving data id will be saved as String
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With