如何微调 JPA/JAX-RS 应用程序
How to fine-tune a JPA/JAX-RS application
我在 Wildfly/RESTeasy 中开发了一个带有 JPA/Hibernate 后端的 JAX-RS JSON API,但我有严重的数据库访问问题。
例如,应用程序突然停止响应,日志显示一堆:
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (EJB default - 4) IJ031012: Unable to obtain lock in 60 seconds: org.jboss.jca.adapters.jdbc.local.LocalManagedConnection
INFO [org.jboss.jca.core.connectionmanager.listener.TxConnectionListener] IJ000302: Unregistered handle that was not registered: org.jboss.jca.adapters.jdbc.jdk7.WrappedConnectionJDK7
WARN [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool] IJ000609: Attempt to return connection twice: org.jboss.jca.core.connectionmanager.listener.TxConnectionListener
WARN [org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory] (default task-9) IJ030020: Detected queued threads during cleanup
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (ForkJoinPool.commonPool-worker-0) IJ031041: Connection handle has been closed and is unusable
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (ForkJoinPool.commonPool-worker-1) IJ031050: The result set is closed
我认为这是由于不同用户的多次访问(比如同时有 15、20 个用户),因为 one/two 用户不会发生这种情况。
我使用的是 Hibernate 5.1 和 Wildfly 10,以及 SQL Server 2014。这是一个原始安装,没有调整或自定义配置。如何微调基础架构以避免这些问题?
使用 HikariCP 连接池。
根据您的流量配置连接池和数据库中的连接数。
在连接池中,可以选择始终保持一定数量的连接可用。并将连接隔离类型设置为仅提交后。
下面是它的示例,
<persistence-unit name="sample" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<!-- provider -->
<property name="hibernate.connection.provider_class" value="com.xo.web.persistence.XOHikariCPConnectionProvider"/>
<!-- Hibernate properties -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.archive.autodetection" value="hbm" />
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="show_sql" value="false"/>
<property name="hibernate.connection.release_mode" value="after_transaction"/>
<property name="hibernate.connection.autocommit" value="false"/>
<property name="hibernate.connection.isolation" value="2"/>
<property name="hibernate.ejb.interceptor" value="com.xo.web.persistence.intercept.XoEntityInterceptor"/>
<property name="hibernate.jdbc.batch_size" value="100"/>
<property name="hibernate.order_inserts" value="true"/>
<property name="hibernate.order_updates" value="true"/>
<!-- Hikari settings -->
<property name="maximumPoolSize" value="80" />
<property name="autoCommit" value="false" />
<property name="minimumPoolSize" value="20" />
<property name="idleTimeout" value="60000" />
<property name="maxLifetime" value="600000" />
<property name="connectionInitSql" value="select 1" />
<property name="connectionTimeout" value="1000" />
<property name="validationTimeout" value="1000" />
<property name="cachePrepStmts" value="true" />
<property name="prepStmtCacheSize" value="250" />
<property name="prepStmtCacheSqlLimit" value="2048" />
</properties>
</persistence-unit>
问题与 REST 服务有关 @Stateless
,因此在每个请求上打开交易。解决方案是将 @Stateless
DAO 注入 REST 服务:不再有锁定问题。
我在 Wildfly/RESTeasy 中开发了一个带有 JPA/Hibernate 后端的 JAX-RS JSON API,但我有严重的数据库访问问题。
例如,应用程序突然停止响应,日志显示一堆:
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (EJB default - 4) IJ031012: Unable to obtain lock in 60 seconds: org.jboss.jca.adapters.jdbc.local.LocalManagedConnection
INFO [org.jboss.jca.core.connectionmanager.listener.TxConnectionListener] IJ000302: Unregistered handle that was not registered: org.jboss.jca.adapters.jdbc.jdk7.WrappedConnectionJDK7
WARN [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool] IJ000609: Attempt to return connection twice: org.jboss.jca.core.connectionmanager.listener.TxConnectionListener
WARN [org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory] (default task-9) IJ030020: Detected queued threads during cleanup
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (ForkJoinPool.commonPool-worker-0) IJ031041: Connection handle has been closed and is unusable
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (ForkJoinPool.commonPool-worker-1) IJ031050: The result set is closed
我认为这是由于不同用户的多次访问(比如同时有 15、20 个用户),因为 one/two 用户不会发生这种情况。
我使用的是 Hibernate 5.1 和 Wildfly 10,以及 SQL Server 2014。这是一个原始安装,没有调整或自定义配置。如何微调基础架构以避免这些问题?
使用 HikariCP 连接池。 根据您的流量配置连接池和数据库中的连接数。 在连接池中,可以选择始终保持一定数量的连接可用。并将连接隔离类型设置为仅提交后。
下面是它的示例,
<persistence-unit name="sample" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<!-- provider -->
<property name="hibernate.connection.provider_class" value="com.xo.web.persistence.XOHikariCPConnectionProvider"/>
<!-- Hibernate properties -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.archive.autodetection" value="hbm" />
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="show_sql" value="false"/>
<property name="hibernate.connection.release_mode" value="after_transaction"/>
<property name="hibernate.connection.autocommit" value="false"/>
<property name="hibernate.connection.isolation" value="2"/>
<property name="hibernate.ejb.interceptor" value="com.xo.web.persistence.intercept.XoEntityInterceptor"/>
<property name="hibernate.jdbc.batch_size" value="100"/>
<property name="hibernate.order_inserts" value="true"/>
<property name="hibernate.order_updates" value="true"/>
<!-- Hikari settings -->
<property name="maximumPoolSize" value="80" />
<property name="autoCommit" value="false" />
<property name="minimumPoolSize" value="20" />
<property name="idleTimeout" value="60000" />
<property name="maxLifetime" value="600000" />
<property name="connectionInitSql" value="select 1" />
<property name="connectionTimeout" value="1000" />
<property name="validationTimeout" value="1000" />
<property name="cachePrepStmts" value="true" />
<property name="prepStmtCacheSize" value="250" />
<property name="prepStmtCacheSqlLimit" value="2048" />
</properties>
</persistence-unit>
问题与 REST 服务有关 @Stateless
,因此在每个请求上打开交易。解决方案是将 @Stateless
DAO 注入 REST 服务:不再有锁定问题。