【问题标题】:Hibernate: c3p0 throws NullPointerException at NewProxyConnection.commit()休眠:c3p0 在 NewProxyConnection.commit() 处抛出 NullPointerException
【发布时间】:2014-02-19 15:17:07
【问题描述】:

我在 4.3.1.Final 版本中同时使用 Hibernate 和 C3P0。 MySQL 5.6.14(所有表的 InnoDB)。

hibernate.cfg.xml 中的 C3P0 设置为:

<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.preferredTestQuery">SELECT 1</property>
<property name="hibernate.c3p0.minPoolSize">3</property>
<property name="hibernate.c3p0.maxPoolSize">100</property>

例如,当我提交事务时:

public void editCategory(int id, String title) {
    Transaction tx = getTransaction();
    Query q = session.createQuery("FROM Category WHERE id = :id");
    q.setInteger("id", id);
    Category cat = (Category) q.uniqueResult();
    cat.setTitle(title);
    tx.commit();
}
private Transaction getTransaction() {
    Transaction tx = session.getTransaction();
    if (!tx.isActive()) {
        tx.begin();
    }
    return tx;
}

在 5 次尝试中大约有 3 次提交失败,原因是:

SEVERE: Servlet.service() for servlet [appserver.services.ApplicationConfig] in context with path [/AppServer] threw exception [org.hibernate.TransactionException: commit failed] with root cause
java.lang.NullPointerException
    at com.mchange.v2.c3p0.impl.NewProxyConnection.commit(NewProxyConnection.java:1284)
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:112)
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:180)
    at appserver.dao.CategoryDao.createCategory(CategoryDao.java:60)
    at appserver.services.CategoryResource.createCategory(CategoryResource.java:41)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:195)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:402)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:349)
    ... stacktrace continues

我缺少 C3P0 设置吗?感谢帮助!

【问题讨论】:

    标签: java mysql hibernate innodb c3p0


    【解决方案1】:

    您的应用服务器正在报告根本原因的根本原因,即它正在跳过一个异常,该异常会报告更多信息性消息“您无法在已关闭的连接上进行操作!!!”

    您的应用程序中有竞争条件。您摘录的方法中引用的对象“会话”很可能有时在查询和提交之间关闭()。 (休眠会话包装了 JDBC 连接。)

    您需要了解会话的生命周期,并确保这种情况永远不会发生。最简单的是,您可能完全避免缓存会话。您可以在需要时获取它们,并在使用后立即关闭它们,即在您提交()事务之后(可靠地,通过 finally 块或 try-with-resources 构造)。

    【讨论】:

    • 史蒂夫,谢谢你的回答。我有静态会话工厂,然后在 DAO 对象的构造函数中初始化字段会话,如下所示: this.session = HibernateUtil.getSessionFactory().getCurrentSession();
    • 我将会话上下文类属性设置为:线程
    • 那么,关于当前会话,在您的配置下与线程相关联:谁打开它,谁关闭它?也就是说,据我了解(而且我不是 Hibernate 专家!),SessionFactory.getCurrentSession() 是一种方便,它将获取您已经打开的会话 [使用 SessionFactory.openSession()],它已绑定到一个上下文[在你的情况下是一个线程],所以你不必显式地将它作为方法参数传递。但是你仍然需要 openSession()s,了解它们的生命周期,从 c3p0 的角度来看,非常重要的是,close() 它们。
    • 小心不要以您不希望的方式共享会话。也就是说,如果您打开一个 Session 并将其绑定到一个 Thread 作为其默认上下文,则它仍应仅在一个逻辑请求或工作单元(可能涉及一系列数据库事务)过程中使用,然后关闭.应该允许会话将自己附加到您的应用服务器正在使用的任何线程上,然后在它们碰巧正在处理请求时从这些线程中重新获取。
    • 我也明白当前会话应该与打开它的线程相关联。由于 Session 不是 AutoCloseable,因此无法使用 try-with-resources,但似乎在每个事务后打开和关闭 Session 有效: Session session = HibernateUtil.getSessionFactory().openSession();尝试 { 交易 tx = session.beginTransaction(); // 做查询 tx.commit(); } 最后 { session.close(); }。谢谢史蒂夫!
    猜你喜欢
    • 1970-01-01
    • 2016-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-15
    相关资源
    最近更新 更多