Grails程序化事务处理

时间:2014-02-07 22:10:09

标签: hibernate grails transactions gorm

我的Grails应用程序有一个服务方法,可以从last.fm的Web服务更新艺术家列表。

@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()
            }
        }
    }
}

每个艺术家都在自己的交易中更新,如果抛出IOException,应该回滚。但是,我注意到以下行为:

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

  

org.hibernate.LazyInitializationException:懒得初始化   角色集合:org.example.Artist.topTracks,没有会话或   会议已经结束

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

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

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

但我不明白为什么我需要这样做,即为什么回滚交易似乎会关闭会议?

1 个答案:

答案 0 :(得分:4)

回滚使会话无法使用是正常的,因为它是一个不可恢复的错误,就像所有Hibernate异常一样。例如,参见类ObjectNotFoundException的javadoc:

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

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

由于此功能难以实施且使用有限,因此决定使这些类型的异常无法恢复。

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

修改

以下是documentation中的Javadoc以外的其他参考资料:

  

Hibernate引发的异常意味着你必须回滚你的   数据库事务并立即关闭Session(这是   本章稍后将详细讨论。如果您的会话是   绑定到应用程序,您必须停止应用程序。滚动   返回数据库事务不会使您的业务对象返回   进入交易开始时的状态。这意味着   数据库状态和业务对象将不同步。   通常这不是问题,因为异常是不可恢复的   无论如何你必须在回滚后重新开始。

还有:

  

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