I'm having problems with suspend function in Room #Transaction
Versions:
room_version = "2.1.0-alpha04"
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-coroutines:$room_version"
kapt "androidx.room:room-compiler:$room_version"
I also tried with 2.1.0-rc01.
Kotlin : 1.3
This is my DAO interface:
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(sifrBl: SifrBl)
#Query("DELETE FROM sifrbl")
suspend fun deleteAll()
#Transaction
suspend fun setSifrBl(sifrBl: SifrBl){
deleteAll()
insert(sifrBl)
}
At compilation I get following error:
Method annotated with #Transaction must not return deferred/async return type androidx.lifecycle.LiveData. Since transactions are thread confined and Room cannot guarantee that all queries in the method implementation are performed on the same thread, only synchronous #Transaction implemented methods are allowed. If a transaction is started and a change of thread is done and waited upon then a database deadlock can occur if the additional thread attempts to perform a query. This restrictions prevents such situation from occurring.
I'm referring to this
If I remove suspend in all functions then it works.
Any help is appreciated :)
There was something wrong with dependencies.
room_version = "2.1.0-rc01"
//Room
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
// Test helpers
testImplementation "androidx.room:room-testing:$room_version"
Now it works.
The accepted answer didn't work for me. I had to make the method open and then it worked. Checking the generated class, I can see why it's necessary to make the method open since it is overridden in the generated class.
After looking at the source code of the annotation processor I can say it is impossible for the given code to produce the stated error, since it would only trigger if the method was returning a LiveData<*> object. (reference)
For reference, any #Transaction method which in some way returns a LiveData object, an RxJava object or Guava's ListenableFuture object would trigger this exception since they may cause mutations after returning from the method. Note that this is a blacklist and any object that defers execution would be equally problematic, but would not trigger an error.
Related
According to Jakarta's CDI 2.0 (and 4.0 as well) spec:
https://jakarta.ee/specifications/cdi/2.0/cdi-spec-2.0.html#producer_method
If a producer method return type contains a wildcard type parameter or
is an array type whose component type contains a wildcard type
parameter, the container automatically detects the problem and treats
it as a definition error.
CDI spec is not precise enough. I'm not certain if it refers to a class definition or generated bytecode (for JVM languages). That may impact Kotlin's suspend functions.
Kotlin's compiler transforms suspend function into continuation passing style (CPS). It analyzes the context in which coroutine is going to be executed and do a transformation into a state machine with local variables representing a coroutine's state.
It adds Continuation and wildcard result (Any?) because Kotlin does not support union types.
Then depending on various factor the same Continuation object (related to function invocation) can be passed from one suspended function to another if they are bounded within the same state machine.
My understanding is that Continuation is instantiated when the suspend function is called for the first time at runtime. Whenever we call the same function from different contexts we create different Continuation instances.
I was exploring different frameworks and created several projects in Kotlin/Arrow and Spring, Quarkus, Micronaut where I define my hexagonal ports as type aliases:
typealias AssignKeyboard = suspend (String) -> Either<KeyboardError, Unit>
typealias AssignMouse = suspend (String) -> Either<MouseError, Unit>
Those are producers / beans definitions:
#ApplicationScoped // or #Bean // or #Singleton
// #Named(BeanName.ASSIGN_KEYBOARD)
fun assignLocalKeyboardBean(shellAdapter: ShellAdapter): AssignKeyboard = // code
#ApplicationScoped // or #Bean // or #Singleton
// #Named(BeanName.ASSIGN_MOUSE)
fun assignLocalMouseBean(shellAdapter: ShellAdapter): AssignMouse = // code
And an injection point:
class KeyboardController(
// #Inject
// #Named(BeanName.ASSIGN_KEYBOARD)
private val assignKeyboard: AssignKeyboard,
) {
// code
}
Spring supports suspend functions for producers and I didn't have to specify a qualifier to inject it.
Quarkus was able to create producers from suspend function (recently they blocked it) and inject it with help of Qualifier.
This is an example how Quarkus represents:
kotlin.jvm.functions.Function2<String, ? super kotlin.coroutines.Continuation<? super arrow.core.Either<? extends rg.KeyboardError, ? extends kotlin.Unit>>, ?>
Micronout detects a wildcard without #Named qualifier.
The question how CDI should look like for suspend functions? Can we apply to them? Should smart analyzer be introduced? Continuation depends on an injection context, so maybe they should be skipped in analysis together with result.
More details can be found here:
https://kotlinlang.org/spec/asynchronous-programming-with-coroutines.html#asynchronous-programming-with-coroutines
Update
A full source code can be found here:
https://github.com/gonciarz/cdi-quarkus
https://github.com/gonciarz/cdi-spring
https://github.com/gonciarz/cdi-micronaut
I'm working on a bunch of legacy code written by people before me and I'm confused about a particular kind of setup and wonder if this has ever worked to begin with.
There is a managed bean in spring that has a transactional method.
#Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public boolean updateDraftAndLivePublicationUsingFastDocumentsOfMySite(List<FastDocumentLite> fastDocumentLites, Long mySiteId) throws Exception { ... }
Now inside that method I find new instantiations calling update methods fe:
boolean firstFeed = new MySiteIdUpdate(publishing, siteDao, siteDomainService).update(siteId, fastDocumentLites.get(0).getMySiteId());
From my understanding on IOC this new class isn't managed by spring , it's just a variable in the bean. Now going further inside the update method you see another service gets called.
#Transactional(propagation=Propagation.REQUIRED, rollbackFor=Throwable.class)
public void activateSubdomainForSite(Long siteId, boolean activationOfSite)
So if there is a transaction open it should be propagated into this service. But here is what I don't get if that MySiteIdUpdate object isn't managed by spring does the first transaction move forward to the activateSubdomainForSite method ?? Or is another transaction being opened here. I looked in the logs and I believe it to be the latter but I rather ask the experts for a second oppinion before I proclame this legacy code to be complete rubbish to the project lead. I'm suffering with a StaleStateException somewhere further down the road and I'm hoping this has anything to do with it.
I think the code is correct, and the second #Transactional should reuse the existing transaction.
Because:
1) Spring Transaction handling is done either by Proxies or by AspectJ advices. If it is done by Proxies then it is required that MySiteIdUpdate invoke an instance that is injected (this is what you did). If you use AspectJ, then it should work anyway.
2) The association Transactions to the code that use is done by the Thread, this mean, as long as you "are" in the thread which started the transaction you can use it. (you do not start an new thread, so it should work)
An other way to explain: It is perfect legal when you have some method in your call hierarchy that does not belong to an spring bean. This should not make the transaction handling fail.
I have a class with #Transactional annotation (instead of marking it for all of its method).
Although i have a single method inside that class that shouldn't be annotated as #Transactional.
My question is is there an annotation i can put in this method to mark it as "non-transactional"? or should i start marking each single method in this class as "transactional" excluding this method (a lot of work)
thanks.
There are different transaction propagation strategies to use. These exist in the enum Propagation. The ones you might want to use are
/**
* Execute non-transactionally, suspend the current transaction if one exists.
* Analogous to EJB transaction attribute of the same name.
* <p>Note: Actual transaction suspension will not work on out-of-the-box
* on all transaction managers. This in particular applies to JtaTransactionManager,
* which requires the {#code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard J2EE).
* #see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
/**
* Execute non-transactionally, throw an exception if a transaction exists.
* Analogous to EJB transaction attribute of the same name.
*/
NEVER(TransactionDefinition.PROPAGATION_NEVER), // maybe not this one
So annotate the method inside your class with either of these.
#Transactional
public class MyTransactionalClass {
#Transactional(propagation = Propagation.NOT_SUPPORTED)
public void nonTransactionalMethod() {...}
}
You can find all the propagation strategies here.
Sorry to answer a six year old question, but I noticed the accepted answer doesn't actually answer the question. The question was how to have a method behave as though it was not annotated with #Transactional at all. Such a method will take part in a transaction if there is one, or execute non-transactionally if there is not. It will not suspend an existing transaction, or refuse to execute if there is one, one of which would be the result of the accepted answer.
The propagation to use is Propagation.SUPPORTS (in other words annotate the method with #Transactional(propagation = SUPPORTS). This will take part in the transaction if there is one, or execute non-transactionally if not, just like a non-annotated method would.
Not that according to the Javadoc it is not exactly the same as having no #Transactional annotation at all. It says:
Support a current transaction, execute non-transactionally if none exists. Analogous to EJB transaction attribute of the same name.
Note: For transaction managers with transaction synchronization, SUPPORTS is slightly different from no transaction at all, as it defines a transaction scope that synchronization will apply for. As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) will be shared for the entire specified scope. Note that this depends on the actual synchronization configuration of the transaction manager.
The only way to have the method behave exacty as if it was not annotated with #Transactional at all is to do as OP suggests: don't annotate the class, but annotate all the other methods, but for most uses that will not be necessary and using Propagation.SUPPORTS will suffice.
I've built some code that can rebuild expression trees so I can avoid triggering the no supported translation to SQL exception and it works fine as long as I call my function to replace the iqueryable. The problem is that I'd like it to automatically be applied to all queries in my project without having to worry about calling this function on each one separately. Is there any way that I can intercept everything?
I've tried using Reflection.Emit to create a wrapping provider and using reflection to replace it on the data context and it turns out that even with Reflection.Emit I can't implement the internal IProvider interface.
I've also tried replacing the provider with a RealProxy based class and that works for non-compiled queries, but the CompiledQuery.Execute method is throwing an exception because it won't cast to the SqlProvider class. I tried replacing the response to the Compile method on the provider with another proxy so I could intercept the Execute call, but that failed a check on the return type being correct.
I'm open to any other ideas or ways of using what I've already tried?
It's hard to tell whether this is an applicable solution without seeing your code, but if you have a DI-friendly app architecture you can implement an interceptor and have your favorite IoC container emit the appropriate type for you, at run-time.
Esoteric? A little. Consider an interface like this:
public interface ISomeService
{
IEnumerable<SomeEntity> GetSomeEntities();
// ...
}
This interface might be implemented like this:
public class SomeService : ISomeService
{
private readonly DbContext _context // this is a dependency!
private readonly IQueryTweaker _tweaker; // this is a dependency!
public SomeService(DbContext context, IQueryTweaker tweaker) // this is constructor injection!
{
_context = context;
_tweaker = tweaker;
}
public IEnumerable<SomeEntity> GetSomeEntities()
{
return _tweaker.TweakTheQuery(_context.SomeEntities).ToList();
}
}
Every time you implement a method of the ISomeService interface, there's always a call to _tweaker.TweakTheQuery() that wraps the IQueryable, and that not only gets boring, it also feels like something is missing a feature - the same feeling you'd get by wrapping every one of these calls inside a try/catch block, or if you're familiar with MVVM in WPF, by raising this annoying PropertyChanged event for every single property setter in your ViewModel.
With DI Interception, you factor this requirement out of your "normal" code and into an "interceptor": you basically tell the IoC container that instead of binding ISomeService directly to the SomeService implementation, you're going to be decorating it with an interceptor, and emit another type, perhaps SomeInterceptedService (the name is irrelevant, the actual type only exists at run-time) which "injects" the desired behavior into the desired methods. Simple? Not exactly.
If you haven't designed your code with DI in mind (are your dependencies "injected" into your classes' constructor?), it could mean a major refactoring.
The first step breaks your code: remove the IQueryTweaker dependency and all the TweakTheQuery calls from all ISomeService implementations, to make them look like this - notice the virtualness of the method to be intercepted:
public class SomeService : ISomeService
{
private readonly DbContext _context
public SomeService(DbContext context)
{
_context = context;
}
public virtual IEnumerable<SomeEntity> GetSomeEntities()
{
return _context.SomeEntities.ToList();
}
}
The next step is to configure the IoC container so that it knows to inject the SomeService implementation whenever a type's constructor requires an ISomeService:
_kernel.Bind<ISomeService>().To<SomeService>();
At that point you're ready to configure the interception - if using Ninject this could help.
But before jumping into that rabbit's hole you should read this article which shows how decorator and interceptor are related.
The key point is, you're not intercepting anything that's internal to LINQ to SQL or the .NET framework itself - you're intercepting your own method calls, wrapping them with your own code, and with a little bit of help from any decent IoC container, you'll be intercepting the calls to methods that call upon Linq to SQL, rather than the direct calls to Linq to SQL itself. Essentially the IQueryTweaker dependency becomes a dependency of your interceptor class, and you'll only code its usage once.
An interesting thing about DI interception, is that interceptors can be combined, so you can have a ExecutionTimerServiceInterceptor on top of a AuditServiceInterceptor, on top of a CircuitBreakerServiceInterceptor... and the best part is that you can configure your IoC container so that you can completely forget it exists and, as you add more service classes to the application, all you need to do is follow a naming convention you've defined and voilĂ , you've just written a service that not only accomplishes all the strictly data-related tasks you've just coded, but also a service that will disable itself for 3 minutes if the database server is down, and will remain disabled until it's back up; that service also logs all inserts, updates and deletes, and stores its execution time in a database for performance analysis. The term automagical seems appropriate.
This technique - interception - can be used to address cross-cutting concerns; another way to address those is through AOP, although some articles (and Mark Seeman's excellent Dependency Injection in .NET) clearly demonstrate how AOP frameworks are a less ideal solution over DI interception.
I am using Spring 3, JPA + Hibernate for a CMS application. In that application I have a service class method which is annotated with #Transactional Annotation with rollBack property. Inside that method I am inserting data (ie entity classes) to a table using a loop. For each iteration of the loop entity classes has to be saved to the database. But it is not happening. The commit only happens when the execution of the loop has completed and exits from the method. Then it commits and saves all at once. But I need to read data once it gets inserted into the database before committing in this case. I tried with the ISOLATION LEVEL to read uncommitted but it didn't supported since I am using the default JPADialect. Also tried to add the hibernate implementation of jpaDialect but still it didn't worked. Please help with a workaround for this problem. One more thing, is there any way using propagation required method.
You are right, this is what I stands for in acid. Because the transactions are working in isolation, other transactions cannot see them before they are committed. But playing with isolation levels is a bad practice. I would rather advice you to run each and every iteration in a separate transaction with start and commit inside.
This is a bit tricky in Spring, but here is an example:
public void batch() {
for(...) {
insert(...)
}
}
//necessarily in a different class!
#Transactional
public void insert() {
}
Note that batch() is not annotated with #Transactional and insert() has to be in a different class (Spring service). Too long to comment, but that's life. If you don't like it, you can use TransactionTemplate manually.
remove the transactional annoation on the the method with loop.
In the loop call a separate method to perform the save, make that method transactional
You either need to go with programmatic transactions (Spring's TransactionTemplate or PlatformTransactionManager are the classes to look at, see Spring Doc for programmatic transactions, or you can call another transactional method from within your loop where the transaction is marked with Propagation.REQUIRES_NEW, meaning each call of that method is executed in its own transaction, see here. I think that the second approach requires you to define the REQUIRES_NEW method on a different Spring bean because of the AOP-Proxy. You can also omit the REQUIRES_NEW if the loop is not executed within a transaction.