[Grails] Service 사용

15825 단어 Grails
참조 링크
http://desmontandojava.blogspot.de/2013/08/grails-pitfalls-dont-do-flushtrue-when.html
http://stackoverflow.com/questions/2979786/rolling-back-a-transaction-in-a-grails-service

사무로 데이터베이스를 업데이트하고 싶습니다


Grails에서 서비스라는 기구를 사용하여 간단하게 실현할 수 있다.
간단하게 말하면, 모든 이름 서비스는grails-app/services 디렉터리에 있습니다.groovy라는 서비스를 준비하고 그 방법을 기술하면 그 방법은 자동으로 Trackshonal에서 실행됩니다.
(또는Grails의create-service 명령을 이용하여 생성)
디렉터에서 서비스를 호출하려면 DI Service를 사용하십시오.
DI 하면 귀찮아진다. 단순히 서비스 이름의 시작을 소문자로 바꾸어 변수를 발표할 뿐이다.

Controller 작업 방법에서 서비스 호출


테스트 클래스


도메인 이름


실행create-domain-class BookBook.groovy
class Book{
    String title
    static constraints = {
    }
}

서비스


실행create-service TestTestService.groovy
import grails.transaction.Transactional

@Transactional
class TestService {
    def test() {
        new Book(title: "test in first").save()
        //throw new RuntimeException("omg")
    }
}

컨트롤러


TesetController.groovy
TestController {
    // 作成したサービス"TestService"をDI
    def testService
    def index(){
        try{
            // サービスのtestメソッドを実行
            testSerivce.test()
            render "OK"
        } catch (Exception e){
            render "NG"
        }
    }
}

커밋


컨트롤러의 인덱스()에 액세스할 때 TestService#test()를 실행하고 Book 인스턴스를 저장합니다.
문제가 없습니다. TestService#test()가 끝나면 자동으로 커밋되고 OK 가 표시됩니다.

되돌아오다


서비스 방법에서 RuntimeException이 발생하고 방법이 끝난 후에 자동으로 굴러가며 화면에 NG가 나타난다.
그레이스, 그루브가 자동으로 생성하는 런타임 엑셉션이 아닌 특정 조건을 충족하지 못한 채 롤백하려는 경우 등을 스스로 기술throw new RuntimeException()했다.

살짝 적어주세요.


컨트롤러의 동작 방법 내의 서비스 방법을 호출하여try-catch를 진행하더라도 보기 전에org.springframework.transaction.UnexpectedRollbackException의 예외가 발생할 수 있다.
서비스를 호출하는 컨트롤러의 동작 방법@Transactional(readOnly = true)의 상태 때문이다.
우선 컨트롤러 자체 또는 서비스를 수행하려는 컨트롤러의 동작 방법에 @Transactional 가이드를 추가한다.
Grails를 재부팅하는 것이 좋습니다(캐시도 제거하는 것이 좋습니다).
잘못된 내용은 다음과 같은 느낌이 있다

백방으로 시도하다


전제 조건


다음은 모든 디렉터가 TestService#first() 방법을 수행한다고 가정합니다.

1. 서비스 내 방법을 통해 예외를 포착하면 어떻게 되는지


저장되었습니다.
서비스 방법이 예외적으로 던져지면 굴러간다는 것이다.
TestService.groovy
def first(){
     try {
        new Book(title: "test in first").save()
        throw new RuntimeException("omg")
    } catch(RuntimeException e) {
        // メソッド内で例外をキャッチしてしまうと、ロールバックされない
        println "oh"
    }
}
따라서 아래와 같이 굴러간다.(의미 없는 코드지만 동작으로 확인)
TestService.groovy
def first(){
     try {
        new Book(title: "test in first").save()
        throw new RuntimeException("omg")
    } catch(RuntimeException e) {
        println "oh"
    } finally {
         // このメソッドが最終的に例外(RuntimeException)を投げればロールバックされる。
         throw new RuntimeException("yeah! rollback baby!")
     }
}

2. 데이터베이스에 저장된 순서


TestService.groovy
import grails.transaction.Transactional

@Transactional
class TestService {
    def first(){
        new Book(title:"first 1").save()
        this.second()
        new Book(title:"first 2").save()
    }
    def second(){
        new Book(title:"second1").save()
    }
}
이런 상황에서 마지막으로 실행된 기록은 데이터베이스에 저장된다.
따라서 책 책상 위에 연속 번호가 매겨지면
1: first 1
2: second 1
3: first 2
되다

3. 서비스 내의 방법을 다른 방법이라고 하고 예외가 발생할 경우


TestService.groovy
import grails.transaction.Transactional

@Transactional
class ServiceTestService {
    def first(){
        new Book(title:"first 1").save()
        this.second()
        new Book(title:"first 2").save()
    }
    def second(){
        new Book(title:"second1").save()
        throw new RuntimeException("omg")
    }
}
두 가지 방법으로 저장할 수 없다.롤백됩니다.
원래 Groovy식 호출 방법으로 예외를 포착하지 않고 던지면 호출자가 그 예외를 직접 던지기 때문에 이번 퍼스트도this다.second()를 부른 결과 런타임 Exception을 받아들였기 때문에 아래new Book(title:"first 2").save()는 원래 실행되지 않았다.
그리고 퍼스트는 그 예외로 끝났기 때문에 이런 절차로 굴러갔다.

4. 서비스 내의 방법을 다른 방법이라고 하고, 처음 부르는 것이 예외가 될 때


TestService.groovy
import grails.transaction.Transactional

@Transactional
class TestService {
    def first(){
        new Book(title:"first 1").save()
        this.second()
        new Book(title:"first 2").save()
        throw new RuntimeException("omg")
    }
    def second(){
        new Book(title:"second1").save()
    }
}
이번에 사용한 방법 자체가 정상적으로 끝났을 때.
둘 다 말려갔어.
이로써 최초로 호출된 서비스 내의 방법이 최종적으로 런타임 Exception이 발생하면 이 방법에서 호출된 다른 방법을 포함하여 모두 굴러간다고 할 수 있다.

5. 위 모드에서 @Transactional


TestService.groovy
import grails.transaction.Transactional

@Transactional
class ServiceTestService {
    def first(){
        new Book(title:"first 1").save()
        this.second()
        new Book(title:"first 2").save()
        //throw new RuntimeException("omg")
    }

    @Transactional(readOnly = true)
    def second(){
        new Book(title:"second1").save()
        //throw new RuntimeException("====?")
    }
}
호출된 서비스 내의 방법에readOnly가 있어도 잘 굴러간다.
이번 경우로 퍼스트()에서 런타임 Exception이 발생하든 second()에서 런타임 Exception이 발생하든 어떤 경우든 잘 굴러간다.

메모지


PostgreSQL에서 시도한 적이 없지만 적어도 PostgreSQL에서 변환기 안에서 INSERT를 진행하면 결국 거꾸로 돌려도 서열이라면 그 서열은 이빨이 벗겨진다.

주의!


도메인에서 다음과 같이 기술된 경우 발생java.lang.NullPointerException하여 DB에서 모든 데이터가 사라짐
static Person addUrlaubTo(Person person, Integer year){
    person.baseUrlaubDays.times{ person.addToUrlaube(new Urlaub(urlaubYear: year)) }
    person.save()
    new Person(username:"test1", password: "password").save()
    //throw new RuntimeException("asdf")
    person
}
개발 환경이라 무슨 일이 있었는지 모르겠다.
한 마디로 하면 여러 개의 도메인을 업데이트하는 논리라면 서비스를 성실하게 사용하는 것이 좋다.
참고로 상기 코드의 런타임 Exception을 논평하지 않으면 데이터가 사라지지 않고 단순히 이 예외throw를 끝낼 수 있다.
그래서 방법이 끝나면 무슨 일이 일어난 것 같다.
이 문제는 방치하는 것이 너무 무서워서 시간이 있을 때 따로 조사할 것이다.

총결산


1. 약간의 복잡한 처리는 모두 서비스를 사용한다.


2. Serivce 내에서 런타임 Exception을 직접 받지 않는 것이 좋다.


3. Service 내에서 롤백하려는 경우 RuntimeException 을 던집니다.


추기


[Grails] 서비스에서 SQL을 직접 실행하는 방법에서는 서비스 내에서 SQL을 직접 실행하는 방법에 대해 설명합니다.
또한 Service 내에서 SQL을 직접 실행하더라도 기사처럼 잘 굴러갈 수 있습니다.

좋은 웹페이지 즐겨찾기