Skip to content

Fix sample transaction code. was: Difference save entity between using repository and transaction #1524

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
rbleuse opened this issue Aug 2, 2022 · 4 comments
Assignees
Labels
type: documentation A documentation update

Comments

@rbleuse
Copy link
Contributor

rbleuse commented Aug 2, 2022

Hello,

I was playing with transactions provided by couchbase and spring data following the documentation from here
I noticed that there's a difference if I persist a document with a repository or with a transaction.

Here are details :
spring-boot 2.7.2
couchbase-transactions 1.2.4

Simple entity

@Document
@Scope("dev")
@Collection("schedule")
data class Schedule(
    @field:Id
    val id: String,

    val nested: Nested,

    @field:Field
    val list: List<String>
)

data class Nested(
    @field:Field("isFree")
    val free: Boolean
)

Repository

interface ScheduleRepository : ReactiveCouchbaseRepository<Schedule, String>

Service

private val collection = clientFactory.withScope("dev").getCollection("schedule").reactive()

fun saveScheduleWithRepo(schedule: Schedule) = repository.save(schedule)

fun saveScheduleAsDocWithTransaction(schedule: Schedule): Mono<TransactionResult> {
    val target = CouchbaseDocument()
    converter.write(schedule, target)
    return transactions.reactive().run {
        it.insert(collection, target.id, target.content)
            .then()
    }
}
val schedule = Schedule("1", Nested(true), listOf("TEST"))
return service.saveScheduleWithRepo(schedule)
    .flatMap {
        service.saveScheduleAsDocWithTransaction(schedule.copy(id = "2"))
    }

Here are differences :

with repository as doc with transaction
{
  "_class": "com.rbleuse.spring.reactive.couchbase.model.Schedule",
  "list": [
    "TEST"
  ],
  "nested": {
    "isFree": true
  }
}
{
  "_class": "com.rbleuse.spring.reactive.couchbase.model.Schedule",
  "list": {
    "empty": false
  },
  "nested": {
    "content": {
      "isFree": true
    },
    "id": null,
    "expiration": 0
  }
}

As you can see, inserting the document with a transaction adds extra fields to the document : content, id and expiration (all in nested). Shouldn't it be in root object instead ?
Furthermore, my simple list of string is not converted into an array with the actual String value.
If I convert my List into an Array in my data class, result is same when using a transaction.

Did I miss something ?

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 2, 2022
@mikereiche
Copy link
Collaborator

mikereiche commented Aug 3, 2022

Before I go into investigating the differences - couchbase-transactions are directly supported in spring-data-couchbase in 5.0.0-M5 It's not necessary to do the conversion. [ the doc is staged at https://mikereiche.github.io/staged/ and will be in the next release which should be in the next couple weeks ] There are instructions on how to use a SNAPSHOT at https://docs.spring.io/spring-data/couchbase/docs/5.0.0-M5/reference/html/ (just use milestone instead of snapshot and use M5).

@mikereiche mikereiche added status: feedback-reminder We've sent a reminder that we need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Aug 3, 2022
@mikereiche
Copy link
Collaborator

mikereiche commented Aug 3, 2022

you need to use target.export instead of target.content to get the correct serialization.

@mikereiche mikereiche added status: feedback-provided Feedback has been provided and removed status: feedback-reminder We've sent a reminder that we need additional information before we can continue labels Aug 3, 2022
@rbleuse
Copy link
Contributor Author

rbleuse commented Aug 3, 2022

Thanks a lot for your suggestion, it's indeed working fine with target.export()

I took this code from spring data couchbase documentation, which gives an example using the target.content instead. Perhaps the documentation needs to be updated while waiting for the 5.0.0 to be released

8.3. Object Conversions
Since the transactions library itself has no knowledge of your spring data entity types, you need to convert it back and forth when reading/writing to interact properly. Fortunately, all you need to do is autowire the MappingCouchbaseConverter and utilize it:

Example 92. Transaction Conversion on Write

@Autowired
MappingCouchbaseConverter mappingCouchbaseConverter;

public void doSomething() {
  transactions.run(ctx -> {

   Airline airline = new Airline("demo-airline", "at");
   CouchbaseDocument target = new CouchbaseDocument();
   mappingCouchbaseConverter.write(airline, target);

   ctx.insert(couchbaseClientFactory.getDefaultCollection(), target.getId(), target.getContent());

   ctx.commit();
  });
}

I also tried to use the 5.0.0-M5 and I'm facing this exception (it's same with the snapshot one) :

@Service
class ScheduleService(
    private val reactiveOperations: ReactiveCouchbaseOperations
) {
    @Transactional
    fun saveScheduleWithTransaction(schedule: Schedule): Mono<Schedule> {
        return reactiveOperations.insertById(Schedule::class.java).one(schedule)
    }
}
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3
	at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
	*__checkpoint ⇢ HTTP POST "/schedule" [ExceptionHandlingWebHandler]
Original Stack Trace:
		at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
		at reactor.core.publisher.Mono.block(Mono.java:1675) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
		at org.springframework.data.couchbase.transaction.CouchbaseCallbackTransactionManager.handlePropagation(CouchbaseCallbackTransactionManager.java:191) ~[spring-data-couchbase-5.0.0-M5.jar:5.0.0-M5]
		at org.springframework.data.couchbase.transaction.CouchbaseCallbackTransactionManager.execute(CouchbaseCallbackTransactionManager.java:76) ~[spring-data-couchbase-5.0.0-M5.jar:5.0.0-M5]
		at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:417) ~[spring-tx-6.0.0-M5.jar:6.0.0-M5]
		at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-6.0.0-M5.jar:6.0.0-M5]
		at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.0-M5.jar:6.0.0-M5]
		at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-6.0.0-M5.jar:6.0.0-M5]
		at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-6.0.0-M5.jar:6.0.0-M5]
		at com.rbleuse.spring.reactive.couchbase.service.ScheduleService$$EnhancerBySpringCGLIB$$f091fb23.saveScheduleWithTransaction(<generated>) ~[main/:na]
		at com.rbleuse.spring.reactive.couchbase.handler.ScheduleHandler.createSchedule(ScheduleHandler.kt:20) ~[main/:na]

@mikereiche
Copy link
Collaborator

mikereiche commented Aug 4, 2022

I also tried to use the 5.0.0-M5 and I'm facing this exception (it's same with the snapshot one)

I'll see if I can eliminate that block().

I'm curious how this code is being called as you had a similar issue with #1516 and I haven't been able to reproduce it. (I did provide a fix for #1516 which eliminates the block()).

I opened #1527 for the exception in M5.

@mikereiche mikereiche added type: documentation A documentation update and removed status: feedback-provided Feedback has been provided labels Aug 4, 2022
@mikereiche mikereiche changed the title Difference save entity between using repository and transaction Fix sample transaction code. was: Difference save entity between using repository and transaction Aug 4, 2022
@mikereiche mikereiche self-assigned this Aug 12, 2022
rbleuse added a commit to rbleuse/spring-data-couchbase that referenced this issue Aug 21, 2022
mikereiche pushed a commit that referenced this issue Aug 22, 2022
* fix transaction sample
fixes #1524

* delete new line
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation A documentation update
Projects
None yet
Development

No branches or pull requests

3 participants