According to the official documentation, and the books I have read, services are transnational be default. however, we were getting records committed, even if we immediately throw a RuntimeException.
e.g:
class MyService {
def someMethod() {
new someDomainObject().save(failOnError:true)
throw new RuntimeException("rollback!")
}
}
and calling it thusly:
class myController{
MyService myService
def someMethod() {
myService.someMethod()
}
}
In the above case, after calling the controller which calls the service, then checking if the row was created by attaching to the DB using mysql workbench, the row was indeed committed and not rolled back.
So we next tried this:
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, this works. However, we dont 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 to static tranasctional=true?
The Service classes were generated by intellij 14 using the "new groovy class" option from the Services folder in the Grails view. The "new Grails Service" option does not work for us, it just does nothing, so we have to create all groovy classes "by hand" in the right place.
OK, found the cause, or Gotcha:
"Annotating a service method with Transactional disables the default Grails transactional behavior for that service"
So I happened to annotate one of the many methods in the service as #Transactional(propagation=Propagation.REQUIRES_NEW), thinking that the others will retain their default of transactional, but no, if you make any declarations, it removes the transactoinal behavior of all other methods silently, even if you say "static transactional = true"
This appears to be rather dangerous, and from now on, I will annotate every service class with #Transactional to avoid being caught out.
This doesn't make a lot of sense. All of the different variants of the service should function the same. The general logic used is to look for #Transactional at the class level or on at least one method. If you use org.springframework.transaction.annotation.Transactional then a transactional proxy will be created. If you use the newer grails.transaction.Transactional then an AST will rewrite methods to use a transaction template, but the net effect is basically the same. If there are no annotations, then unless you have static transactional = false, then the service is transactional and a Spring proxy is created (the same as if you had included the Spring #Transactional annotation at the class level). static transactional = true is never needed since it's the default; the only way for a service to be completely non-transactional is to include static transactional = false and have no #Transactional annotations.
One thing that could be happening is that the underlying table might not be transactional. Newer versions of MySQL default to InnoDB as the table type, but before 5.5 the default was MyISAM. Grails auto-detects the database and registers a Hibernate Dialect for you, and this works well in most cases except for MySQL + MyISAM. To ensure that you always use InnoDB, specify an appropriate Dialect in DataSource.groovy, e.g.
dataSource {
dialect = org.hibernate.dialect.MySQL5InnoDBDialect
}
This will only help with new tables that are created by Hibernate going forward. Be sure to convert any existing MyISAM tables to InnoDB (although in this case that wouldn't be needed since you're using create-drop).
For anyone coming to this question after years of asking, since Grails 3.1 this has been changed. Today at Grails 5.2.5 Services are NOT transactional by default. The "static transactional" property does nothing anymore. You can make a service transactional by annotating it with #Transactional
More has been said about this change here: https://docs.grails.org/latest/guide/services.html#declarativeTransactions
Related
I was getting a "PooledConnection has already been closed" error when executing a controller with a method that performs a groovy sql query against the dataSource like this
class MyController {
def sessionFactory
def viewWeek (ThingCommand cmd) {
def summary = summaryService()
def db = new Sql(sessionFactory.currentSession.connection())
def sqlStrFind = "SELECT * FROM mytable"
def weekList = db.rows(sqlStrFind)
}
}
In Grails 2 I had seen runtime issues when ordering a Service.method call after inline use of a sessionFactory connection, but not the order above.
This led me to try refactoring the inline code into a new Service. This made the code work, but I noticed that #Transactional was annotating the new Service class, so I guessed that annotating class MyController with #Transactional might do the same for the Controller - and I was correct.
What I don't understand is why #Transactional makes a difference when I thought that Controllers and Services were transactional by default - or did something change in Grails 3?
BTW Burt Beckwith promoted the use of sessionFactory connection as this gave you a pooled connection
#virtualdogbert on slack grails-community provided this answer, which answers my question:
Some where in the Grails 3 line they removed the automatic transaction proxies by default, but you could bring them back with a config change
[see application.yml - grails: spring: transactioManagement: proxies: false ]
The #Transaction(Grails version) was added because it used an AST transform rather than a spring proxy, which in my mind makes it more reliable. Using the AST transform, was promoted over using the proxies for this reason.
The #Transactional AST transform also gives you greater control over how your transactions work.
Even though it's shown in examples I wouldn't use #Transactional in controllers, because it's considered bad practice.
Your business logic should be in services - controllers should just be use for routing, and rendering.
I need to to read data from database to be read into Config.groovy.
Is that possible to get data from Database into Config.groovy?
No it is not possible. In the sequence of events when a Grails application is starting up the Config.groovy is processed before the Datasource is made available to the application.
Without knowing what you are trying to accomplish I can't make a suggestion on how else to approach this issue.
Updated (based on comment)
In your comment you explain that you are trying to use the feature switch plugin (which is designed to be run time and not persistent). Looking at the source code for the plugin you should be able to make your own service that will load the settings from the database and toggles/updates the feature switch settings. Here is just a simple sketch/example:
package example
import org.springframework.beans.factory.InitializingBean
class MyExampleService implements InitializingBean {
def grailsApplication
void afterPropertiesSet() {
// here is where you would do whatever you needed to load the settings
grailsApplication.config.features['somefeature'].enabled = true
grailsApplication.config.features['otherfeature'].enabled = false
}
}
That should at least give you an idea.
Alternatively you could just write it all in Bootstrap.groovy which can access the datasource/GORM as well.
I have a service method to transfer funds to/from an external system.
it should create a transaction in our system first (so we have a transactionId)
Then we call the external system.
If the external system fails, we need to rollback the transaction, then write a new record in our payment audit log table, regardless of if the call failed or worked.
I cant figure out how to control the transaction in this case.
I understand services are transactional by default.
I assume I could create 3 methods (they are all 1 method now, which doesn't work as I have no control over what gets committed and what gets rolled back)
createPaymentTransaction()
sendToPaymentSystem()
createPaymentRecord()
I need to rollback 1 if 1 fails, and do nothing more.
I need to rollback 1 if 2 fails, but write 3.
I need to write 3 if 1 and 2 works.
I don't know how to annotate these, or how to structure a 4th request to manage the 3.
I'd go with something like this:
package com.myapp
import grails.transaction.Transactional
import org.springframework.transaction.annotation.Propagation
#Transactional
class MyService {
def createPaymentTransaction() {}
def sendToPaymentSystem() {}
#Transactional(propagation=Propagation.REQUIRES_NEW)
def createPaymentRecord() {}
def method4() {
try {
def transactionId = createPaymentTransaction()
sendToPaymentSystem(transactionId)
}
finally {
createPaymentRecord()
}
}
}
By annotating at the class level, we set the defaults for all methods, but can customize as needed, e.g. for createPaymentMethod.
So what will happen is that calling method4 will join an existing transaction, or start a new one if necessary. If there's a problem in either createPaymentTransaction or sendToPaymentSystem then the transaction will be rolled back, but the call to createPaymentRecord will happen because it's in the finally block, and it will run in a separate transaction so it isn't affected by a rollback in the main transaction, and a failure there doesn't affect the main transaction.
If you're not able to use the new grails.transaction.Transactional annotation, use the standard Spring org.springframework.transaction.annotation.Transactional annotation, but you need to make a small change. One of the motivations for the Grails annotation is to provide the same functionality as the Spring annotation, but avoid the problems with calling an annotated method from within the service. The Spring annotation triggers creation of a proxy at runtime which intercepts all calls, manages transactionality for the method, and then calls the real method in the service instance. But with the current code, the call to createPaymentRecord will bypass the proxy (the service instance is just calling itself) and there won't be a new transaction. The Grails annotation rewrites the bytecode to wrap each method in a transaction template which uses the applicable annotation settings (explicit or inferred from a class-scope annotation), so it works correctly internally and externally. If using the Spring annotation, you need to call the method on the proxy, which just involves accessing the Spring bean for this service. Add a dependency injection for the GrailsApplication as a field:
def grailsApplication
and then call createPaymentRecord via
grailsApplication.mainContext.myService.createPaymentRecord()
in the finally block.
By default all methods in a service are transactional, but you can change the behaviour on a method-by-method basis with annotations, e.g.
import grails.transaction.*
// By default all methods are transactional
#Transactional
class MyService {
#NotTransactional
def notTransactional() {
}
// inherits the class-level default
def transactional() {
}
}
See the Grails manual for more details about the transaction annotations.
If you need to manage transactions at a more fine-grained level than per-method, you can use the withTransaction domain class method to manage transactions programatically.
The Grails FAQ says this:
Q: How can I access domain classes from sources in src/groovy?
Sometimes, you are developing some utility classes that live in src/groovy and which you intend >to use from Services and other artifacts. However, as those classes are pre-compiled by Grails, >it is not possible to instantiate them and write things like Book.findByTitle("Groovy in >Action"). But fortunately, there is a workaround since it's possible to do this:
import org.codehaus.groovy.grails.commons.ApplicationHolder
//…
def book = ApplicationHolder.application.getClassForName("library.Book").findByTitle("Groovy in Action")
The application MUST have finished bootstrapping before the dynamic Gorm methods will function correctly.
However, it appears that I can directly import domain objects and use GORM methods in my src/groovy classes without any problem, e.g.:
Book.findByTitle("Groovy in Action")
Since ApplicationHolder is deprecated, this advice must be out of date, but is there still any reason to avoid using domain classes directly from src/groovy?
You are correct, you referring to an out dated information. You can use domain classes inside classes defined under src/groovy.
The only overhead is that you have to handle transactions manually. On the contrary, services inside grails-app/services handes transaction by default. Services take care of transactions when the transactional flag is set to true (default is true of nothing specified).
On the other hand, when you access domain classes from src/groovy you have to use withTransaction block to handle transactions manually..
Book.withTransaction{status->
def book = Book.findByTitle("Groovy in Action")
book.title = "Grails in Action"
book.save()
status.setRollbackOnly() //Rolls back the transaction
}
Refer withTransaction for details.
I'm using the resources.groovy to declare a service e.g.
aService(com.foo.OrganizationService)
so that I can tie aService to my controllers instead of using organizationService which could change in the future.
I've noticed that the OrganizationService doesn't get treated special like other services "not" declared in the resources.groovy. For example it doesn't get injected with grailsApplication, and likely a hibernateSession etc and other things I've not hit yet....
Now, I know I can manually wire in stuff to my service but I'd rather not have to maintain that...
Is there a special way to declare a service in the resources.groovy so that gets treated like another service that grails loads up?
TIA
The short answer to your question is "no".
Under the covers, Grails services are driven by some intelligent code that is referencing a specific location and expecting certain properties.
Viewing the source code (especially around the ServicesGrailsPlugin.groovy) is a good way to see the "magic" in how these are wired together.
Is there a reason you wouldn't want to use a bonafide Grails service to solve your problem? If you are expecting things like a grailsApplication, it seems like that use is pretty specific to Grails and would be a good candidate for porting over to a "true" Grails service.
Good luck!
So I've come full circle on this. This is a timing problem. Where services haven't been grails initialized yet.
Basically when you use the resources.groovy to do service wiring you run the risk of using a Service that might initialize itself e.g. afterPropertiesSet method or static initializers that use grails services (log, hibernate session, ..) that haven't been injected yet.
So... What I've turned to instead is to create my own BeanBuilder in a BootStrap.groovy file.
BeanBuilder builder = new BeanBuilder(grailsApplication.parentContext)
def bb = builder.beans {
LoginListener(com.foo.LoginListener) {
springSecurityService = ref("springSecurityService")
userService = ref("userService")
}
}
bb.registerBeans(grailsApplication.mainContext)