从无状态Bean中获取JDBC Connection对象
在无状态会话Bean中注入了EntityManager
,但我希望获得一个Connection
对象以调用DB过程。 这有什么解决方案吗?
这将是JPA提供商特定的代码。 通常,这是通过在EntityManager
类上调用unwrap()
来完成的。
如果您正在使用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();
请注意,为包含消息的PersistenceException
Hibernate 3.6.5提供的JPA 2.0解决方案将失败
Hibernate无法解开java.sql.Connection接口
使用Skaffman提供的代码使其与Hibernate一起工作(validation在3.6.5下工作,即使对于容器管理的持久性上下文也是如此)。
但是,EclipseLink wiki指出了一个有用的信息 – 如果您使用的是JTA托管数据源,则应该使用@Resource
注释注入它或使用JNDI查找检索它。 只要您需要对数据库执行事务性工作,无论您是从数据源还是从现有数据源获取新连接,都是无关紧要的; 无论如何,大多数连接池将提供与当前线程相关联的相同连接(即实体管理器已经使用的连接)。 因此,您可以避免以这种方式展开实体管理器,还可以对数据库执行事务活动; 请记住,如果执行此操作,可能无法同步持久性上下文缓存和二级缓存。
JPA API本身似乎没有提供这一点,这并不奇怪,但如果您愿意将代码耦合到特定的实现,那么您可以使用类似的东西(Hibernate):
Session hibernateSession = entityManager.unwrap(Session.class); Connection jdbcConnection = hibernateSession.connection();
请注意,在Hibernate 4中不推荐使用Session.doWork()
进行删除。请考虑使用Session.doWork()
。
在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(); } } } }); }
您必须使用entitymanager.getDelegate()
或entitymanager.unwrap
(这是更好的方法)获取底层委托,将其entitymanager.getDelegate()
转换为特定的实现(在Hibernate
中称为Session
)。 然后你可以调用connection()
方法。 请注意,这已被弃用,请改用Work
类。 在这里阅读更多。
这非常有效,如果需要,您可以在其他地方使用连接对象
SessionImpl sessionImpl = (SessionImpl) session; Connection conn = sessionImpl.connection();
其中session
是Hibernate Session对象的名称
以下是适合我的代码。 我们使用jpa 1.0,Apache openjpa实现。
import java.sql.Connection; import org.apache.openjpa.persistence.OpenJPAEntityManager; import org.apache.openjpa.persistence.OpenJPAPersistence; public final class MsSqlDaoFactory { public static final Connection getConnection(final EntityManager entityManager) { OpenJPAEntityManager openJPAEntityManager = OpenJPAPersistence.cast(entityManager); Connection connection = (Connection) openJPAEntityManager.getConnection(); return connection; } }
在JPA2.0中,如果需要JDBC则是DTO nomodel或实体查询更复杂。 有时候JPA不是全部……
我希望这能帮到您:
Statement statement = null; EntityManager em = null; em = emf.createEntityManager(); EntityTransaction et = em.getTransaction(); if(!et.isActive()) { et.begin(); } java.sql.Connection connection = em.unwrap(java.sql.Connection.class); String qquerry="SELE ... try { statement = connection.createStatement(); ResultSet rs = statement.executeQuery(qquerry); if (!rs.next()) { return null; } else{ wwwwas=rs.getString(4); } statement.close(); } catch (SQLException e) { System.out.println("\n b-03:"+e); throw new RuntimeException(e.getMessage(), e); } finally { try { // em.getTransaction().commit(); if(connection != null ) connection.close(); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } }