Are Grails Services not Transactional?

According to the official documentation and the books I read, the services are transnational by default. however, we were getting records even if we immediately throw a RuntimeException.

eg:

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

and calling it like this:

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

In the above case, after calling the controller that calls the service, then, checking whether the row was created by attaching to the database using mysql tools, the row was actually executed and not rolled back.

So, we tried the following:

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

Same problem.

Next we tried this:

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

Finally it works. However, we do not understand why.

Note: Grails 2.4.4 using MYSQL:

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

Is this normal behavior?
Is @Transactional different from static tranasctional = true?

Service classes were generated using intellij 14 using the "new groovy class" option from the Services folder in the Grails view. The option “new Grails service” does not work for us, it just doesn’t do anything, so we have to create all the groovy classes “manually” in the right place.

+5
source share
2 answers

OK, found a reason or gotcha:

"Annotating a service method with Transactional disables the default Grails transactional behavior for this service."

Thus, I managed to annotate one of the many methods in the service like @Transactional(propagation=Propagation.REQUIRES_NEW) , assuming that the others will keep their transaction failure, but no, if you make any declarations, it deletes the transactional behavior of all other methods quiet even if you say " static transactional = true "

This seems pretty dangerous, and from now on I will annotate each class of service using @Transactional so as not to be caught.

+10
source

It doesn’t make much sense. All different service options should work the same. The common logic used is to search for @Transactional at the class level or at least by one method. If you use org.springframework.transaction.annotation.Transactional then a transaction proxy will be created. If you use the new grails.transaction.Transactional , then the AST rewrites the methods for using the transaction template, but the network effect is basically the same. If there are no annotations, then if you have static transactional = false , then the service is transactional and a Spring proxy is created (just as if you turned on Spring @Transactional annotation at the class level). static transactional = true never required since it is by default; the only way a transaction is complete for a service is to enable static transactional = false and not have @Transactional annotations.

One thing that can happen is that the underlying table may not be transactional. Newer versions of MySQL default to InnoDB as the table type, but prior to 5.5, MyISAM was the default. Grails automatically detects the database and logs Hibernate dialogs for you, and this works well in most cases except MySQL + MyISAM. To ensure that you always use InnoDB, specify the appropriate dialect in DataSource.groovy, for example.

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

This will only help with new tables created by Hibernate in the future. Be sure to convert any existing MyISAM tables to InnoDB (although this is not necessary in this case, since you are using drop-drop).

+3
source

Source: https://habr.com/ru/post/1214243/


All Articles