Skip to content

v2.7.3 - save() not working as expected for updates #1658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sagarikamraj opened this issue Jan 30, 2023 · 9 comments
Closed

v2.7.3 - save() not working as expected for updates #1658

sagarikamraj opened this issue Jan 30, 2023 · 9 comments
Assignees
Labels
status: invalid An issue that we don't feel is valid

Comments

@sagarikamraj
Copy link

sagarikamraj commented Jan 30, 2023

I have recently upgraded my project to java 17 and spring boot 2.7.4 and spring cloud 2021.0.4. I am using mavenBom for spring cloud dependency management. It has brought in spring-data-commons-2.7.3.

With the upgrade, the CRUD repository's save() doesn't seem to be updating the existing objects. I am getting a duplicate key exception. (org.springframework.dao.DuplicateKeyException: Document with the given id already exists). I have already tried enabling transaction management, but to no avail.

Could you please help.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 30, 2023
@mp911de
Copy link
Member

mp911de commented Jan 30, 2023

If you would like us to spend some time helping you to diagnose the problem, please spend some time describing it and, ideally, providing a minimal sample that reproduces the problem.

@mp911de mp911de added the status: waiting-for-feedback We need additional information before we can continue label Jan 30, 2023
@sagarikamraj
Copy link
Author

I am using spring-data with Couchbase as the DB.
My custom repository interface extends org.springframework.data.repository.CrudRepository.
I have noticed that the upsert isn't working when using save().

My custom update method looks as below:
Step 1 - get the ID from user
Step 2 - check if a doc exists in the DB with the given ID
Step 3 - if ID doesn't exist, create new doc in DB.
If ID exists, get the existing doc from DB, update it and save in DB

Problem:
Step 3 mentioned above isn't working for update operations. The save() operation is failing with DuplicateKeyException.
Please see the stack trace below

stacktrace=org.springframework.dao.DuplicateKeyException: Document with the given id already exists {"completed":true,"coreId":"0x178e7df000000001","idempotent":false,"lastChannelId":"178E7DF000000001/000000007D798881","lastDispatchedFrom":"127.0.0.1:58740","lastDispatchedTo":"localhost:58656","requestId":25,"requestType":"InsertRequest","retried":0,"service":{"bucket":"test_bucket","collection":"_default","documentId":"2f0bed70-9cd9-4214-b99d-83bcb26f97aa","errorCode":{"description":"key already exists, or CAS mismatch","name":"KEY_EEXISTS"},"opaque":"0x25","scope":"_default","type":"kv","vbucket":639},"status":"EXISTS","timeoutMs":2500,"timings":{"dispatchMicros":23894,"encodingMicros":726,"totalDispatchMicros":23894,"totalServerMicros":0,"totalMicros":31835,"serverMicros":0}}; nested exception is com.couchbase.client.core.error.DocumentExistsException: Document with the given id already exists {"completed":true,"coreId":"0x178e7df000000001","idempotent":false,"lastChannelId":"178E7DF000000001/000000007D798881","lastDispatchedFrom":"127.0.0.1:58740","lastDispatchedTo":"localhost:58656","requestId":25,"requestType":"InsertRequest","retried":0,"service":{"bucket":"test_bucket","collection":"_default","documentId":"2f0bed70-9cd9-4214-b99d-83bcb26f97aa","errorCode":{"description":"key already exists, or CAS mismatch","name":"KEY_EEXISTS"},"opaque":"0x25","scope":"_default","type":"kv","vbucket":639},"status":"EXISTS","timeoutMs":2500,"timings":{"dispatchMicros":23894,"encodingMicros":726,"totalDispatchMicros":23894,"totalServerMicros":0,"totalMicros":31835,"serverMicros":0}} at org.springframework.data.couchbase.core.CouchbaseExceptionTranslator.translateExceptionIfPossible(CouchbaseExceptionTranslator.java:63) at org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate.potentiallyConvertRuntimeException(ReactiveCouchbaseTemplate.java:169) at org.springframework.data.couchbase.core.ReactiveInsertByIdOperationSupport$ReactiveInsertByIdSupport.lambda$one$3(ReactiveInsertByIdOperationSupport.java:92) at reactor.core.publisher.Mono.lambda$onErrorMap$31(Mono.java:3776)

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jan 30, 2023
@sagarikamraj
Copy link
Author

sagarikamraj commented Jan 30, 2023

My data model looks like below:

@Document(expiry = 7, expiryUnit = TimeUnit.DAYS, touchOnRead = true)
public class MyModel {

  @Id @Field @NotNull private String uniqueId;

  @Field private Integer loadPlanVersion;

  @Version private Long documentVersion;

  @Field @NotNull private String someId;
}

My repository class looks like this:
public interface MyRepository extends CrudRepository<MyModel, String> {}

@mp911de mp911de transferred this issue from spring-projects/spring-data-commons Jan 30, 2023
@mp911de
Copy link
Member

mp911de commented Jan 30, 2023

Moved into Spring Data Couchbase as the ticket relates to Couchbase and not Spring Data Commons.

@sagarikamraj
Copy link
Author

spring-data-couchbase version that I am using is 4.4.3

@mikereiche
Copy link
Collaborator

DuplicateKey can occur on insert(). If your entity object has an @Version property that is zero, insert() will be used. This is the correct/normal behavior.
If you want to use upsert() on an entiy class that has an @Version property, you'll need to explicitly use template.upsertById() or introduce your own repository.upsert() method. Or override the repository.save() method.

@mikereiche mikereiche removed the status: waiting-for-triage An issue we've not yet triaged label Jan 30, 2023
@mikereiche mikereiche self-assigned this Jan 30, 2023
@mikereiche
Copy link
Collaborator

see #1277

@sagarikamraj
Copy link
Author

sagarikamraj commented Jan 31, 2023

@mikereiche , thanks for confirming that it needs an explicit overriding of repository methods for accommodating upsert operations.
Could you please share a sample of the update query that I could use. It is a big data object, I am checking if there is any alternative to updating field by field on a typical SQL update query.
Is there a short cut to replace almost the entire object (maintaining only the ID )? Kind of an equivalent to template.replaceById()

Example of the typical query I am referring to:

update MyBucket 
set departureTime = 'some' 
, scheduleId = 
, dataVersion = 
, orders = 
, returnTime = 
, waveId = 
, vehicleType = 
, friendlyId = 
, planStatus = 
, dateTime = 
where id = 'a16555d6-0ac1-4a15-9d6c-1b9edb5825e5';

@mikereiche
Copy link
Collaborator

mikereiche commented Feb 1, 2023

replace almost the entire object (maintaining only the ID )? Kind of an equivalent to template.replaceById()

you'll need to explicitly use template.upsertById()

@mikereiche mikereiche added status: invalid An issue that we don't feel is valid and removed status: feedback-provided Feedback has been provided labels Feb 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

4 participants