4

我有一个事务性 grails 服务正在执行一些(长时间运行)处理。在处理时,我想更新一个“percentComplete”值(最终将用于在前端显示进度条)。这显然必须立即写入(即不作为当前事务的一部分),否则它没有任何价值。

因此,我使用Grails 事务处理插件,特别是“withNewTransaction”方法来启动一个新事务,其中更新了 percentComplete 属性。

我的问题是,第二次进入“updatePercentComplete()”方法时,应用程序在尝试退出“withNewTransaction”方法时挂起(大概是在尝试提交事务时)。

笔记:

  • 如果我在主服务方法中注释掉会话刷新,则没有问题(顺便说一句,在我的实际应用程序中出于性能原因需要此刷新以及清除)
  • 使用 hsql 数据库,没有问题(参见 DataSources.groovy)。
  • 也使用 grails 执行器插件,但我认为这本身不会导致任何问题(请参阅 LibraryServiceTests,它也挂起并绕过插件)。

我应该去哪里调试这个问题?也许我可以在 grails/hibernate 中设置一些日志级别以查明发生了什么?

执行这项工作的线程似乎在尝试从套接字读取时卡住了,请参阅下面的堆栈跟踪。JVM 本身似乎没有任何实际的死锁。

这是我的服务类,下面是完整项目的链接:

package withtransactiontest

class LibraryService {

    static transactional = true

    def sessionFactory

    def loadBooks(library) {

        int repeat = 5
        repeat.times {
            updatePercentComplete(library, it * (100 / repeat))

            // Simulate some long running process in order to be able to see percentComplete getting written to DB.
            Thread.sleep(2000)

            // Update some property (within the default transaction)
            library.name += "x"
            library.save()

            // Comment out the following, and the current method will complete successfully.
            def session = sessionFactory?.currentSession
            session?.flush()
        }

        library.percentComplete = 100
        library.save()
    }

    void updatePercentComplete(library, val) {

        println "before new transaction"
        Library.withNewTransaction {

            println "Percent complete: " + val
            library.refresh()
            library.percentComplete = val
            library.save()

            println "after save"

            // Hang here, second time around.
        }

        println "Percent complete transaction committed"
        library.refresh()
    }
}

链接到带有重新创建问题的集成测试用例的 grails 项目

“worker”线程的堆栈跟踪:

线程 [pool-1-thread-1] (Suspended)
SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) 行:不可用 [native method]
SocketInputStream.read(byte[], int, int) 行: 129
ReadAheadInputStream.fill(int) line: 114
ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(byte[], int, int) line: 161
ReadAheadInputStream.read(byte[], int, int) line: 189
MysqlIO.readFully(InputStream, byte[] , int, int) line: 2499 MysqlIO.reuseAndReadPacket(Buffer, int) line: 2952
MysqlIO.reuseAndReadPacket(Buffer) line: 2941
MysqlIO.checkErrorPacket(int) line: 3489
MysqlIO.sendCommand(int, String, Buffer, boolean, String , int) 行:1959
MysqlIO.sqlQueryDirect(StatementImpl, String, String, Buffer, int, int, int, boolean, String, Field[]) line: 2113
JDBC4Connection(ConnectionImpl).execSQL(StatementImpl, String, int, Buffer, int, int, boolean, String, Field[], boolean) line: 2568 JDBC4PreparedStatement(PreparedStatement).executeInternal(int, Buffer, boolean, boolean, Field[], boolean) line: 2113
JDBC4PreparedStatement(PreparedStatement).executeUpdate(byte[][], InputStream[ ], boolean[], int[], boolean[], boolean) line: 2409
JDBC4PreparedStatement(PreparedStatement).executeUpdate(boolean, boolean) line: 2327
JDBC4PreparedStatement(PreparedStatement).executeUpdate() line: 2312
DelegatingPreparedStatement.executeUpdate() line : 105
DelegatingPreparedStatement.executeUpdate() line: 105
GroovyAwareSingleTableEntityPersister(AbstractEntityPersister).update(Serializable, Object[], Object[], Object, boolean[], int, Object, Object, String, SessionImplementor) line: 2435
GroovyAwareSingleTableEntityPersister(AbstractEntityPersister).updateOrInsert (Serializable, Object[], Object[], Object, boolean[], int, Object, Object, String, SessionImplementor) line: 2335
GroovyAwareSingleTableEntityPersister(AbstractEntityPersister).update(Serializable, Object[], int[], boolean, Object [],对象,对象,对象,SessionImplementor) 行:2635
EntityUpdateAction.execute() 行:115
ActionQueue.execute(Executable) 行:279
ActionQueue.executeActions(List) 行:263
ActionQueue.executeActions() 行:168
PatchedDefaultFlushEventListener.performExecutions(EventSource) 行:46
PatchedDefaultFlushEventListener(DefaultFlushEventListener).onFlush(FlushEvent) 行:50
SessionImpl.flush() 行:1027
SessionImpl.managedFlush() 行:365
JDBCTransaction.commit()行:137
GrailsHibernateTransactionManager(HibernateTransactionManager).doCommit(DefaultTransactionStatus) 行:656 GrailsHibernateTransactionManager(AbstractPlatformTransactionManager).processCommit(DefaultTransactionStatus) 行:754 GrailsHibernateTransactionManager(AbstractPlatformTransactionManager).commit(TransactionStatus) 行:723
TransactionTemplate.execute(TransactionCallback)行:
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(对象,对象...) 行:597
PojoMetaMethodSite$PojoCachedMethodSite.invoke(Object, Object[]) 行:188
PojoMetaMethodSite$PojoCachedMethodSite(PojoMetaMethodSite).call(Object, Object[]) 行:52 PojoMetaMethodSite$PojoCachedMethodSite(AbstractCallSite)。 call(Object, Object) line: 124
GroovyDynamicMethods$_doWith_closure1.doCall(Map, Map, Closure) line: 55
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(Object, Object[ ]) 行:266
PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce(PogoMetaMethodSite).callCurrent(GroovyObject, Object[]) 行:51
PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce(AbstractCallSite).callCurrent(GroovyObject, Object, Object, Object) 行:157
GroovyDynamicMethods$_doWith_closure1.call(Map , Map, Closure) line: 不可用
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: 不可用 [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(Object, Object[ ]) 行:266
PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce(PogoMetaMethodSite).call(Object, Object[]) 行:63 PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce(AbstractCallSite).call(Object, Object, Object, Object) 行:132
GroovyDynamicMethods$_doWith_closure3.doCall(Map , Closure) line: 65 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
PogoMetaMethodSite$PogoCachedMethodSite.invoke(Object, Object[]) line: 225
PogoMetaMethodSite$PogoCachedMethodSite(PogoMetaMethodSite).callCurrent (GroovyObject, Object[]) line: 51
PogoMetaMethodSite$PogoCachedMethodSite(AbstractCallSite).callCurrent(GroovyObject, Object, Object) line: 153
GroovyDynamicMethods$_doWith_closure3.doCall(Closure) line: 不可用
NativeMethodAccessorImpl.invoke0(Method, Object, Object[ ]) 行:不可用 [本机方法]
NativeMethodAccessorImpl.invoke(Object, Object[]) 行:39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) 行:25
Method.invoke(Object, Object...) line: 597
CachedMethod.invoke(Object, Object[]) line: 90
CachedMethod(MetaMethod).doMethodInvoke(Object, Object[]) line: 233 ExpandoMetaClass(MetaClassImpl).invokeMethod( Class, Object, String, Object[], boolean, boolean) line: 1058
ExpandoMetaClass.invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 1070 ExpandoMetaClass(MetaClassImpl).invokeMethod(Object, String, Object []) 行:886
GroovyDynamicMethods$_doWith_closure3(Closure).call(Object[]) 行:282 ClosureStaticMetaMethod.invoke(Object, Object[]) 行:59
StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce.invoke(Object, Object[]) 行:148
StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce(StaticMetaMethodSite).call(Object, Object[]) 行:88 StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce(AbstractCallSite).call(Object, Object) 行:124
LibraryService.updatePercentComplete(Object, Object) 行:34
NativeMethodAccessorImpl.invoke0(Method , Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object.. .) 行:597
CachedMethod.invoke(Object, Object[]) 行:90
CachedMethod(MetaMethod).doMethodInvoke(Object, Object[]) line: 233 ExpandoMetaClass(MetaClassImpl).invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 1058
ExpandoMetaClass.invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 1070 ExpandoMetaClass(MetaClassImpl).invokeMethod(Object, String, Object[]) line: 886
ExpandoMetaClass(MetaClassImpl).invokeMethod(Class, Object, String, Object[], boolean, boolean)行:1003
ExpandoMetaClass.invokeMethod(Class, Object, String, Object[], boolean, boolean) 行:1070 ExpandoMetaClass(MetaClassImpl).invokeMethod(Object, String, Object[]) 行:886
PogoMetaClassSite.callCurrent(GroovyObject, Object[ ]) 行:66
PogoMetaClassSite(AbstractCallSite).callCurrent(GroovyObject, Object, Object) line: 153 LibraryService$_loadBooks_closure1.doCall(Object) line: 13
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke (Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
CachedMethod.invoke(Object, Object[]) line: 90
CachedMethod(MetaMethod).doMethodInvoke(Object, Object[]) line: 233 ExpandoMetaClass(MetaClassImpl).invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 1058
ExpandoMetaClass.invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 1070 ExpandoMetaClass(MetaClassImpl).invokeMethod(Object, String, Object[]) line: 886
LibraryService$_loadBooks_closure1(Closure).call(Object[ ]) 行:282
LibraryService$_loadBooks_closure1(Closure).call(Object) 行:295
DefaultGroovyMethods.times(Number, Closure) 行:9487
dgm$630.invoke(Object, Object[]) 行:不可用
PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke (Object, Object[]) 行:270
PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce(PojoMetaMethodSite).call(Object, Object[]) 行:52
PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce(AbstractCallSite).call(Object, Object) 行:124
LibraryService.loadBooks(Object) 行:12
LibraryService$$FastClassByCGLIB$$f97d911e.invoke(int, Object, Object[]) 行:不可用
MethodProxy.invoke(Object, Object[]) 行:149
Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint( ) 行:688
Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() 行:150
TransactionInterceptor.invoke(MethodInvocation) 行:110
Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() 行:172
Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) 行:621 LibraryService$$EnhancerByCGLIB$$c098c6ba.loadBooks(Object) 行:不可用 LibraryService$loadBooks.call(Object, Object) 行:不可用
LibraryController $_closure4_closure9.doCall(Object) line: 30
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object []) 行:25
Method.invoke(Object, Object...) 行:597
PogoMetaMethodSite$PogoCachedMethodSite.invoke(Object, Object[]) 行:225
PogoMetaMethodSite$PogoCachedMethodSite(PogoMetaMethodSite).callCurrent(GroovyObject, Object[]) 行:51
PogoMetaMethodSite$PogoCachedMethodSite(AbstractCallSite).callCurrent(GroovyObject, Object) 行:149
LibraryController$_closure4_closure9.doCall() 行:不可用
NativeMethodAccessorImpl.invoke0(Method , Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object.. .) 行:597
CachedMethod.invoke(Object, Object[]) 行:90
CachedMethod(MetaMethod).doMethodInvoke(Object, Object[]) line: 233 ExpandoMetaClass(MetaClassImpl).invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 1058
ExpandoMetaClass.invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 1070 ExpandoMetaClass(MetaClassImpl).invokeMethod(Object, String, Object[]) line: 886
LibraryController$_closure4_closure9(Closure).call(Object[]) line: 282
ConvertedClosure.invokeCustom(Object , Method, Object[]) line: 51
ConvertedClosure(ConversionHandler).invoke(Object, Method, Object[]) line: 82
$Proxy6.call() line: 不可用
java_util_concurrent_Callable$call.call(Object) 行:不可用 PersistenceContextCallableWrapper$_call_closure1.doCall(Object) 行:36
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) 行:不可用 [本机方法]
NativeMethodAccessorImpl.invoke(Object, Object []) 行:39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) 行:25
Method.invoke(Object, Object...) 行:597
PogoMetaMethodSite$PogoCachedMethodSite.invoke(Object, Object[]) 行:225
PogoMetaMethodSite$ PogoCachedMethodSite(PogoMetaMethodSite).callCurrent(GroovyObject, Object[]) 行:51
PogoMetaMethodSite$PogoCachedMethodSite(AbstractCallSite).callCurrent(GroovyObject, Object) 行:149
PersistenceContextCallableWrapper$_call_closure1.doCall() line: 不可用
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: 不可用 [native Method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) 行:25
Method.invoke(Object, Object...) 行:597
CachedMethod.invoke(Object, Object[]) 行:90
CachedMethod(MetaMethod).doMethodInvoke(Object, Object[]) 行:233 ExpandoMetaClass(MetaClassImpl).invokeMethod(Class, Object, String, Object[], boolean, boolean) 行:1058
ExpandoMetaClass.invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 1070 ExpandoMetaClass(MetaClassImpl).invokeMethod(Object, String, Object[]) line: 886
PersistenceContextCallableWrapper$_call_closure1(Closure).call(Object[ ]) 行:282
PersistenceContextCallableWrapper$_call_closure1(Closure).call() 行:277
Closure$call.call(Object) 行:不可用
PersistenceContextCallableWrapper(PersistenceContextWrapper).wrap(Closure) 行:35
NativeMethodAccessorImpl.invoke0(方法,对象, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) 行:597
PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(Object, Object[]) 行:266
PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce(PogoMetaMethodSite).callCurrent(GroovyObject, Object[]) 行:51
PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce (AbstractCallSite).callCurrent(GroovyObject, Object) 行:149
PersistenceContextCallableWrapper.call() 行:36
FutureTask$Sync.innerRun() 行:303
FutureTask.run() 行:138
ThreadPoolExecutor$Worker.runTask(Runnable) 行:886
ThreadPoolExecutor$Worker.run() 行:908
Thread.run() 行:680

4

1 回答 1

0

解决方法是引入一个新的域类Progress,它具有属性percentCompletebelongsTo库。这是在新的(嵌套的)事务中更新的,而不是在Library实例本身中更新。

于 2012-07-09T06:08:32.307 回答