Grails服务不是事务性的



根据官方文件和我读过的书,服务是跨国的。然而,即使我们立即抛出RuntimeException,我们也会提交记录。

例如:

class MyService {
    def someMethod() {
        new someDomainObject().save(failOnError:true)
        throw new RuntimeException("rollback!")
    }
}

并如此称呼它:

class myController{
   MyService myService
    def someMethod() {
         myService.someMethod()
    }
}

在上面的例子中,在调用调用服务的控制器,然后检查行是否是通过使用mysql工作台连接到DB创建的之后,该行确实被提交,并且没有回滚。

所以我们接下来尝试了这个:

class MyService {
    static transactional = true
    def someMethod() {
        new someDomainObject().save(failOnError:true)
        throw new RuntimeException("rollback!")
    }
}

同样的问题。

接下来我们尝试了这个:

@Transactional
class MyService {
    static transactional = true
    def someMethod() {
        new SomeDomainObject().save(failOnError:true)
        throw new RuntimeException("rollback!")
    }
}

最后,这是可行的。然而,我们不明白为什么。

注:Grails 2.4.4使用MYSQL:

development {
    dataSource {
        dbCreate = "create-drop"
        url = "jdbc:mysql://127.0.0.1:3306/db"
        username = "user"
        password = "***"
    }
}

这是正常行为吗
@Transactional与static transascional=true不同吗?

服务类是intellij14使用Grails视图中Services文件夹中的"newgroovyclass"选项生成的。"new Grails Service"选项对我们不起作用,它什么都不起,所以我们必须在正确的位置"手动"创建所有groovy类。

确定,找到原因,或找到:

"用Transactional注释服务方法将禁用该服务的默认Grails事务行为"

因此,我碰巧将服务中的许多方法中的一个注释为@Transactional(propagation=Propagation.REQUIRES_NEW),认为其他方法将保留其默认的transactional,但不,如果您进行任何声明,它将静默地删除所有其他方法的transactionalbehavior,即使您说"static transactional = true"

这看起来相当危险,从现在起,我将用@Transactional注释每个服务类,以避免被发现。

这没有多大意义。服务的所有不同变体的功能都应该相同。所使用的一般逻辑是在类级别或至少一个方法上查找@Transactional。如果使用org.springframework.transaction.annotation.Transactional,则会创建一个事务代理。如果使用较新的grails.transaction.Transactional,那么AST将重写方法以使用事务模板,但最终效果基本相同。如果没有注释,那么除非您有static transactional = false,否则服务是事务性的,并且会创建一个Spring代理(与在类级别包含Spring @Transactional注释相同)。static transactional = true是默认值,因此永远不需要;服务完全非事务性的唯一方法是包括CCD_ 10并且不具有CCD_。

可能发生的一件事是,底层表可能不是事务性的。MySQL的较新版本默认使用InnoDB作为表类型,但在5.5之前,默认使用MyISAM。Grails自动检测数据库并为您注册Hibernate方言,这在除MySQL+MyISAM之外的大多数情况下都能很好地工作。为了确保始终使用InnoDB,请在DataSource.groovy中指定适当的方言,例如

dataSource {
   dialect = org.hibernate.dialect.MySQL5InnoDBDialect
}

这只会对Hibernate创建的新表有所帮助。请确保将任何现有的MyISAM表转换为InnoDB(尽管在这种情况下,由于您使用的是create-drop,因此不需要转换)。

对于经过多年询问后提出这个问题的人来说,自从Grails 3.1以来,这个问题已经改变了。如今,在Grails 5.2.5中,默认情况下服务不是事务性的。";静态事务";房地产什么都不做了。您可以通过使用@Transactional 对服务进行注释来使其具有事务性

关于这一变化,这里有更多的说法:https://docs.grails.org/latest/guide/services.html#declarativeTransactions

最新更新