Grails service layer is the proper place to put all the application logic. Services are transactional and also good place to make your applications code reusable.
In this article will show how to store user with a new account in a transaction. So, when account is saved but saving user fails the transaction is rolled back. That results in scenario that nothing is storred, user nor account.
Step 1
Create domain class that represents an account: grails create-domain-class com.myapp.Account.
classAccount {static constraints = { }}
Step 2
Create domain class that represents an user that will have a reference to an accont: grails create-domain-class com.myapp.User.
In this step we create AccountService that will be transactional, meaning that all methods in the service will be executed in a transaction. When an exception that extends RuntimeException is thrown, the transaction will be rolled back automatically.
It is also possible to define transactional behavior on method level.
Run grails create-service com.myapp.AccountService to create the service.
importgrails.transaction.Transactional@Transactionalclass AccountService { void createUserWithAccount(String username, String password) { Account account = new Account() account.save(failOnError: true) User user = new User() user.username = username user.password = password user.account = account user.save(failOnError: true) throw new RuntimeException("unexpected exception to simulate failure") }}
Instead of defining failOnError: true everywhere, it is possible to enable failOnError globalygrails.gorm.failOnError = true in Config.groovy.
Step 4
Create a view that will execute createUserWithAccount with dummy values. After the method is executed, try to fetch values from database and print it into the console to see nothing is stored in database because we let the transaction fail.
When we run the application and a runtime exception is thrown in the service method, we should see no database items fetched from the database. Have a look the console output to see what has happend.
failed: database connection failed
[]
[]
After we remove throwing a runtime exception exception: