I wasn't able to find out what is the behaviour of transactional system when calling method annotated with #Transactional(propagation=Propagation.REQUIRED, timeout=2) within the method, which is annotated with #Transactional(propagation=Propagation.REQUIRES_NEW, timeout=10).
What is the resulting timout for inner transaction and why?
We use Spring 3.0 and hibernate 3.
The timeout in the nested method (2) is ignored, since it will join the same transaction. There is no "inner transaction".
Related
In MyService I have the following:
import groovy.sql.Sql
class MyService {
Sql groovySql
def serviceMethod(){
groovySql.firstRow("some query.....")
}
}
In resources.groovy groovySql inject as follows:
groovySql(groovy.sql.Sql, ref('dataSource'))
This is a Grails 2.4.5 application. Now, the question is when serviceMethod is called, is the connection closed automatically?
Every method in Sql creates and releases resources if necessary.
Under the covers the facade hides away details associated with getting
connections, constructing and configuring statements, interacting with
the connection, closing resources and logging errors.
If you create a Sql with a DataSource, it will get a new connection every time, and close it at the end of the operation.
If we are using a DataSource and we haven't enabled statement caching,
then strictly speaking the final close() method isn't required - as
all connection handling is performed transparently on our behalf;
however, it doesn't hurt to have it there as it will return silently
in that case.
I have a service that distributes tasks to operators.
Inside a method I distribute many tasks in time inside a loop. I want to flush the task, the operator, and a DistributionLog. If I just had one domain to save I think I could do something like
Operator.withTransaction{ //...some code }
but I have at least 3 domains to save and to make it even worse, two of them have dependency on each other. The operator have a list of tasks.
I can't wait all the distribution to finish before an operator can get his tasks, so I have to force it to flush. To make it even harder, it's all inside a multitenantService.doWithTenant() (multitenant plugin)
You can get the session using the withSession method available in all domain classes and call to flush() on it.
Operator.withSession { session ->
// ...
session.flush()
}
If you want to do an explicit flush, you can get a reference to the hibernate session factory in your grails service like this:
def sessionFactory
You can then get the current hibernate session, and call flush on that:
sessionFactory.currentSession.flush()
You can force a flush with flush argument to the last call to save:
obj.save flush:true
See the documentation:
http://grails.github.io/grails-doc/2.2.5/ref/Domain%20Classes/save.html
The save method informs the persistence context that an instance should be saved or updated. The object will not be persisted immediately unless the flush argument is used:
b.save(flush: true)
I have a service method to transfer funds to/from an external system.
it should create a transaction in our system first (so we have a transactionId)
Then we call the external system.
If the external system fails, we need to rollback the transaction, then write a new record in our payment audit log table, regardless of if the call failed or worked.
I cant figure out how to control the transaction in this case.
I understand services are transactional by default.
I assume I could create 3 methods (they are all 1 method now, which doesn't work as I have no control over what gets committed and what gets rolled back)
createPaymentTransaction()
sendToPaymentSystem()
createPaymentRecord()
I need to rollback 1 if 1 fails, and do nothing more.
I need to rollback 1 if 2 fails, but write 3.
I need to write 3 if 1 and 2 works.
I don't know how to annotate these, or how to structure a 4th request to manage the 3.
I'd go with something like this:
package com.myapp
import grails.transaction.Transactional
import org.springframework.transaction.annotation.Propagation
#Transactional
class MyService {
def createPaymentTransaction() {}
def sendToPaymentSystem() {}
#Transactional(propagation=Propagation.REQUIRES_NEW)
def createPaymentRecord() {}
def method4() {
try {
def transactionId = createPaymentTransaction()
sendToPaymentSystem(transactionId)
}
finally {
createPaymentRecord()
}
}
}
By annotating at the class level, we set the defaults for all methods, but can customize as needed, e.g. for createPaymentMethod.
So what will happen is that calling method4 will join an existing transaction, or start a new one if necessary. If there's a problem in either createPaymentTransaction or sendToPaymentSystem then the transaction will be rolled back, but the call to createPaymentRecord will happen because it's in the finally block, and it will run in a separate transaction so it isn't affected by a rollback in the main transaction, and a failure there doesn't affect the main transaction.
If you're not able to use the new grails.transaction.Transactional annotation, use the standard Spring org.springframework.transaction.annotation.Transactional annotation, but you need to make a small change. One of the motivations for the Grails annotation is to provide the same functionality as the Spring annotation, but avoid the problems with calling an annotated method from within the service. The Spring annotation triggers creation of a proxy at runtime which intercepts all calls, manages transactionality for the method, and then calls the real method in the service instance. But with the current code, the call to createPaymentRecord will bypass the proxy (the service instance is just calling itself) and there won't be a new transaction. The Grails annotation rewrites the bytecode to wrap each method in a transaction template which uses the applicable annotation settings (explicit or inferred from a class-scope annotation), so it works correctly internally and externally. If using the Spring annotation, you need to call the method on the proxy, which just involves accessing the Spring bean for this service. Add a dependency injection for the GrailsApplication as a field:
def grailsApplication
and then call createPaymentRecord via
grailsApplication.mainContext.myService.createPaymentRecord()
in the finally block.
By default all methods in a service are transactional, but you can change the behaviour on a method-by-method basis with annotations, e.g.
import grails.transaction.*
// By default all methods are transactional
#Transactional
class MyService {
#NotTransactional
def notTransactional() {
}
// inherits the class-level default
def transactional() {
}
}
See the Grails manual for more details about the transaction annotations.
If you need to manage transactions at a more fine-grained level than per-method, you can use the withTransaction domain class method to manage transactions programatically.
I'm currently using Spring Data with Neo4j and have subclassed the SpringRestGraphDatabase to allow the registration of specific transaction event handlers.
I call the registerTransactionEventHandler method to do so. Unfortunately I always get the following exception:
Caused by: java.lang.UnsupportedOperationException: null
at org.neo4j.rest.graphdb.AbstractRemoteDatabase.registerTransactionEventHandler(AbstractRemoteDatabase.java:52) ~[neo4j-rest-graphdb-1.6.jar:1.6]
at org.neo4j.rest.graphdb.RestGraphDatabase.registerTransactionEventHandler(RestGraphDatabase.java:28) ~[neo4j-rest-graphdb-1.6.jar:1.6]
By looking closely at the AbstractRemote I see that it always throws an exception:
public <T> TransactionEventHandler<T> registerTransactionEventHandler( TransactionEventHandler<T> tTransactionEventHandler ) {
throw new UnsupportedOperationException();
}
The RestGraphDatabase doesn't provide an implementation for the register method hence the exception. I'm not sure what alternatives to use, especially as I'm extending SpringRestGraphDatabase.
Is there a cleaner alternative?
(I'm using v2.1.0.M1)
Yeah,
the exposure of these handlers would be very costly over the network. Depending on what you want to do, I would suggest writing a custom plugin to expose your operations and register what you need via a REST endpoint, see http://docs.neo4j.org/chunked/snapshot/server-plugins.html
Have a transaction in a grails Service class on which a rollback flag is set:
TransactionAspectSupport
.currentTransactionInfo()
.transactionStatus
.setRollbackOnly()
what happens is that when we return to the Controller an exception:
org.springframework.transaction.UnexpectedRollbackException
which we have to catch in the Controller (but not in any of the Service classes). This code is being refactored from the previous solution where all the logic happened direct in the Controller. Any advise on what happens that trips this exception to be thrown when the method returns, given that:
static transactional = true
has been set on all the classes. Guessing theres some subtle Controller verses Service magic happening - does anyone know about this? For now just catching the exception as a workaround, but this loses the TransactionStatus object that otherwise would have been returned.
Any thoughts much appreciated
Transaction management in Grails is pretty ugly (for me).
So i'm proffering Spring declarative transactions:
Chapter 9. Transaction management
They works perfectly in grails services.
Returning back to setRollbackOnly(). This method is not simple... While you have set RollBack=true in your inner transaction you have triggered to rollback your outer transaction to sou you are getting exception.
I've similar problem some time ago - here is useful info to find best solution suiting for you:
AbstractPlatformTransactionManager.setGlobalRollbackOnParticipationFailure(false)
Grails - Declarative Transactions
Declarative transactions don't works in 1.3.x ?