How to create new transaction within existing transaction in Grails - grails

I have Machine and Parts domain class
In my service class I am trying to start a transaction, inside that transaction i want to create a new transaction and commit it when it comes out of the inner transaction.
Machine.withTransaction { // transaction 1
// some code to add Parts
// some code to remove Parts
Machine.withNewTrasaction { // transaction 2
// some code to remove Parts.
} // end of transaction 2
// some code to update couple of columns in machine table.
}// end of transaction 1
When it comes out of transaction 2 I want transaction 2 be commited the Parts for the Machine irrespective to transaction 1.But grails is throwing an error back as "Illegal attempt to associate a collection with two open sessions"
How to commit the transaction 2 alone separately without considering the transaction 1?

You can try handling transaction explicitly using #Transactional annotation inside the service class.
Notes:-
Once you add #Transactional annotation to service method, the service class is not deemed transactional by default.
Since you splitting the functionality into two methods, you have to use the proxied instance of the service class to call the second method otherwise you cannot create a new transaction for the second method. Hence, use of applicationContext below in method 1.
You would not need withTransaction or withNewTransaction block any more.
Service class would look like:
class MachineService{
#Transactional
def someMethodToAddParts(){
......
grailsApplication.mainContext.machineService.someMethodToRemoveParts()
......
}
#Transactional(propagation = TransactionDefinition.PROPAGATION_REQUIRES_NEW)
def someMethodToRemoveParts(){
.......
}
}

I've encountered a slightly different problem, maybe it can help somebody, and maybe it could help for the above problem.
I think that the above problem could be avoided by merging entities to the new transaction, then use .merge() method on the collection causing the problem.
First I think the above code looks like this (I've added comments to explain) :
Machine.withTransaction { // transaction 1
// some code to add Parts
yourEntity.addToParts(...)
// some code to remove Parts
Machine.withNewTrasaction { // transaction 2
// some code to remove Parts.
yourEntity.removeFromParts(...)
} // end of transaction 2 -> the session is flushed, and the transaction is committed
// during the flush, hibernate detect that "parts" collection is already attached
// to another session, in another transaction then throw "Illegal
// attempt to associate a collection with two open sessions"
// some code to update couple of columns in machine table.
}
Then the solution is to merge the collection to the new transaction, it give us something like this :
Machine.withTransaction { // transaction 1
// some code to add Parts
yourEntity.addToParts(...)
// some code to remove Parts
Machine.withNewTrasaction { // transaction 2
// some code to remove Parts.
yourEntity.removeFromParts(...)
// Merging the collection to the session
yourEntity.merge() // I haven't tried but maybe you need ensure
// there is a merge cascade on "parts" collection
} // end of transaction 2 -> the session is flushed, and the transaction is committed
// some code to update couple of columns in machine table.
}
In my case, with a merge in the new transaction, I solved the error message "A different object with the same identifier value was already associated with the session : [yourPackage.YourEntity]" (when I talk about YourEntity, you can also read YourDomaineClass)

Related

Command object only in controller or could it be passed to service layer?

In Grails framework I saw the command object pattern but its use is not very clear for me. In addition most of examples given by Grails documentation are about domain classes not command objects (maybe to simplify code example).
1 - Command object is something used between view and controller layer and must stay there ?
2 - Or is it a good practice to pass command object to service layer ?
To illustrate point 2 :
class MyController {
def updateUserPassword (UserPasswordCommand cmd) {
...
myService.updatePassword(cmd)
...
}
}
If point 2 is a bad practice, then how do you pass submitted data to the service layer ? Via domain class ?
EDIT : Seems OK
[EDIT]
If I use command object and not domain class what to do in this case :
def signup(UserCreateCommand cmd)
{
if (!cmd.hasErrors()) {
def userInstance = userService.signup(cmd)
}
}
if (cmd.hasErrors()) {
/* Stay on form in order to display errors */
render(view:"/app/authentication/_signupForm", model:[userCreateCommand: cmd])
return
}
...
}
what happen if when user service transaction ends, there is an exception raided by database (because of flushing data not respecting schema constraints) ?
The problem in my point of view is that there are two queries :
Firstly - when call cmd.hasErrors() there is a persistent call for unique constraint on email for example
Secondly - when service transaction ends, there is a flush to DB (which result in one SQL insert in my case), and maybe raises an exception on column email which has unique constraint
Test cmd.hasErrors() doesn't prevent the case where DB raises a violated constraint unique exception or I'm wrong ?
That's the best way to pass request params to service layer. I have seen people passing params to service which is really a worst practice. Our controllers should be dump, Max 5-8 LOC in controller method is a guideline in my company.
Command object gives you so much power out of the box like validation, method etc.
Constraints like unique which needs to validated from database cannot be applied on command object. In this case you can use validator http://grails.github.io/grails-doc/2.5.1/ref/Constraints/validator.html.
You can also use importFrom constraint to have all the constraint form User domain to command object http://grails.github.io/grails-doc/2.5.1/guide/validation.html.

When does grails check for Object Staleness?

I'm using Grails 2.5.1, and I have a controller calling a service method which occasionally results in a StaleObjectStateException. The code in the service method has a try catch around the obj.save() call which just ignores the exception. However, whenever one of these conflicts occurs there's still an error printed in the log, and an error is returned to the client.
My GameController code:
def finish(String gameId) {
def model = [:]
Game game = gameService.findById(gameId)
// some other work
// this line is where the exception points to - NOT a line in GameService:
model.game = GameSummaryView.fromGame(gameService.scoreGame(game))
withFormat {
json {
render(model as JSON)
}
}
}
My GameService code:
Game scoreGame(Game game) {
game.rounds.each { Round round ->
// some other work
try {
scoreRound(round)
if (round.save()) {
updated = true
}
} catch (StaleObjectStateException ignore) {
// ignore and retry
}
}
}
The stack-trace says the exception generates from my GameController.finish method, it doesn't point to any code within my GameService.scoreGame method. This implies to me that Grails checks for staleness when a transaction is started, NOT when an object save/update is attempted?
I've come across this exception many times, and generally I fix it by not traversing the Object graph.
For example, in this case, I'd remove the game.rounds reference and replace it with:
def rounds = Round.findAllByGameId(game.id)
rounds.each {
// ....
}
But that would mean that staleness isn't checked when the transaction is created, and it isn't always practical and in my opinion kind of defeats the purpose of Grails lazy collections. If I wanted to manage all the associations myself I would.
I've read the documentation regarding Pessimistic and Optimistic Locking, but my code follows the examples there.
I'd like to understand more about how/when Grails (GORM) checks for staleness and where to handle it?
You don't show or discuss any transaction configuration, but that's probably what's causing the confusion. Based on what you're seeing, I'm guessing that you have #Transactional annotations in your controller. I say that because if that's the case, a transaction starts there, and (assuming your service is transactional) the service method joins the current transaction.
In the service you call save() but you don't flush the session. That's better for performance, especially if there were another part of the workflow where you make other changes - you wouldn't want to push two or more sets of updates to each object when you can push all the changes at once. Since you don't flush, and since the transaction doesn't commit at the end of the method as it would if the controller hadn't started the transaction, the updates are only pushed when the controller method finishes and the transaction commits.
You'd be better off moving all of your transactional (and business) logic to the service and remove every trace of transactions from your controllers. Avoid "fixing" this by eagerly flushing unless you're willing to take the performance hit.
As for the staleness check - it's fairly simple. When Hibernate generates the SQL to make the changes, it's of the form UPDATE tablename SET col1=?, col2=?, ..., colN=? where id=? and version=?. The id will obviously match, but if the version has incremented, then the version part of the where clause won't match and the JDBC update count will be 0, not 1, and this is interpreted to mean that someone else made a change between your reading and updating the data.

Grails - Saving multiple object, Rollback all object if one fails to save

I need to save multiple object at once, and rollback all if one object fails to save.
For example :
class Transaction {
Item item;
}
class Item {
date lastTransaction;
}
If I create new Transaction, I need to change lastTransaction value and save the item.
If I failed to save the item, I need to rollback the Transaction (vice versa).
Any ideas?
Yuck. Don't throw exceptions to roll back transactions. You're incurring a pretty high cost to take advantage of a side effect where the transaction manager, assuming that a runtime exception means that you're not in control, automatically rolls back the transaction for you to keep you from doing more damage. It's a bit like being lonely and hitting yourself in the head repeatedly with a hammer so some EMTs and perhaps a nurse or a doctor will spend some time with you.
It's pretty easy to roll back a transaction, but unfortunately Grails doesn't expose any of this:
import org.springframework.transaction.interceptor.TransactionAspectSupport
class FooService {
def someMethod(...) {
boolean somethingBadHappened = ...
if (somethingBadHappened) {
// roll back
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
}
// ok, proceed
...
}
}
And later you can check if the current transaction was rolled back with
TransactionAspectSupport.currentTransactionStatus().isRollbackOnly()
Note that this won't work in a controller since the transaction will have ended by that point.
Create a service method and put your persistence logic in there. When you call save, if you specify failOnError: true then if there are validation problems an exception will be thrown and your transaction will be rolled back.
def myServiceMethod(...some parameters...) {
....
Item item = new Item(lastTransaction: new Date())
item.save(failOnError: true)
Transaction transaction = new Transaction(item: item)
transaction.save(failOnError: true)
...
return transaction
}
Also, have a read through of the services section of the Grails docs.

Wrapping membership provider and dbcontext on single transaction

MVC Project using EF 5 code first and .NET 4.5.
I was looking for a way to wrap dbContext and SimpleMembershipProvider on a single transaction. I tried to use TransactionScope but since the membership provider will open another connection I get an exception (MSDTC on server 'servername' is unavailable).
So I though I could use ObjectContext.Connection.BeginTransaction instead.
The membership provider won't be part of the transaction but the idea is to have it somewhere where if it fails the transaction won't be committed.
Book bk1 = default(Book);
Book bk2 = default(Book);
object obc = (IObjectContextAdapter)dbContext;
obc.ObjectContext.Connection.Open();
using (tx == obc.ObjectContext.Connection.BeginTransaction) {
bk1 = new Book {
Name = "Book 1 Name",
Location = "USA"
};
dbContext.Books.Add(bk1);
dbContext.SaveChanges();
bk2 = new Book {
Name = "Book 2 Name. Book one Id is: " + bk1.Id,
Location = "USA"
};
dbContext.Books.Add(bk2);
dbContext.SaveChanges();
// this is not part of the transaction,
// however if it trhows an exception the transaction is aborted.
// I'm assuming that if we got here, the commit won't fail...
// But is it really true?
WebSecurity.CreateUserAndAccount("username", "123456");
tx.Commit();
}
Anyways, based on the above code:
If WebSecurity.CreateUserAndAccount fails, the whole thing fails, which is expected.
If any of the SaveChanges method fails, once again the whole thing fails because we dont get to the point where CreateUserAndAccount is executed.
This whole thing bring me to a question:
Is it safe? What I mean is:
Is there any possibility the "Commit" method will throw an exception(of fail somehow) after we successfully execute DbContext.SaveChanges ? If it happens we will endup with an orphan user because the provider is not part of the transaction.
I appreciate any comments or advice on this.
Quick note:
There is this nice article explaining why I have to cast dbContext to IObjectContextadapter instead of using its own connection property but I can't find it anymore.
Yes, Commit can certainly throw. One trivial example is if the connection drops. There are other cases, of course.
You have a few choices:
Transactions on the same DB won't escalate to distributed if the connection is shared. So you could use one connection for both EF and your WebSecurity connection.
Start the distributed transaction controller on the server and live with the escalation. Not the worst thing in the world.
Instead of using a transaction, change the order of operations such that a partially successful operation can be completed or undone later. E.g., detect and clean up "orphan" users.

Grails: how to structure transactions when I want to continue validating even after the transaction has already failed

My users are uploading a csv or xls or whatever and each line is going to be an instance of a domain object I save. If any of the lines fail I want the whole thing rolled back, but I also want to return errors for any lines that will fail later. Let's make an example:
Domain class:
MyDomainClass{
String fieldOne
BigDecimal fieldTwo
}
Input:
ThisLineWorks,4.4
ThisLineFails,BecauseOfThis
How would I also get an error, for this line as well considering the last one would have rolled back the transaction already?
Fantasy Output:
OK|ThisLineWorks,4.4
field 2 isn't a number|ThisLineFails,BecauseOfThis
field 2 isn't a number|How would I also get an error, for this line as well considering the last one would have rolled back the transaction already?
You can validate the objects without having to save them: ( http://grails.org/doc/2.0.x/guide/validation.html#validatingConstraints). So in a service you can create all of the objects, then validate all of the objects, then save all of the objects. Something similar to:
def serviceMethod(data) {
def listOfObjects = createObjectsFromData(data)
listOfObjects*.validate()
def anErrorOccurred = listOfObjects.find {it.hasErrors()} != null
if(anErrorOccurred) {
return listOfObjects
}
listOfObjects*.save(validate: false) //you could use the validate:false or leave it out. I figure since we've already validated that you could do without re-validating.
}
This way you can collect all of your errors and not have to worry about rolling back the transaction. Problem with this setup is you'll be creating N number of objects and holding onto all of them. If your file is longer than 100k rows (a slightly educated guess on where you'll start to suffer) then this might cause some performance issues. If you don't like the above method you could handle the transaction manually:
( http://grails.org/doc/2.0.x/ref/Domain%20Classes/withTransaction.html)
def serviceMethod(data) {
MyDomainClass.withTransaction { status ->
def listOfObjects = []
data.each {
def domainObject = createObjectFromData(it)
lisOfObjects << domainObject.save()
}
def anErrorOccurred = lisOfObjects.find {it.hasErrors()} != null
if(anErrorOccurred) {
status.setRollbackOnly() //will roll back all of the transactions surrounded by the .withTransaction {}
}
}
}
You're still holding onto all of the objects here (since you want to retrieve ALL errors that occur). One way I can think of to avoid holding onto all of the objects would be to create the objects one at a time and validate them one by one adding errors to a list when applicable, but then you'd have to recreate all of the objects when they all pass validation which doesn't seem very efficient either.
here is what i am thinking:
1 . Set a flag that signals ALL CLEAR and commit the transaction manually at the end if all is clear.
or
2 . Commit each line in a separate transaction capturing errors of failed lines and skipping over failures.

Resources