Grails编程事务处理 [英] Grails programmatic transaction handling

查看:141
本文介绍了Grails编程事务处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  @Transactional(

propagations = Propagation.NOT_SUPPORTED)
void updateLastFmArtists(Range idRange = null){

Artist.list()。each {Artist artist - >

//我们可以在这里更新很多艺术家,这个过程可能会占用
//一小时,而我们不想将所有这些都包含在单个事务中
Artist.withTransaction {status - >
try {
updateArtistInfo(artist)

} catch(IOException ex){
status.setRollbackOnly()
}
}






$ b每个单独的艺术家都会在它自己的交易中更新,如果抛出 IOException ,则回滚。但是,我注意到以下行为:

如果尝试更新艺术家会抛出 IOException - 导致事务被回滚 - 然后下一个艺术家的更新总是失败,由于以下错误


org.hibernate.LazyInitializationException:未能延迟初始化
a角色的集合:org.example.Artist.topTracks,无会话或
会话已关闭


如果我更改上面的代码,以便每个艺术家在其自己的会话中更新,这似乎解决了问题,

 艺术家。 withNewSession {session  - > 
Artist.withTransaction {status - >
try {
updateArtistInfo(artist)

} catch(IOException ex){
status.setRollbackOnly()
}
}

$ / code>

但我不明白为什么我需要这样做,也就是说为什么要滚动返回一个事务似乎关闭了会话?

解决方案

回滚会导致会话不可用,因为这是一个不可恢复的错误,像所有休眠异常。请参阅例如class ObjectNotFoundException 的javadoc:

  / * 
* ...
*
*和所有的Hibernate异常一样,这个异常被认为是
*不可恢复的。
*
* /

原因是会话是一个状态同步器数据库与内存中的对象之间的组件。处理数据库中的回滚的方法是回滚内存中对象的更改。



因为这个功能很难实现并且功能有限,我们决定让这些类型的异常无法恢复。

您可以尝试捕获并继续使用会话,但不能保证会话将处于一致的状态。

编辑:



以下是Javadoc以外的其他参考资料, 文档


Hibernate引发的异常意味着您必须回滚您的
数据库事务并立即关闭会话(这是
在更多讨论中本章后面的细节)。如果您的Session是绑定到应用程序的
,则必须停止应用程序。将
滚动回数据库事务不会将您的业务对象返回
到它们在事务开始时的状态。这意味着
数据库状态和业务对象将不同步。
通常这不是问题,因为异常不可恢复
,您必须在回滚后重新开始。

还有:

lockquote

如果Session引发一个异常,包括任何SQLException,
立即回滚数据库事务,调用Session.close()
并放弃Session实例。 Session的某些方法不会
使会话处于一致状态。没有
引发的异常Hibernate可以被视为可恢复。通过在finally块中调用close()来确保会话
被关闭。



My Grails app has a a service method that updates a list of artists from last.fm's web service.

@Transactional(propagation = Propagation.NOT_SUPPORTED)
void updateLastFmArtists(Range idRange = null) {

    Artist.list().each { Artist artist ->

        // We could be updating a lot of artists here, the process could take up 
        // to an hour and we don't want to wrap all that in a single transaction
        Artist.withTransaction { status ->
            try {
                updateArtistInfo(artist)

            } catch (IOException ex) {
                status.setRollbackOnly()
            }
        }
    }
}

Each individual artist is updated within it's own transaction, which should be rolled back if an IOException is thrown. However, I noticed the following behaviour:

If an attempt to update an artist throws an IOException - causing the transaction to be rolled back - then the update of the next artist always fails due to the following error

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.example.Artist.topTracks, no session or session was closed

If I change the code above so that each artist is updated within it's own session, this seems to fix the problem,

   Artist.withNewSession { session ->
       Artist.withTransaction { status ->
            try {
                updateArtistInfo(artist)

            } catch (IOException ex) {
                status.setRollbackOnly()
            }
        }
   }

But I don't understand why I need to do this, i.e. why is that rolling back a transaction seems to close the session?

解决方案

It's normal that rollback makes the session unusable, as it's an unrecoverable error like all Hibernate exceptions. See for example the javadoc of class ObjectNotFoundException:

/*
 * ...
 *
 * Like all Hibernate exceptions, this exception is considered 
 * unrecoverable.
 *
 */

The reason is that the session is a state synchronizer component between the database and objects in memory. The way to treat a rollback in the database would be to rolllback the changes in the objects in memory.

Because this functionality would be hard to implement and of limited use, the decision was taken to make these type of exceptions unrecoverable.

You can try to catch it and continue to use the session but there is no guarantee that the session will be in a consistent state.

EDIT:

Here is further references other than the Javadoc, found in the documentation:

An exception thrown by Hibernate means you have to rollback your database transaction and close the Session immediately (this is discussed in more detail later in the chapter). If your Session is bound to the application, you have to stop the application. Rolling back the database transaction does not put your business objects back into the state they were at the start of the transaction. This means that the database state and the business objects will be out of sync. Usually this is not a problem, because exceptions are not recoverable and you will have to start over after rollback anyway.

and also:

If the Session throws an exception, including any SQLException, immediately rollback the database transaction, call Session.close() and discard the Session instance. Certain methods of Session will not leave the session in a consistent state. No exception thrown by Hibernate can be treated as recoverable. Ensure that the Session will be closed by calling close() in a finally block.

这篇关于Grails编程事务处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆