从无状态 Bean 获取 JDBC 连接对象
在无状态会话中,注入了一个Bean,但我想获得一个对象以调用数据库过程。有什么解决方案吗?EntityManager
Connection
在无状态会话中,注入了一个Bean,但我想获得一个对象以调用数据库过程。有什么解决方案吗?EntityManager
Connection
这将是 JPA 提供程序特定的代码。通常,这是通过在类上调用 unwrap()
来完成的。EntityManager
如果您使用的是 EclipseLink,以下代码(来自 EclipseLink wiki)将非常有用(如果您使用的是应用程序管理的 EntityManager):
JPA 2.0
entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class); // unwraps the Connection class.
...
entityManager.getTransaction().commit();
JPA 1.0
entityManager.getTransaction().begin();
UnitOfWork unitOfWork = (UnitOfWork)((JpaEntityManager)entityManager.getDelegate()).getActiveSession();
unitOfWork.beginEarlyTransaction();
Accessor accessor = unitOfWork.getAccessor();
accessor.incrementCallCount(unitOfWork.getParent());
accessor.decrementCallCount();
java.sql.Connection connection = accessor.getConnection();
...
entityManager.getTransaction().commit();
请注意,为 JPA 2.0 提供的解决方案对于 Hibernate 3.6.5 将失败,并且包含消息PersistenceException
休眠无法解开java.sql接口的包装。连接
使用 Skaffman 提供的代码使其适用于 Hibernate(经验证,即使在容器管理的持久性上下文中,也可以在 3.6.5 下工作)。
但是,EclipseLink wiki 指出了一个有用的信息 - 如果您使用的是 JTA 托管数据源,则应使用注释注入它或使用 JNDI 查找来检索它。只要您需要对数据库执行事务性工作,那么从数据源获取新连接还是从现有数据源获取新连接并不重要。无论如何,大多数连接池将提供与当前线程关联的相同连接(即实体管理器已使用的连接)。因此,您将避免以这种方式解包实体管理器,并对数据库执行事务活动;请记住,如果这样做,持久性上下文缓存和二级缓存可能不会同步。@Resource
在Hibernate中,skaffman发布的解决方案导致以下错误消息:
Hibernate 无法解开类 org.hsqldb.Session 的包装
我确实让它使用SessionImpl而不是Session工作:
Connection connection = entityManager().unwrap(SessionImpl.class).connection();
使用 Session.doWork() 解决问题的示例如下:
private void executeNative(final String query) {
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
Statement s = null;
try {
s = connection.createStatement();
s.executeUpdate(query);
}
finally {
if (s != null) {
s.close();
}
}
}
});
}