Grails服务不是交易性的吗?

时间:2015-02-26 14:05:02

标签: grails service transactions

根据官方documentation和我读过的书籍,服务是跨国的默认。但是,即使我们立即抛出RuntimeException,我们也会提交记录。

e.g:

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

并且这样称呼它:

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

在上面的例子中,在调用调用服务的控制器之后,然后检查是否通过使用mysql工作台附加到数据库来创建行,该行确实已提交但未回滚。

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

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 tranasctional = true不同吗?

服务类是由intellij 14使用" new groovy class"生成的。 Grails视图中Services文件夹中的选项。新的Grails服务"选项对我们不起作用,它什么都不做,所以我们必须手工创建所有的常规课程#34;在正确的地方。

2 个答案:

答案 0 :(得分:10)

好的,找到原因,或者知道:

“使用Transactional注释服务方法会禁用该服务的默认Grails事务行为”

所以我碰巧注释了服务中的许多方法中的一个@Transactional(propagation=Propagation.REQUIRES_NEW),认为其他方法将保留其默认的事务,但是,如果你做出任何声明,它就会删除所有的交易行为。其他方法默默无闻,即使你说“static transactional = true

这似乎相当危险,从现在开始,我将使用@Transactional注释每个服务类,以避免陷入困境。

答案 1 :(得分:3)

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

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

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

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