2

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

Debugging

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?

  • I just edited the question title, so maybe there is a better understanding of it – lealceldeiro Nov 23 '17 at 20:08
  • Probably with your _setup_ you have to manually call the commit on the transaction. Can you share your hibernated configuration ? Which transaction manager are you using ? In which environment are you ? – gtosto Nov 23 '17 at 20:24
  • 1
    The code belongs to a Grails application. I edited the question with my custom configuration. This happens in all enviroments [developments | test | production]. The service is annotated with @Transactional too – Leandro Roura Sixto Nov 23 '17 at 20:40
  • please provide the sequence or code sample to re-generate the issue. – devbd Nov 23 '17 at 20:53
  • Did you check there is no RuntimeException in the transaction scope? – Sergei Dubinin Nov 24 '17 at 11:17
  • @SergeiDubinin, Yes, I did. No RuntimeException occurs – Leandro Roura Sixto Nov 24 '17 at 16:52
  • I am going to try with a recomendation of a friend of using @Transactional(propagation = Propagation.NOT_SUPPORTED) in the method. Just trying – Leandro Roura Sixto Nov 24 '17 at 16:53
  • The solution that I planted to do previously did not work for me. I obtained the same result by combining the annotation with the closures with[New]Transaction and with[New]Session. Any other idea? – Leandro Roura Sixto Nov 24 '17 at 22:50

3 Answers3

2

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.

elixir
  • 1,394
  • 1
  • 11
  • 21
2

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

lealceldeiro
  • 14,342
  • 6
  • 49
  • 80
1

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