Closed klimeryk closed 8 years ago
I believe your proposed change is wrong. The README should possibly make it clear that DSLContext
is thread-local, but shouldn't tell you to use a Provider
. Guice-Persist is clear that a UnitOfWork
is thread-local, and a unit of work with guice-persist-jooq is a DSLContext
(even if JOOQ's DSLContext
is otherwise threadsafe).
IIUC, there may be a bug in Guice-Persist (replicated here in guice-persist-jooq) that the Provider<Xxx>
implementation in the XxxPersistService
automatically calls begin()
if not isWorking()
. The checkState
just after will thus never throw.
Thank you for looking into this - I was hoping that someone would verify my findings. You are most likely right, however I'm not familiar enough with guice-persist to propose a change I'd be confident to be correct. I was hoping that the author of this project (or someone else suitable) would look into this. I was basing my "fix" on an existing code, which in turn is supposed to be based on JPA's support in Guice. I've raised this issue, because I am at least confident that the current implementation is not working as it should (either because there's a bug in this project or guice-persist, as you've pointed out). Normally, I'd be happy to dig into this deeper and learn something new about Guice, however it so happens that I'm leaving the project that I need this code for, so I wouldn't be able to test my proposed patch thoroughly.
@tbroyer and @klimeryk: just saw this (I wasn't getting github notifications for some reason) so sorry for the delay in responding. In any case, it seems that proper handling of transactions could benefit from some unit tests which may also serve as better example/docs if they happen to be tests that pass. I'll leave this PR open for now until I have a chance to verify a working approach whether it be an issue with documentation and/or Guice-Persist as @tbroyer suggests.
Note: we've been bitten by that behavior of get()
automatically calling begin()
. We didn't have PersistFilter
, so each HTTP request (thread) would (implicitly) begin()
but never end()
, which quickly exhausted all connections in our connection pool.
IMO, guice-persist-jooq should not "pin" a connection to a thread/DSLContext
. It should only do that when starting a transaction, and revert to using the connection pool outside transactions.
Hi, first of all, thanks for this module - it has helped immensly in setting up Guice with jOOQ. However, I've stumbled upon an issue with the
@Transactional
annotation. Namely, it wasn't working ;) Or rather, the changes were commited to the database, even though there was a rollback... After more hours of debugging and scratching my head than I'm willing to admit, I've had a relevation - theDSLContext
injected into the DAO and the one inJdbcLocalTxnInterceptor
was just... not the same.The source of the problem is that injecting
DSLContext
directly sets it to the value bound to the current thread (for example, the one doing the initialization, injecting dependencies, etc.). However, the same thread might not handle the request and a call to a@Transactional
method/class.@Transactional
looks up theDSLContext
in aThreadLocal
and in the (very common) case I've described above, theDSLContext
injected into the DAO and the oneJdbcLocalTxnInterceptor
will be modifing will just simply not be the same. So,@Transactional
sets autoCommit to true, but the DAO uses a different DSLContext so it doesn't matter >_<.This subtle difference is hinted in the Guice's documentation about JPA:
I've included a pull request with proposed changes to README.md that describe a proper (in my opinion) way of injecting
DSLContext
- in most cases the service and/or dao are singletons, and even if not, it won't hurt and will avoid introducing a nasty bug in case someone makes them singletons in the future.