根据官方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;在正确的地方。
答案 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,因此不需要)。