문제

요약부모는 많은 자녀를 가질 수 있습니다. 부모를 추가 한 후 자식을 추가 할 때 오류가 발생하면 전체 거래가 롤백되도록 서비스를 어떻게 작성합니까? 예를 들어, 부모 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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top