【问题标题】:How to know if data was persisted during database transaction after method returning?方法返回后如何知道数据是否在数据库事务期间持久化?
【发布时间】:2017-11-23 19:55:13
【问题描述】:

我有一个用 Grails 服务编写的方法,它处理大量数据。
我注意到,有时该方法返回成功,但数据并未持久化到数据库中。

我调试了它,跟踪所有数据直到方法结束,一切都很好,但是数据没有持久化。

下图演示了我刚才解释的内容。您可以看到该方法的结尾,其中一个 Map 对象填充了持久对象元数据。甚至你可以看到包含 printend Hibertate SQL 的控制台

方法返回成功后如何检测是否抛出回滚机制?

这是我的 Oracle 12c 数据库的连接属性。其他配置是 Grails 的默认配置

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>

服务被注释为@Transactional

@Transactional
class SincronizacionService {

}

有什么想法吗?

【问题讨论】:

  • 我只是编辑了问题标题,所以也许对它有更好的理解
  • 可能使用您的 setup 您必须手动调用事务的提交。你能分享你的休眠配置吗?您使用的是哪个事务管理器?你在哪个环境?
  • 代码属于 Grails 应用程序。我用我的自定义配置编辑了这个问题。这发生在所有环境中 [发展 |测试 |生产]。该服务也使用 @Transactional 注释
  • 请提供序列或代码示例以重新生成问题。
  • 你检查事务范围内没有RuntimeException吗?

标签: grails transactions grails-orm


【解决方案1】:

当使用 GORM 的保存方法时,也要使用 failOnError:true。默认情况下,保存方法会静默失败。但是如果你使用failOnError:true,如果数据没有持久化就会抛出异常。

如果您不想在数据保存失败时停止程序,可以使用 try-catch 块记录保存失败的数据,让算法继续工作。

希望对您有所帮助。

【讨论】:

  • 我会测试它。几分钟后我会回复你的
【解决方案2】:

我发现了问题。在这种方法actaDenunciaService.generarActaDenuncia(denuncia) 中,有一个特殊性。在部分方法中位于如下sn -p:

            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))
            }

一位团队成员更改了此行 nomencladorService.obtenerNomencladorDNomenclador(meta.valor.toLong())。这一变化代表了内存节省的巨大改进。但是,团队成员没有考虑到业务流程,也没有考虑到他使用的方法。

是的,正在引发运行时异常。

根据方法的目标,治疗是正确的

对于未来,这就是从现在开始的方法:

            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()) 用于业务流程
  • e.printStackTrace() 用于追踪任何其他特性

非常感谢所有合作发现此错误的人

【讨论】:

    【解决方案3】:

    我发现了错误!

    在生成包含数据的 PDF 文档的方法中引发的错误似乎失败了。第二行显示了这个

            try {
                denuncia.xmlFirmadoServ = dfileManagerService.guardarDFile(signatureResponse.resultado, "xmlfirmadoservidor.xml", usuario)
                denuncia = actaDenunciaService.generarActaDenuncia(denuncia).denuncia
            } catch (Throwable t) {
                denunciaUtilService.incrementarNumeroDenuncia(true)
                throw t
            }
    

    现在,新的问题是:如果方法封装在try/catchblock 中,为什么catch 块没有执行?

    当我注释try/catch 块内的第二行时,数据会保存在数据库中

    没有cmets,生成PDF方法执行到最后,做它必须做的一切

    【讨论】:

      猜你喜欢
      • 2013-06-19
      • 1970-01-01
      • 2014-05-04
      • 1970-01-01
      • 1970-01-01
      • 2018-08-24
      • 2013-08-12
      • 1970-01-01
      相关资源
      最近更新 更多