4

我有一个使用 EJB 3.0 和在 JBoss 4.2.3 AS 上运行的 Hibernate 和由 EJB 控制的事务的应用程序。

我遇到的问题是 Postgres 日志中有几条关于大对象的消息,例如“错误:无效的大对象描述符:0”,有时还有“错误:大对象 488450 不存在”。结果是应用程序中的一切工作正常,但有时(并非总是)Postgres 在休眠提交后无法提交事务(在主 EJB 调用方法中的所有代码正在执行之后)。

我调查了遗留代码,发现了代表数据库中文件存储的所有实体的超类。在此类中,文件由 Blob 属性表示,并由 getBinaryStream() 方法使用。我发现奇怪的是这个类的 finalize() 方法中的内容如下:

@Lob
@Basic(fetch = FetchType.LAZY)
@Column(name = "BIN_CONTENT", nullable = true, updatable = true)
protected Blob content;

@Override
protected void finalize() throws Throwable {
    if (this.content != null) {
        try {
            IOUtils.closeQuietly(this.content.getBinaryStream());
        } catch (Exception e) {
            logger.severe("Error finalizing Blob stream");
        }
        try {
            this.content.free();
        } catch (AbstractMethodError e) {
        } catch (SQLFeatureNotSupportedException e) {
        } catch (UnsupportedOperationException e) {
        } catch (Throwable e) {
            logger.severe("Error finalizing Blob stream");
        }
        this.content = null;
    }
    super.finalize();
}

在我评论这段代码之后,一切似乎都运行良好。问题是:有必要吗?我想了解由于执行导致数据库端错误的代码而导致的内部情况。

4

1 回答 1

2

您提供的代码存在几个问题。

第一个问题是finalize()时机。

java.sql.Blob实现取决于 jdbc 驱动程序,并且通常实现类仅存储 blob 的标识符,并且在访问内容时(getBinaryStream()例如使用)执行对数据库的另一个调用。这意味着在getBinaryStream()调用用于获取 blob 的连接时仍应打开。但是 JVM 在调用 finalize 时不提供任何保证,因此在 finalize 中访问 Blob 是不正确的。

我不确定 PostgreSQL jdbc 驱动程序是否将此逻辑用于 blob,但我确定java.sql.Array实现具有此限制(即在连接关闭后您无法调用数组方法)。

第二个问题是尽管 blob 映射被定义为惰性,即使客户端没有使用它,blob 字段也将始终由finalize().

通常,客户端有责任在使用 blob 时执行清理。使用 blob 的模式是:

try {
    blob = entity.getContent();
    // ... use blob
} finally {
    // ... do blob cleanup
}
于 2013-10-27T09:31:39.647 回答