4

我的 Grails 应用程序没有使用 GORM,而是使用我自己的 SQL 和 DML 代码来读取和写入数据库(数据库是一个巨大的标准化遗留数据库,这是唯一可行的选择)。

所以,我使用Groovy Sql 类来完成这项工作。数据库调用在我的控制器中调用的服务中完成。

此外,我的数据源是通过 Tomcat 中的 DBCP 声明的 - 所以它没有在 Datasource.groovy 中声明。

我的问题是我需要编写一些事务代码,这意味着在一系列成功的 DML 调用之后打开事务并提交,或者在发生错误时回滚整个事情。

我认为分别使用groovy.sql.Sql#commit()groovy.sql.Sql#rollback()就足够了。

但是在这些方法 Javadocs 中,Groovy Sql 文档清楚地说明了

如果此 SQL 对象是从 DataSource 创建的,则此方法不执行任何操作。

所以,我想知道:在我的上下文中执行事务的建议方法是什么?即使在数据源声明中禁用自动提交似乎也无关紧要,因为这两种方法“......什么都不做”

4

2 回答 2

3

Groovy Sql 类有withTransaction

http://docs.groovy-lang.org/latest/html/api/groovy/sql/Sql.html#withTransaction(groovy.lang.Closure)

public void withTransaction(Closure closure)
                     throws java.sql.SQLException

使用缓存连接在事务中执行关闭。如果闭包接受单个参数,它将与连接一起调用,否则将不带参数调用。

试试看。

于 2013-02-13T17:48:04.277 回答
1

谢谢詹姆斯。我还找到了以下解决方案,阅读http://grails.org/doc/latest/guide/services.html

  • 我宣布我的服务是事务性的

    静态事务 = true

这样,如果发生错误,之前执行的 DML 将被回滚。

  • 对于每个 DML 语句,我都会抛出一个描述消息的错误。例如:

    try{
        sql.executeInsert("""
           insert into mytable1 (col1, col2) values (${val1}, ${val2})
        """)
    catch(e){
        throw new Error("you cant enter empty val1 or val2")
    }
    
    try{
        sql.executeInsert("""
           insert into mytable2 (col1, col2) values (${val1}, ${val2})
        """)
    catch(e){
        throw new Error("you cant enter empty val1 or val2. The previous insert is rolledback!")
    }
    

最后的问题!从控制器调用服务时,必须在 try catch 中,如下所示:

try{
    myService.myMethod(params)
}catch(e){
    //http://jts-blog.com/?p=9491
    Throwable t = e instanceof UndeclaredThrowableException ? e.undeclaredThrowable : e
    // use t.toString() to send info to user (use in view)
    // redirect / forward / render etc
}
于 2013-02-14T10:46:04.483 回答