def saveProcessDetail = {
//def employeeLoanInstance = EmployeeLoan?.findById(params?.long("id"),[lock: true])
//lock(params?.long("id"))
def employeeLoanInstance = EmployeeLoan?.get(params?.long("id"))
if(employeeLoanInstance){
def instance
if(params?.modeOfPayment){
if(params.modeOfPayment == 'DD'){
params.ddDate = params.ddDate ? DateUtility?.parseDate(params.ddDate) : params.ddDate
instance = new Dd()
}
if(params.modeOfPayment == 'Cheque'){
params.chequeDate = params.chequeDate ? DateUtility?.parseDate(params.chequeDate) : params.chequeDate
instance = new Cheque()
}
if(params.modeOfPayment == 'Cash'){
params.paidDate = params.paidDate ? DateUtility?.parseDate(params.paidDate) : params.paidDate
instance = new Cash()
}
instance?.properties = params
}
params.deductionDate = params.deductionDate ? DateUtility?.parseLoanDate(params.deductionDate) : params.deductionDate
params.sanctionedDate = params.sanctionedDate ? DateUtility?.parseDate(params.sanctionedDate) : params.sanctionedDate
//println " test : "+DateUtility.getFormattedMonthAndYear(params.deductionDate)
//println " test zx : "+DateUtility.getFormattedMonthAndYear(params.sanctionedDate)
def formattedDeductionDate = DateUtility.getFormattedMonthAndYear(params.deductionDate)
def formattedSanctionedDate = DateUtility.getFormattedMonthAndYear(params.sanctionedDate)
//println " less : "+(formattedDeductionDate < formattedSanctionedDate)
//println " = : "+(formattedDeductionDate == formattedSanctionedDate)
//println " greater : "+(formattedDeductionDate > formattedSanctionedDate)
// formattedDeductionDate.before(formattedSanctionedDate) && !(formattedDeductionDate.equals(formattedSanctionedDate))
employeeLoanInstance?.properties = params
instance?.validate()
if(params.modeOfPayment == 'Cash' && employeeLoanInstance?.sanctionedAmount && instance?.cashAmount && (instance?.cashAmount != employeeLoanInstance?.sanctionedAmount))
instance.errors.rejectValue ("cashAmount", "cash.cashAmount.invalid.message", [
message(code : 'cash.cashAmount.label', default : 'Amount')]
as Object[], message(code : 'cash.cashAmount.invalid.message'))
if(!instance?.hasErrors())
employeeLoanInstance.loanId = employeeLoanInstance.loanId ? employeeLoanInstance.loanId : loanService?.getLoanId(employeeLoanInstance?.employee,employeeLoanInstance?.createdBranch)
employeeLoanInstance?.validate()
/* Emi Amount Validation */
if(employeeLoanInstance?.noOfInstallments && employeeLoanInstance?.emiAmount && employeeLoanInstance?.sanctionedAmount){
def amt = (employeeLoanInstance?.noOfInstallments - 1) * (employeeLoanInstance?.emiAmount)
def sanctionedAmt = (employeeLoanInstance?.sanctionedAmount - amt)
if(amt > employeeLoanInstance?.sanctionedAmount)
employeeLoanInstance.errors.rejectValue ("emiAmount", "employeeLoan.emiAmount.invalid.message", [
message(code : 'employeeLoan.emiAmount.label', default : 'Emi Amount')]
as Object[], message(code : 'employeeLoan.emiAmount.invalid.message'))
if(sanctionedAmt > employeeLoanInstance?.emiAmount)
employeeLoanInstance.errors.rejectValue ("emiAmount", "employeeLoan.emiAmount.invalid.message", [
message(code : 'employeeLoan.emiAmount.label', default : 'Emi Amount')]
as Object[], message(code : 'employeeLoan.emiAmount.invalid.message'))
}
/* End */
if(!(employeeLoanInstance?.hasErrors()) && !(instance?.hasErrors())){
instance?.save(flush : true)
employeeLoanInstance.paymentId = instance?.id
employeeLoanInstance.outstandingAmount = employeeLoanInstance?.sanctionedAmount
employeeLoanInstance?.save(flush : true)
println"employeeLoanInstance?.noOfInstallments"+employeeLoanInstance?.noOfInstallments
println "-------loan instance----------->"+employeeLoanInstance?.errors
/* For saving EmiAmount Details */
def emiMonth = params.deductionDate
def amt = 0
if(employeeLoanInstance?.noOfInstallments){
for(int i = 0; i < Integer?.valueOf(employeeLoanInstance?.noOfInstallments); i++){
amt = employeeLoanInstance?.emiAmount
if(i > 0){
Calendar calendar = GregorianCalendar.getInstance()
Integer year = emiMonth?.year+1900
Integer month = (emiMonth?.month) + 1
Integer date = emiMonth.getAt(Calendar.DAY_OF_MONTH)
//calendar.set (year, month, date)
calendar.set(year, month, date, 0, 0, 0)
emiMonth = calendar?.getTime()
}
if(i == (employeeLoanInstance?.noOfInstallments - 1)){
amt = employeeLoanInstance?.sanctionedAmount - (employeeLoanInstance?.emiAmount * (employeeLoanInstance?.noOfInstallments - 1))
}
def emiAmountInstance = new EMIAmountDetails()
emiAmountInstance?.emiMonth = emiMonth
emiAmountInstance?.emiAmount = amt
emiAmountInstance?.loanId = employeeLoanInstance.loanId
auditService.beforeSave(emiAmountInstance)
emiAmountInstance?.save(flush : true)
}
}
/* End */
flash.message = "${message(code : 'loanApproval.created.message', args : [employeeLoanInstance?.loanType,loanService?.getName(employeeLoanInstance.employee.empPersonalDetails),message(code : 'employeeLoan.loanStatus.'+employeeLoanInstance?.loanStatus)])}"
redirect(action : "list")
}
else{
render(template : "processLoan", model : [screenName : params?.screenName,instance:instance,employeeLoanInstance : employeeLoanInstance, methodName : params?.methodName])
}
}
else{
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'employeeLoan.label', default: 'EmployeeLoan'), params.id])}"
redirect(action : "list")
}
}
注意:我无法通过各种场景在本地重现此问题。但是当我查看上面的生产服务器日志文件时,问题反复发生。我将其作为同步的代码块或者用于事务的服务层management.line实例?.save(flush:true)导致问题的确切...请让你的想法继续前进
答案 0 :(得分:1)
您绝对应该将数据库访问权限转移到事务性服务中。但这并不一定能阻止这个问题。此外,同步绝对不是这里的方式
这是乐观的锁定失败。 (见https://grails.github.io/grails-doc/latest/guide/GORM.html#locking)
根据您提供的信息,我无法提供明确的答案,但根据我之前看到的情况,我怀疑您有双击问题:用户之前第二次触发操作第一个动作完成。第一个操作完成并更新受影响对象的版本。当第二个操作写入数据库时,它会失败,因为对象的版本自加载对象后已更新。
为了帮助验证是否存在问题,您应该将日志记录添加到生产系统,以便您可以查看此方法何时启动以及ID是什么。如果您看到同一对象的两个(或更多)日志条目具有几乎相同的时间戳,那么这就是您的问题。
要解决此问题,请修改网页以阻止双击或修改代码以接受StaleObjectStateException。