Search code examples
javaspringgrailsflush

My grails project facing error"TransactionRequiredException:no transaction" using domain.save(flush:true).save() it can is saving but updating


package com.fhjony.ocbt


import grails.web.servlet.mvc.GrailsParameterMap


class MemberService {

def save(GrailsParameterMap params) {
    Member member = new Member(params)
    def response = AppUtil.saveResponse(false, member)
    if (member.validate()) {
        member.save(true)
        if (!member.hasErrors()){
            response.isSuccess = true
        }
    }
    return response
}


def update(Member member, GrailsParameterMap params) {

    member.properties = params
    def response = AppUtil.saveResponse(false, member)
    if (member.validate()) {
        member.save(flush: true)
        if (!member.hasErrors()){
            response.isSuccess = true
        }
    }
    return response
}


def getById(Serializable id) {
    return Member.get(id)
}


def list(GrailsParameterMap params) {
    params.max = params.max ?: GlobalConfig.itemPerPage()
    List<Member> memberList = Member.createCriteria().list(params) {
        if (params?.colName && params?.colValue) {
            like(params.colName, "%" + params.colValue + "%")
        }
        if (!params.sort) {
            order("id", "desc")
        }
    }
    return [list: memberList, count: memberList.totalCount]
}


def delete(Member member) {
    try {

        member.delete(flush: true,failOnError:true)
    } catch (Exception e) {
        println(e.getMessage())
        return false
    }
    return true
}
}

Error message:

URI /member/update Class
javax.persistence.TransactionRequiredException Message null Caused by
no transaction is in progress
     Line | Method
 ->>  211 | invoke           in org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  |    188 | invoke           in org.grails.core.DefaultGrailsControllerClass |     90 | handle . . . .
 . in org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter |   1039
 | doDispatch       in
 org.springframework.web.servlet.DispatcherServlet |    942 | doService
 . . .  in     '' |   1005 | processRequest   in
 org.springframework.web.servlet.FrameworkServlet |    908 | doPost . .
 . . . in     '' |    882 | service          in     '' |     77 |
 doFilterInternal in

Solution

  • You want your database interactions to be happening in a transactional context. One simple piece of that is you can mark your service class with @grails.gorm.transactions.Transactional.

    Separate from that, and this isn't really related to your question, but passing GrailsParameterMap map around as a method argument is an unusual thing to do. What the right thing to do is depends on some factors in your app and you may want to pass values into your service rather than the whole map but if you really want the whole map in the service, one way to get there is by way of WebAttributes.

    import grails.gorm.transactions.Transactional
    import grails.web.api.WebAttributes
    
    @Transactional
    class MemberService implements WebAttributes {
    
        def serviceMethod() {
            // you can access params here because 
            // WebAttributes provides access to it
            Member member = new Member(params)
    
            // ...
        }
    }