【问题标题】:Get hold of a JDBC Connection object from a Stateless Bean从无状态 Bean 中获取 JDBC 连接对象
【发布时间】:2011-10-06 03:11:34
【问题描述】:

在无状态会话 Bean 中注入了 EntityManager,但我想获取 Connection 对象以调用 DB 过程。 有什么解决办法吗?

【问题讨论】:

  • JPA API 不允许这样的事情,尽管 JDO API 允许。

标签: java hibernate jpa jdbc ejb


【解决方案1】:

这将是 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();

注意,为 JPA 2.0 提供的解决方案对于 Hibernate 3.6.5 将失败,PersistenceException 包含消息

Hibernate 无法解开接口 java.sql.Connection

使用 Skaffman 提供的代码使其与 Hibernate 一起工作(经过验证,即使在容器管理的持久性上下文中也可以在 3.6.5 下工作)。

然而,EclipseLink wiki 指出了一个有用的信息——如果您使用的是 JTA 托管数据源,您应该使用 @Resource 注释注入它或使用 JNDI 查找检索它。只要您需要对数据库执行事务性工作,您是从数据源获取新连接还是现有连接都无关紧要;大多数连接池无论如何都会提供与当前线程关联的相同连接(即实体管理器已经使用的连接)。因此,您将避免以这种方式打开实体管理器,并且还要对数据库执行事务活动;请记住,如果这样做,持久化上下文缓存和二级缓存可能不会同步。

【讨论】:

  • unwrap(java.sql.Connection.class) 在 OpenJPA 中也不起作用(至少 2.1.1)
  • @Pawel,好像是"fixed" in 2.2.0
  • 谢谢!但是他们还没有发布 2.2.0 :)
  • FWIW DataNucleus JPA 似乎也支持 JPA 2+ unwrap 可移植方法,所以只有 Hibernate 不支持。
  • 我确认 EclipseLink 的问题:如果在执行查询之前解开连接,则会引发异常。如果在执行查询后解包连接,则解包返回有效的 java.sql.Connection
【解决方案2】:

在 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();
                }
            }
        }

    });
}

【讨论】:

  • 你应该把它转换成“org.hibernate.Session”而不是“org.hsqldb.Session”
【解决方案3】:

JPA API 本身似乎没有提供这一点,这并不奇怪,但如果您愿意将您的代码耦合到特定的实现,那么您可以使用这样的东西(Hibernate):

Session hibernateSession = entityManager.unwrap(Session.class);
Connection jdbcConnection = hibernateSession.connection(); 

请注意,Session.connection() 在 Hibernate 4 中已不推荐删除。请考虑改用 Session.doWork()

【讨论】:

    【解决方案4】:

    您必须使用entitymanager.getDelegate()entitymanager.unwrap(这是更好的方法)获取底层委托,将其转换为具体的实现(在Hibernate 中称为Session)。然后你可以调用connection() 方法。请注意,这已被弃用,请改用 Work 类。阅读更多here

    【讨论】:

      【解决方案5】:

      在 JPA2.0 中,如果需要 JDBC 是 por DTO nomodel 或 entity 用于查询更多 复杂的。有时 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);
             }
          }
      

      【讨论】:

        【解决方案6】:

        这非常有效,如果需要,您可以在其他地方使用连接对象

        SessionImpl sessionImpl = (SessionImpl) session;
        Connection conn = sessionImpl.connection();
        

        session 是 Hibernate Session 对象的名称

        【讨论】:

          【解决方案7】:

          以下是对我有用的代码。我们使用 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;
          
              }
          
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-07
            • 2017-09-03
            • 2017-11-09
            • 2012-07-27
            • 2015-03-25
            • 1970-01-01
            相关资源
            最近更新 更多