Grails - DuplicateKeyException

时间:2013-07-31 12:00:28

标签: hibernate grails transactions

我有以下代码,它将新对象添加到数据库中。首先,它从DB获取另一个对象并添加到最终对象。

我的代码几行

            ClassC c = ClassC.findByName(cName)

            ClassD d = new ClassD(
                    name: "WHATEVER",
                    classC: c
            )

            print "AAA\n"

            ClassC.withTransaction {
                c = c.merge()
                // c.save(failOnError: true, flush: true)
            }

            print "BBB\n"

            // ClassD.withTransaction {
            //     d = d.merge()
            // }
            // print "CCC\n"

            ClassD.withTransaction {
                d.save(failOnError: true, flush: true)
            }

            print "DDD\n"

我收到以下错误:

AAA
BBB

2013-07-31 13:57:14,279 ERROR JobRunShell - Job DEFAULT.1 threw an unhandled Exception: 
 org.springframework.dao.DuplicateKeyException: a different object with the same identifier value was already associated with the session: [xxx.ClassD#15]; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [xxx.ClassD#15]

你能帮帮我吗?

由于


ClassC.withTransaction {
    ClassC c = ClassC.findByName(cName)

    // find the record with name: "WHATEVER" or create a new one if there is none
    ClassD d = ClassD.findOrCreateWhere(name: "WHATEVER")

    c = c.merge()
    c.addToClassesD(d) // static hasMany = [classesD: ClassD] <-- in ClassC domain
    c.save(failOnError: true, flush: true)
}

错误来自

  

c.addToClassesD(d)

  

java.lang.IllegalStateException:找不到线程绑定请求:是   您指的是实际Web请求之外的请求属性,   或处理原始接收线程之外的请求?如果   您实际上是在Web请求中运行并仍然收到此信息   消息,你的代码可能在外面运行   DispatcherServlet / DispatcherPortlet:在这种情况下,请使用   RequestContextListener或RequestContextFilter公开当前   请求。在   org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)     在   org.springframework.web.context.request.RequestContextHolder $ currentRequestAttributes.call(未知   来源)at   xxx.AuditLogService.getCurrentUser(AuditLogService.groovy:127)at   xxx.AuditLogService $ getCurrentUser.callStatic(未知来源)at   xxx.AuditLogService $ _closure2.doCall(AuditLogService.groovy:58)at   sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)     在   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)     在java.lang.reflect.Method.invoke(Method.java:597)at   org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1243)     在   org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)   2013-08-02 09:39:11,110 ERROR ErrorLogger - Job(DEFAULT.1扔了一个   例外。 org.quartz.SchedulerException:Job扔了一个未处理的   例外。在org.quartz.core.JobRunShell.run(JobRunShell.java:224)     在   org.quartz.simpl.SimpleThreadPool $ WorkerThread.run(SimpleThreadPool.java:557)   引起:java.lang.IllegalStateException:没有线程绑定请求   发现:您是指实际的请求属性吗?   Web请求,或处理原始请求之外的请求   接收线程?如果您实际在Web请求中操作   并且仍然收到此消息,您的代码可能正在外面运行   DispatcherServlet / DispatcherPortlet:在这种情况下,请使用   RequestContextListener或RequestContextFilter公开当前   请求。在   org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)     在   org.springframework.web.context.request.RequestContextHolder $ currentRequestAttributes.call(未知   来源)at   xxx.AuditLogService.getCurrentUser(AuditLogService.groovy:127)at   xxx.AuditLogService $ getCurrentUser.callStatic(未知来源)at   xxx.AuditLogService $ _closure2.doCall(AuditLogService.groovy:58)at   sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)     在   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)     在java.lang.reflect.Method.invoke(Method.java:597)at   org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1243)     在   org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)

2 个答案:

答案 0 :(得分:2)

您可能只应在一次交易中完成所有操作。

至于你得到的错误,我假设你有一个unique设置名称 - 当已经有一个名为“WHATEVER”的记录时你会得到那个错误。

你可能想要做这样的事情:

ClassC.withTransaction {
    ClassC c = ClassC.findByName(cName)

    // find the record with name: "WHATEVER" or create a new one if there is none
    ClassD d = ClassD.findOrCreateWhere(name: "WHATEVER")

    c = c.merge()
    d.classC = c
    d.save(failOnError: true, flush: true)
}

答案 1 :(得分:0)

看看AuditLogService。您似乎正在对域类(或Hibernate)实现某种审计或安全性,这需要安全上下文,而您在一个外部调用此代码。

另外,出于好奇,为什么要在c上调用.merge()?