How to I bind a Hibernate Session to a thread in Grails? - grails

I'm writing a multi-threaded application in Grails and the additional threads need access to GORM/Hibernate. When they try to access GORM I get the error "org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here".
OK fair enough, can someone guide me on the best way to set the threads up to have access? The error message almost sounds like you just need to change some config options yet I sense, it is not so simple...

There is a bean in Grails applications called “persistenceInterceptor” that can be used for this.
See this example from the JMS plugin on how to use it:
http://github.com/gpc/grails-jms/blob/master/src/groovy/grails/plugin/jms/listener/adapter/PersistenceContextAwareListenerAdapter.groovy#L21
Here is the interface:
https://github.com/grails/grails-core/blob/master/grails-core/src/main/groovy/grails/persistence/support/PersistenceContextInterceptor.java
And Hibernate impl:
https://github.com/grails/grails-data-mapping/blob/master/grails-datastore-gorm-support/src/main/groovy/org/grails/orm/hibernate4/support/HibernatePersistenceContextInterceptor.java

You need to put any GORM calls in a withTransaction closure. An example taken from a discussion of multi threading at
https://fbflex.wordpress.com/2010/06/11/writing-batch-import-scripts-with-grails-gsql-and-gpars/
Single threaded
user = User.findByUsername( photo.username )
multi threaded
User.withTransaction{
user = User.findByUsername( photo.username )
}

withNewSession will also work. In my case, I have low priority updates where the last update can always "win". version: false is also important here in order to avoid the StaleObjectException:
Thread.start {
try {
Widget.withNewSession {
xxx()
log.info "Asynchronously did some updates."
}
} catch (Exception ex) {
log.error "Failed to asynchronously do something...", ex
}
}

Luke Daley gave the right answer. Unfortunately, the links have changed. Thus, I'll update his answer and provide a code example to make this answer self-contained.
There is a bean in Grails applications called persistenceInterceptor that can be used for initializing the persistence context / session for Hibernate. You can inject the bean into one of your controller / service classes and start a new thread, e.g. using the following code snippet.
class YourControllerOrService {
PersistenceContextInterceptor persistenceInterceptor
def someOperation() {
...
Runnable yourTask = { ->
try {
if (persistenceInterceptor) {
persistenceInterceptor.init()
}
// execute the hibernate operations here in a transaction,
// e.g. call a method annotated with #Transactional
...
} catch (Exception e) {
log.error('Your error message', e)
} finally {
if (persistenceInterceptor) {
persistenceInterceptor.flush()
persistenceInterceptor.destroy()
}
}
}
Thread workerThread = new Thread(yourTask)
workerThread.start()
...
}
}
You'll find an exemplary implementation in the Grails JMS plug-in on GitHub.
The PersistenceContextInterceptor interface can be found on GitHub, too.

Related

How to know if data was persisted during database transaction after method returning?

I have a method written in a Grails service, which processes a lot of data.
I noticed that, sometimes, the method returns success but the data is not persisted to the database.
I debugged it, following all the data till the end of the method and everything is fine, however data is not persisted.
The following image demonstrates the what I just explained. You can see the end of the method, in which a Map object is filled with persistent object metadata. Even you can see the console which contains the printend Hibertate SQL
How can I detect whether a rollback mechanism is thrown after successful method returning?
This is my connection properties for Oracle 12c database. Others configurations are Grails defaults
dataSource.pooled=true
hibernate.jdbc.use_get_generated_keys=true
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=false
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
dataSource.driverClassName=oracle.jdbc.driver.OracleDriver
dataSource.dialect=org.hibernate.dialect.OracleDialect
dataSource.url=jdbc:oracle:thin:#172.16.1.20:1521:db
dataSource.username=<USER>
dataSource.password=<PASS>
hibernate.default_schema=<SCHEMA>
The service is anotated as #Transactional
#Transactional
class SincronizacionService {
}
Any Idea?
When using GORM's save method, also use failOnError:true. By default, save method silently fails. However, if you use failOnError:true, it will throw an exception if the data is not persisted.
If you do not want to stop the program when the data fails to save, you can use the try-catch block to log data that failed to save and let the algorithm continue to do it work.
Hope that helps.
I found the problem. In this method actaDenunciaService.generarActaDenuncia(denuncia), there is a peculiarity. In a part of the method is located the following snippet:
try {
DNomenclador nomenclador = nomencladorService.obtenerNomencladorDNomenclador(meta.valor.toLong())
if (!nomenclador) {
return toReturn(limpiarTexto(meta.valor))
} else {
return toReturn(nomenclador.valor)
}
} catch (Exception e) {
return toReturn(limpiarTexto(meta.valor))
}
A team member changed this line nomencladorService.obtenerNomencladorDNomenclador(meta.valor.toLong()). The change represented a huge improvement of memory saving. However, the team member did not take into account a business process, which does not take into account the method he used.
Yes, a runtime exception is being thrown.
And the treatment, depending on the objective of the method, is correct
For the future, this is how the method will be from now on:
try {
DNomenclador nomenclador = nomencladorService.obtenerNomencladorDNomencladorLibre(meta.valor.toLong())
if (!nomenclador) {
return toReturn(limpiarTexto(meta.valor))
} else {
return toReturn(nomenclador.valor)
}
} catch (Exception e) {
e.printStackTrace()
return toReturn(limpiarTexto(meta.valor))
}
nomencladorService.obtenerNomencladorDNomencladorLibre(meta.valor.toLong()) for the business process
e.printStackTrace() for tracing any other peculiarity
Thanks a lot to everybody who had collaborated on finding this error
I found the error!
An error thrown inside a method for generating a PDF document with data, appearsto be failing. The second line shows this
try {
denuncia.xmlFirmadoServ = dfileManagerService.guardarDFile(signatureResponse.resultado, "xmlfirmadoservidor.xml", usuario)
denuncia = actaDenunciaService.generarActaDenuncia(denuncia).denuncia
} catch (Throwable t) {
denunciaUtilService.incrementarNumeroDenuncia(true)
throw t
}
Now, the new question is: If the method is encapsulated inside a try/catchblock, why the catch block is not excecuting?
When I comment the 2nd line inside try/catch block, data is persisted on database
With no comments, generation PDF method is executed till the end, doing all what it must do

Spring #Transactional and Neo4j OGM session.getTransaction()

What is the correlation between Spring org.springframework.transaction.annotation.Transactional annotation and Neo4j OGM org.neo4j.ogm.session.Session.getTransaction() method.
I'm trying to access the current transaction via session.getTransaction() inside of the method annotated with Spring #Transactional but always getting null.
I have added a following code inside of my Spring MVC RestController method:
Transaction tx = session.beginTransaction();
try {
for (int i = 0; i < 10; i++) {
initializeNode(node);
}
}
tx.commit();
} catch (Throwable th) {
logger.error("Error while inserting mock data", th);
th.printStackTrace();
} finally {
tx.close();
}
in case of the following method:
private void initializeNode(TestNode node) {
System.out.println(session.getTransaction());
}
it prints current tx - so far everything is okay.
But in case of the following method:
private void initializeNode(TestNode node) {
System.out.println(session.getTransaction());
User admin = userDao.findByUsername("admin");
}
first time it prints current tx and then null... transaction disappear before commit for a some reason..
this is findByUsername method:
#Service
#Transactional
public class UserDaoImpl implements UserDao {
#Override
#Transactional(readOnly = true)
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
...
}
Right after that on commit I'm getting a following exception:
org.neo4j.ogm.exception.TransactionManagerException: Transaction is not current for this thread
at org.neo4j.ogm.session.transaction.DefaultTransactionManager.commit(DefaultTransactionManager.java:100)
at org.neo4j.ogm.transaction.AbstractTransaction.commit(AbstractTransaction.java:83)
at org.neo4j.ogm.drivers.embedded.transaction.EmbeddedTransaction.commit(EmbeddedTransaction.java:77)
What am I doing wrong ? Why transaction disappears ?
There are several issues and themes going on in this question. I will try and break them down and hopefully at the end it will all make sense.
As of the latest release of Spring Data Neo4j (4.1.x) there is no correlation between Spring's #Transactional and the Neo4j OGM's Session.getTransaction() or Session.beginTransaction() when called directly.
In your first two code blocks you are completely managing your OGM session lifecycle directly. Spring is not involved at all at this point and as you say it executes as expected.
In your updated third code block you are now expecting the session that you have manually opened to work with your Spring managed DAO. What will happen here is depends on the Neo4j Driver you are using with SDN but essentially because your DAO has the #Transactional annotation, Spring will intercept the call and start a brand new transaction all on its own on top of the one you are manually managing. At this point, we can't make any guarantees about the behaviour but the easiest explanation would be to say that it will be unexpected (again, depending on the driver used).
So how can you fix this?
I'm going to assume you want to use Spring Transactions and Spring Data Neo4j. If that's the case you will want to start by:
Changing your DAO to use Spring Data Repositories. This gives you a lot of free persistence functionality like finders, saves, deletes etc.
Putting the #Transactional annotation around the unit of work you want to accomplish. You might have a method that calls userRepository.findByUserName(), modifies that user and calls userRepository.save(user). In a web environment this is typically some sort of service method.
Removing any code that manually starts or ends an OGM session transaction.
You can find a very short code sample here and a longer code sample here.
A more comprehensive guide can also be found here.
In Spring Data Neo4j 4.2.x we hope to introduce some more powerful and friendlier #Transactional behaviour so keep posted for that update.

Grails manual transactions with no domain classes

I'm not sure if I'm missing something here but is it possible to do manual transaction management in Grails (in groovy classes in src/groovy) without using the withTransaction method?
I don't have any domain classes in my app as I'm calling into the service layer of another Java web application.
Service methods are transactional by default. This is the easiest way to get transactional behavior in grails:
class SomethingService {
def doSomething() {
// transactional stuff here
}
}
If you need finer grained control than this, you can start and end transactions programmatically through hibernate:
class CustomTransactions {
def sessionFactory
def doSomething() {
def tx
try {
tx = sessionFactory.currentSession.beginTransaction()
// transactional stuff here
} finally {
tx.commit()
}
}
}
The only way to start transactions in a Grails app are those mentioned in this answer.
I don't have any domain classes in my app as I'm calling into the service layer of another Java web application.
Is this really a separate application or just a Java JAR that your Grails app depends on? If the former, then the transactions should be managed by the application doing the persistence.
Above method is also correct.
You can also use #Transactional(propagation=Propagation.REQUIRES_NEW)
class SomethingService{
def callingMathod(){
/**
* Here the call for doSomething() will
* have its own transaction
* and will be committed as method execution is over
*/
doSomething()
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
def doSomething() {
// transactional stuff here
}
}

Groovy method interception

In my Grails app I've installed the Quartz plugin. I want to intercept calls to every Quartz job class' execute method in order to do something before the execute method is invoked (similar to AOP before advice).
Currently, I'm trying to do this interception from the doWithDynamicMethods closure of another plugin as shown below:
def doWithDynamicMethods = { ctx ->
// get all the job classes
application.getArtefacts("Job").each { klass ->
MetaClass jobMetaClass = klass.clazz.metaClass
// intercept the methods of the job classes
jobMetaClass.invokeMethod = { String name, Object args ->
// do something before invoking the called method
if (name == "execute") {
println "this should happen before execute()"
}
// now call the method that was originally invoked
def validMethod = jobMetaClass.getMetaMethod(name, args)
if (validMethod != null) {
validMethod.invoke(delegate, args)
} else {
jobMetaClass.invokeMissingMethod(delegate, name, args)
}
}
}
}
So, given a job such as
class TestJob {
static triggers = {
simple repeatInterval: 5000l // execute job once in 5 seconds
}
def execute() {
"execute called"
}
}
It should print:
this should happen before execute()
execute called
But my attempt at method interception seems to have no effect and instead it just prints:
execute called
Perhaps the cause of the problem is this Groovy bug? Even though the Job classes don't explicitly implement the org.quartz.Job interface, I suspect that implicitly (due to some Groovy voodoo), they are instances of this interface.
If indeed this bug is the cause of my problem, is there another way that I can do "before method interception"?
Because all the job classes are Spring beans you can solve this problem using Spring AOP. Define an aspect such as the following (adjust the pointcut definition so that it matches only your job classes, I've assumed they are all in a package named org.example.job and have a class name that ends with Job).
#Aspect
class JobExecutionAspect {
#Pointcut("execution(public * org.example.job.*Job.execute(..))")
public void executeMethods() {}
#Around("executeMethods()")
def interceptJobExecuteMethod(ProceedingJoinPoint jp) {
// do your stuff that should happen before execute() here, if you need access
// to the job object call jp.getTarget()
// now call the job's execute() method
jp.proceed()
}
}
You'll need to register this aspect as a Spring bean (it doesn't matter what name you give the bean).
You can have your customized JobListener registered in the application to handle logics before execute() is triggered. You can use something like:-
public class MyJobListener implements JobListener {
public void jobToBeExecuted(JobExecutionContext context) {
println "Before calling Execute"
}
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException) {}
public void jobExecutionVetoed(JobExecutionContext context) {}
}
Register the customized Job Listener to Quartz Scheduler in Bootstrap:-
Scheduler scheduler = ctx.getBean("quartzScheduler") //ctx being application context
scheduler.getListenerManager().addJobListener(myJobListener, allJobs())
resources.groovy:-
beans = {
myJobListener(MyJobListener)
}
One benefit I see here using this approach is that we don't need the second plugin used for method interception any more.
Second, we can register the listener to listen all jobs, specific jobs, and jobs in a group. Refer Customize Quartz JobListener and API for JobListener, TriggerListener, ScheduleListener for more insight.
Obviously, AOP is another approach if we do want want to use Quartz API.
You are not getting the job classes like that. If you refer to the Quartz plugin, you can get them by calling jobClasses:
application.jobClasses.each {GrailsJobClass tc -> ... }
see https://github.com/nebolsin/grails-quartz/blob/master/QuartzGrailsPlugin.groovy
If you actually look, you can see that they are almost doing what you are trying to acheive without the need to use aop or anything else.
For method interception implement invokeMethod on the metaclass. In my case the class was not of third party so I can modify the implementation.
Follow this blog for more information.

Is this a valid way to code up an MVC Service Layer?

In my MVC service layer I have code such as the following to validate:
protected bool ValidateAccount(Account account)
{
var accounts = _accountRepository.GetPk(account.PartitionKey);
if (accounts.Any(b => b.Title.Equals(account.Title) &&
!b.RowKey.Equals(account.RowKey)))
_validationDictionary.AddError("", "Duplicate title");
return _validationDictionary.IsValid;
}
However in the "action type" methods I absorb exceptions with code like this:
public bool Create(Account account)
{
if (!ValidateAccount(account))
return false;
try
{
_accountRepository.AddOrUpdate(account);
}
catch
{
return false;
}
return true;
}
My controller is coded like this:
public ActionResult Create(BaseViewModel vm)
{
_accountService = new AccountService(new ModelStateWrapper(this.ModelState), vm.Meta.DataSourceID);
if (ModelState.IsValid)
{
_accountService = new AccountService(new ModelStateWrapper(this.ModelState), vm.Meta.DataSourceID);
if (!_accountService.Create(vm.Account))
return View("CreateEdit", vm);
else
return RedirectToAction("Created");
}
return RedirectToAction("Home");
}
return View("CreateEdit", vm);
}
Is this a reasonable approach to take? My one concern is that I might be losing exception information in the service layer.
You should at the very least log your exception somewhere (event log, file system, using Elmah, etc).
The problem with your code is that you'll never know if something bad happened in production environment or you won't be able to discover what failed exactly (just that the code returned false).
Plus, you should never handle all exceptions like you do (unfiltered catch) but only the one you can revert back to a normal state. It's far better to let the application crash than to keep it online unstable.
Avoid handling errors by catching non-specific exceptions, such as System.Exception, System.SystemException, and so on, in application code. There are cases when handling errors in applications is acceptable, but such cases are rare.
See this MSDN article on best practices for handling exceptions and Design Guidelines for Exceptions
Since you are not doing anything with the exception in your Create method in the service layer, I would suggest removing the try/catch from it.
I would still return true or false to indicate whether the create operation was successful. I will however add a try/catch in the caller to make sure exceptions are handled. In your case that could be in your controller action (or the OnException in your base controller.)
Another approach is to leave the try/catch in your Create method but as #Stephane suggested do something with it (like log it) but you could also log it wherever you catch it.

Resources