성배에서 거래를하는 방법
-
06-07-2019 - |
문제
요약부모는 많은 자녀를 가질 수 있습니다. 부모를 추가 한 후 자식을 추가 할 때 오류가 발생하면 전체 거래가 롤백되도록 서비스를 어떻게 작성합니까? 예를 들어, 부모 P1을 추가하고, 자식 C1을 성공적으로 추가 한 다음, 자식 C2를 추가하면 오류가 발생하면 P1과 C1이 모두 롤백해야합니다.
상세한 문제
다음 코드에는 자식의 이름 속성에 고유 한 제약이 있습니다. 따라서 다른 부모와 동일한 이름을 두 번 추가하려고하면 아동 기록을 추가하지 않아야하며 부모 기록을 롤백해야합니다.
내 문제는 부모 기록이 롤백되지 않는다는 것입니다.
Grails 1.2-M2 및 Tomcat 6.018과 함께 innodb w/ innodb를 사용하고 있습니다.
데이터 소스
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
dataSource {
configClass = GrailsAnnotationConfiguration.class
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
dialect = org.hibernate.dialect.MySQLInnoDBDialect
zeroDateTimeBehavior="convertToNull" //Java can't convert ''0000-00-00 00:00:00' to TIMESTAMP
username = "root"
password = "12345"
loggingSql=false
}
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='com.opensymphony.oscache.hibernate.OSCacheProvider'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost:3306/transtest?zeroDateTimeBehavior=convertToNull"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost:3306/transtest?zeroDateTimeBehavior=convertToNull"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost:3306/transtest?zeroDateTimeBehavior=convertToNull"
}
}
}
다음과 같은 간단한 도메인 클래스가 있습니다.
부모의:
class Parent {
static hasMany = [ children : Child ]
String name
static constraints = {
name(blank:false,unique:true)
}
}
어린이
class Child {
static belongsTo = Parent
String name
Parent parent
static constraints = {
name(blank:false,unique:true)
}
}
간단한 데이터 입력 GSP
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sample title</title>
</head>
<body>
<h1>Add A Record</h1>
<g:form action="add" name="doAdd">
<table>
<tr>
<td>
Parent Name
</td>
<td>
Child Name
</td>
</tr>
<tr>
<td>
<g:textField name="parentName" />
</td>
<td>
<g:textField name="childName" />
</td>
</tr>
<tr><td><g:submitButton name="update" value="Update" /></td></tr>
</table>
</g:form>
</body>
</html>
제어 장치
class AddrecordController {
def addRecordsService
def index = {
redirect action:"show", params:params
}
def add = {
println "do add"
addRecordsService.addAll(params)
redirect action:"show", params:params
}
def show = {}
}
서비스
class AddRecordsService {
// boolean transactional = true //shouldn't this be all I need?
static transactional = true // this should work but still doesn't nor does it work if the line is left out completely
def addAll(params) {
println "add all"
println params
def Parent theParent = addParent(params.parentName)
def Child theChild = addChild(params.childName,theParent)
println theParent
println theChild
}
def addParent(pName) {
println "add parent: ${pName}"
def theParent = new Parent(name:pName)
theParent.save()
return theParent
}
def addChild(cName,Parent theParent) {
println "add child: ${cName}"
def theChild = new Child(name:cName,parent:theParent)
theChild.save()
return theChild
}
}
해결책
또한 트랜잭션이 자동으로 롤백되기 위해서는 서비스 내부에 Runtimeexception이 버려야합니다.
그래서 나는 이것을 할 것이다 :
def addParent(pName) {
println "add parent: ${pName}"
def theParent = new Parent(name:pName)
if(!theParent.save()){
throw new RuntimeException('unable to save parent')
}
return theParent
}
def addChild(cName,Parent theParent) {
println "add child: ${cName}"
def theChild = new Child(name:cName,parent:theParent)
theChild.save()
if(!child.save()){
throw new RuntimeException('unable to save child')
}
return theChild
}
그런 다음 컨트롤러에서 예외를 포착하고 오류를 렌더링하십시오.
다른 방법은 자동 트랜잭션을 바꾸고 상위를 사용하는 것입니다.
다른 팁
나는 그것이되어야한다고 믿는다 :
class AddRecordsService {
static transactional = true;// note *static* not boolean
}
또는 도메인 개체를 저장할 때 FailOrror 속성을 사용할 수 있습니다. 저장이 유효성 검사 오류에 대해 저장이 실패하면 예외가 발생합니다.
def addChild(cName,Parent theParent) {
println "add child: ${cName}"
def theChild = new Child(name:cName,parent:theParent)
theChild.save(failOnError:true)
return theChild
}
이 동작은 Grails-App/conf/config.groovy에 성적으로 Grails.gorm.FailOnerror 속성을 설정하여 전 세계적으로 활성화 할 수 있습니다.
자세한 내용은 '저장'사용자 가이드 문서를 참조하십시오. http://grails.org/doc/latest/ref/domain%20classes/save.html