目前在我的JavaEE应用程序服务器中使用本地和远程EJB,MDB(Singleton和Stateless)我正在使用JDBC-Transactions for Hibernate Core。
管理自己所有的打开和关闭,提交休眠会话和事务都可能导致连接泄漏和未经发布的事务。
特别是在编程错误的情况下,导致自定义或未经检查的异常未被捕获并抛出到远程客户端。
最简单或最好的方法是确保关闭hibernate会话并回滚事务以防万一引发错误?
使用容器管理的事务(CMT)还是可以关闭在返回任何EJB方法时调用的拦截器中的会话?
一种简单的方法是将会话范围的用法包装在try-catch块中并捕获任何类型的Exception,但是使用较少代码的一般方法将受到青睐。
编辑:远程EJB示例
我的低级Hibernate DAO会关闭连接并在抛出异常时回滚事务。问题是DAO访问之间的业务逻辑,以防连接仍然打开。*
public void doSomething(Foo foo) throws Exception
{
// open session and transaction
Session session = DAO.openSession();
// retrieve data
Bar bar = DAO.get(session, ...)
// call other methods which throws an exception resulting in open connection
doOtherStuff(foo, bar)
DAO.save(session, foo);
// commit transaction
DAO.closeAndCommitSession(session);
}
现在我正在使用一个很大的尝试 - 终于:
public void doSomething(Foo foo) throws Exception
{
// open session and transaction
Session session = DAO.openSession();
try
{
// retrieve data
Bar bar = DAO.get(session, ...)
// call other methods which throws an exception resulting in open connection
doOtherStuff(foo, bar)
DAO.save(session, foo);
}
catch (final Exception e)
{
DAO.rollBackTransaction(session);
throw e;
}
finally
{
DAO.closeAndCommitSession(session);
}
}
答案 0 :(得分:2)
一般来说,这个问题是关于正确执行资源管理 以及简单方式。这总是需要两个要素:一个简单的API和纪律,可以在任何地方使用这个API。
可能不是使用Hibernate的用例的具体解决方案,而只是为了显示一般的想法:使用贷款模式:
public interface ConnectionRunnable {
public void run(Connection conn) throws SQLException;
}
如果你使用Groovy或Scala(带闭包),这段代码会更加优雅。在这种情况下,不需要此接口。
无论如何,在任何需要连接的地方,请使用以下内容:
public static void withConnection(final String dataSourceName,
ConnectionRunnable runnable) throws SQLException, NamingException {
final InitialContext ic = new InitialContext();
final DataSource ds = (DataSource) ic.lookup(dataSourceName);
final Connection conn = ds.getConnection();
try {
runnable.run(conn);
} finally {
conn.close();
}
}
在EJB中使用如下:
ConnectionUtils.withConnection("java:/jdbc/sandbox", new ConnectionRunnable() {
public void run(Connection conn) throws SQLException {
// Do something with the connection
}
});
SQLException
或NamingException
,您可以集中决定如何正确处理正确:使用BMT手动提交或回滚。使用setRollbackOnly
或抛出SystemException
来触发容器(使用CMT)等。如果没有特殊原因,请使用CMT。更新:使用ConnectionRunnable
界面的开销。
ConnectionRunnable
仅是“打字开销”:Groovy和Scala以相同的方式实现闭包,并且运行时开销可以忽略不计。 Java 8可能会以相同的方式实现闭包。
在这种情况下,提交或回滚数据库事务的成本无论如何都要高得多。
从Java /程序/通常的角度来看,它看起来很奇怪,并且关于异常处理的代码重用的想法也可能看起来很奇怪。
使用Scala在使用网站上看起来像这样(按字面翻译):
ConnectionUtils.withConnection("java:/jdbc/sandbox") {
conn =>
// Do something with the connection
}
但在引擎盖下它也会在JVM上使用类似匿名类的东西。