Search code examples
javamongodbgrailsgrails-orm

How do I perform a mongodb two phase commit in grails?


I'm working on a system that used mongodb. For a specific case, I'm required to be able to rollback saves. How do I go on doing using GORM?


Solution

  • I just followed the instructions at http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits. My code looks like:

    FinancialTransaction financialTransaction = createFinancialTransaction(transactionType, amount, from, to,
                 process)
    
            financialTransaction = financialTransaction.save(flush: true, failOnError: true)
    
            financialTransaction.transactionStatus = FinancialTransactionStatusEnum.PENDING
            financialTransaction = financialTransaction.save(flush: true, failOnError: true)
    
    
            def transactionLineNumber = 1
            financialTransaction.addToTransactionItems( new FinancialTransactionItem(financialAccount: from.financialAccount, 
                transactionLineNumber: transactionLineNumber++, debitAmount: amount, creditAmount: 0,
                description: "Money debited from Unions account for loan." ))
            financialTransaction.addToTransactionItems( new FinancialTransactionItem(financialAccount: to.financialAccount,
                transactionLineNumber: transactionLineNumber++, creditAmount: amount, debitAmount: 0, 
                description: "Money credited to Coops account from a loan received from a Union." ))
    
            financialTransaction.save( flush: true, failOnError: true)
    
            financialTransaction.transactionItems.each()  { transactionItem -> 
                        financialAccount = transactionItem.financialAccount
    
    
                    if( financialAccount.pendingTransactions.contains(financialTransaction.id )) //transaction has been committed to this account(used during recovery)
                        return
    
                    delta = (transactionItem.debitAmount == 0) ? transactionItem.creditAmount : transactionItem.debitAmount
                    sign = (transactionItem.debitAmount == 0) ? 1.0 : -1.0
                    newBalance = financialAccount.totalBalance + delta * sign
    
                    financialAccount.totalBalance = newBalance
                    financialAccount.pendingTransactions << financialTransaction.id
    
                    financialAccount.save(flush: true, failOnError: true)
    
                    if(log.isDebugEnabled())
                            log.debug("Saved Financial Account Id: ${transactionItem.financialAccount.id} Balance: ${newBalance}")
    
                    new FinancialAccountChange(financialAccount: financialAccount, updatedBalance: newBalance,
                        delta: delta * sign, financialTransactionItem: transactionItem).save(flush: true, failOnError: true)
    
            }
    
            financialTransaction.transactionStatus = FinancialTransactionStatusEnum.COMMITTED
            financialTransaction = financialTransaction.save(flush: true, failOnError: true)
    
            financialTransaction.transactionItems*.financialAccount.each { fA ->
                fA.pendingTransactions - financialTransaction.id
                fA.save( flush: true, failOnError: true )           
            }
    
            financialTransaction.transactionStatus = FinancialTransactionStatusEnum.DONE
            financialTransaction = financialTransaction.save(flush: true, failOnError: true)