休眠缓慢以获取 Postgres 连接
Posted
技术标签:
【中文标题】休眠缓慢以获取 Postgres 连接【英文标题】:Hibernate Slow to Acquire Postgres Connection 【发布时间】:2012-04-21 22:28:41 【问题描述】:我很难调试这个问题。每当我尝试与 postgres 建立连接时,都需要一整分钟。建立连接后,一切正常。我已经尝试禁用所有映射并且不加载任何映射,但仍然需要很长时间才能获得连接。我也试过禁用验证,没有区别。当我使用一个简单的简单 JDBC 连接时,它是瞬时的。 Hibernate 正在做一些需要大量时间的事情,我似乎无法缩小范围。非常感谢任何输入!
Postgres 驱动程序:
postgresql-9.1-901.jdbc4.jar
配置设置:
<hibernate-configuration>
<session-factory>
<!-- properties -->
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://xxxx.com:5432/xxxxx</property>
<property name="connection.username">xxxxxxx</property>
<property name="connection.password">xxxxxxx</property>
</session-factory>
</hibernate-configuration>
代码中的其他设置:
config.setProperty("hibernate.hbm2ddl.auto", hbm2ddlMode);
//config.setProperty("hibernate.cache.use_query_cache", "true");
config.setProperty("hibernate.cache.use_second_level_cache", "true");
//config.setProperty("hibernate.cache.region.factory_class", "net.sf.ehcache.hibernate.EhCacheRegionFactory");
config.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.EhCacheProvider");
//config.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider");
config.setProperty("hibernate.jdbc.fetch_size", "100");
config.setProperty("hibernate.jdbc.batch_size", "30");
config.setProperty("hibernate.jdbc.use_scrollable_resultset", "true");
config.setProperty("hibernate.connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider");
config.setProperty("hibernate.c3p0.acquire_increment", "1");
config.setProperty("hibernate.c3p0.idle_test_period", "0");
config.setProperty("hibernate.c3p0.min_size", "1");
config.setProperty("hibernate.c3p0.max_size", "2");
config.setProperty("hibernate.c3p0.timeout", "0");
config.setProperty("javax.persistence.validation.mode", "none");
这是发生延迟的代码段:
private SessionFactory buildSessionFactory() throws Exception
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();
//Building session takes a whole minute without mappings!!!
sessionFactory = config.buildSessionFactory(serviceRegistry);
validateConnection();
return sessionFactory;
这是日志结果:
[main] 2012-04-09 10:40:32,823 110391 INFO C3P0ConnectionProvider - HHH000046:
Connection properties: user=hgaidb_test, password=****
[main] 2012-04-09 10:40:32,823 110391 INFO C3P0ConnectionProvider - HHH000006:
Autocommit mode: false
[main] 2012-04-09 10:40:34,100 111668 DEBUG JdbcServicesImpl - Database ->
name : PostgreSQL
version : 8.3.3
major : 8
minor : 3
[main] 2012-04-09 10:40:34,101 111669 DEBUG JdbcServicesImpl - Driver ->
name : PostgreSQL Native Driver
version : PostgreSQL 9.1 JDBC4 (build 901)
major : 9
minor : 1
*******************************************************************************
// 1 MINUTE DELAY
*******************************************************************************
[main] 2012-04-09 10:40:34,102 111670 DEBUG JdbcServicesImpl - JDBC version : 4.
0
[main] 2012-04-09 10:41:21,632 159200 INFO Dialect - HHH000400: Using dialect:
org.hibernate.dialect.PostgreSQLDialect
*******************************************************************************
[main] 2012-04-09 10:41:21,669 159237 INFO LobCreatorBuilder - HHH000424: Disab
ling contextual LOB creation as createClob() method threw error : java.lang.refl
ect.InvocationTargetException
[main] 2012-04-09 10:41:21,814 159382 DEBUG SettingsFactory - Automatic flush du
ring beforeCompletion(): disabled
[main] 2012-04-09 10:41:21,814 159382 DEBUG SettingsFactory - Automatic session
close at end of transaction: disabled
[main] 2012-04-09 10:41:21,815 159383 DEBUG SettingsFactory - JDBC batch size: 3
0
[main] 2012-04-09 10:41:21,816 159384 DEBUG SettingsFactory - JDBC batch updates
for versioned data: disabled
[main] 2012-04-09 10:41:21,816 159384 DEBUG SettingsFactory - Scrollable result
sets: enabled
[main] 2012-04-09 10:41:21,817 159385 DEBUG SettingsFactory - Wrap result sets:
disabled
[main] 2012-04-09 10:41:21,818 159386 DEBUG SettingsFactory - JDBC3 getGenerated
Keys(): enabled
[main] 2012-04-09 10:41:21,818 159386 DEBUG SettingsFactory - JDBC result set fe
tch size: 100
[main] 2012-04-09 10:41:21,819 159387 DEBUG SettingsFactory - Connection release
mode: auto
[main] 2012-04-09 10:41:21,819 159387 INFO TransactionFactoryInitiator - HHH000
399: Using default transaction strategy (direct JDBC transactions)
[main] 2012-04-09 10:41:21,844 159412 DEBUG SettingsFactory - Default batch fetc
h size: 1
[main] 2012-04-09 10:41:21,844 159412 DEBUG SettingsFactory - Generate SQL with
comments: disabled
[main] 2012-04-09 10:41:21,845 159413 DEBUG SettingsFactory - Order SQL updates
by primary key: disabled
[main] 2012-04-09 10:41:21,846 159414 DEBUG SettingsFactory - Order SQL inserts
for batching: disabled
[main] 2012-04-09 10:41:21,846 159414 DEBUG SettingsFactory - Query translator:
org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory
[main] 2012-04-09 10:41:21,867 159435 INFO ASTQueryTranslatorFactory - HHH00039
7: Using ASTQueryTranslatorFactory
[main] 2012-04-09 10:41:21,867 159435 DEBUG SettingsFactory - Query language sub
stitutions:
[main] 2012-04-09 10:41:21,867 159435 DEBUG SettingsFactory - JPA-QL strict comp
liance: disabled
[main] 2012-04-09 10:41:21,868 159436 DEBUG SettingsFactory - Second-level cache
: enabled
[main] 2012-04-09 10:41:21,868 159436 DEBUG SettingsFactory - Query cache: disab
led
[main] 2012-04-09 10:41:21,869 159437 DEBUG SettingsFactory - Cache region facto
ry : org.hibernate.cache.internal.NoCachingRegionFactory
[main] 2012-04-09 10:41:21,872 159440 DEBUG SettingsFactory - org.hibernate.cach
e.internal.NoCachingRegionFactory did not provide constructor accepting java.uti
l.Properties; attempting no-arg constructor.
[main] 2012-04-09 10:41:21,873 159441 DEBUG SettingsFactory - Optimize cache for
minimal puts: disabled
[main] 2012-04-09 10:41:21,873 159441 DEBUG SettingsFactory - Structured second-
level cache entries: disabled
[main] 2012-04-09 10:41:21,873 159441 DEBUG SettingsFactory - Statistics: disabl
ed
[main] 2012-04-09 10:41:21,874 159442 DEBUG SettingsFactory - Deleted entity syn
thetic identifier rollback: disabled
[main] 2012-04-09 10:41:21,874 159442 DEBUG SettingsFactory - Default entity-mod
e: pojo
[main] 2012-04-09 10:41:21,875 159443 DEBUG SettingsFactory - Named query checki
ng : enabled
[main] 2012-04-09 10:41:21,875 159443 DEBUG SettingsFactory - Check Nullability
in Core (should be disabled when Bean Validation is on): enabled
[main] 2012-04-09 10:41:21,876 159444 DEBUG SettingsFactory - multi-tenancy stra
tegy : NONE
我已经对此进行了更多研究,逐步通过调试器。我的类路径中没有所有源代码,但我仍然可以看到变量。在那一分钟的等待期间,Hibernate 正在查询 pg_catalog.pg_type 表:
[SELECT typname FROM pg_catalog.pg_type WHERE oid = , ]
截图如下:
【问题讨论】:
这种延迟可能是DNS问题造成的,尝试使用connection.url
中的IP地址代替域名排除。
我用IP试过了,采集时间还是没有差别。
另见:***.com/questions/23969399/…
一个问题(2014 年)已发布到 Hibernate 项目:请参阅 hibernate.atlassian.net/browse/HHH-9124。在撰写本文时,此问题仍未解决。
【参考方案1】:
我修好了 =) 我真的不得不四处寻找答案。基本上,它归结为加载元数据和 JDBC 驱动程序。它正在加载所有元数据,包括 sql 列旁边的 cmets 和其他各种结构,这些都是操作不需要的。我不知道为什么默认情况下会启用此功能,但除非您明确需要,否则您绝对应该关闭此功能:
config.setProperty("hibernate.temp.use_jdbc_metadata_defaults","false");
立即连接!
我能找到的唯一信息是代码:
107 // 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value.
108 // The need for it is intended to be alleviated with future development, thus it is
109 // not defined as an Environment constant...
110 //
111 // it is used to control whether we should consult the JDBC metadata to determine
112 // certain Settings default values; it is useful to *not* do this when the database
113 // may not be available (mainly in tools usage).
114 boolean useJdbcMetadata = ConfigurationHelper.getBoolean( "hibernate.temp.use_jdbc_metadata_defaults", configValues, true );
http://grepcode.com/file/repo1.maven.org/maven2/org.hibernate/hibernate-core/4.1.1.Final/org/hibernate/engine/jdbc/internal/JdbcServicesImpl.java#JdbcServicesImpl
【讨论】:
根据我的经验,必须明确定义这种真正有效的休眠方言。否则它会导致应用程序启动失败(至少对于 PostgreSQL 9.3 和 Hibernate 4)。 SchemaUpdate 可能会受到禁用它的影响。 启动需要 1.5 分钟,直到我将<property name="temp.use_jdbc_metadata_defaults">false</property>
添加到 hibernate.cfg.xml。感谢您的提示!
见org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(Map)
这不适用于 Spring Boot。我将此作为属性添加到 application.properties,它再次开始工作:spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
【参考方案2】:
我还必须启用 hibernate.jdbc.use_get_generated_keys 否则身份生成策略会引发异常。在它根据从数据库收到的元数据自动启用之前。所以我的整个解决方案是在persistence.xml中添加以下两行:
<property name="hibernate.jdbc.use_get_generated_keys" value="true" />
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
【讨论】:
谢谢!使用 Hibernate 5.2、Spring Framework 4.3 和 PostgreSQL JDBC 4.2 请参阅this question 了解有关由传奇人物@CraigRinger 引起滋扰的序列的更多详细信息。【参考方案3】:差不多 7 年后,这仍然是一个问题......
关闭“temp”键会有所帮助,但逐个启用会自动配置的属性会很麻烦(请参阅其他答案)。
对于 Oracle 和 Teradata,我没有注意到这种放缓,所以我深入挖掘并发现最慢的部分在哪里: https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/jdbc/PgDatabaseMetaData.java#L2237
在我的例子中,这个结果集有 372 行(类型)。然后,对于每个驱动程序从 https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/jdbc/TypeInfoCache.java#L204 这会导致针对数据库的大量 SQL 语句。
现在不知道如何加快速度,幸运的是它需要一次然后被缓存。
【讨论】:
虽然只需要一次,但是在开发过程中这很烦人,因为我们需要等待很长时间才能看到我们所做的事情是否成功。【参考方案4】:我遇到了可滚动结果集的问题,所以我不得不添加第三个参数,见下文:
<property name="hibernate.temp.use_jdbc_metadata_defaults">false</property>
<property name="hibernate.jdbc.use_get_generated_keys">true</property>
<property name="hibernate.jdbc.use_scrollable_resultset">true</property>
【讨论】:
【参考方案5】:一个 postgresql 服务器可以包含多个数据库。不幸的是你不能hide other-database metadatas to one connection,这就是jdbc-driver读取元数据需要很长时间的原因!
将这些数据库分离到不同的postgres-servers中,元数据读取的性能将会提高!
阅读how to seperate on centos。
【讨论】:
【参考方案6】:这听起来有点像我们在 Ruby on Rails 中看到的问题。您可能会寻找与我在此处描述的类似原因:
http://archives.postgresql.org/pgsql-performance/2009-11/msg00128.php
简而言之,这个问题是由从多个 ClassLoader 上下文显式注册 JDBC 驱动程序引起的。
【讨论】:
【参考方案7】:禁用hibernate.temp.use_jdbc_metadata_defaults
可能会增加应用程序的启动速度,但会禁用某些功能。喜欢batch
操作。当 hibernate 不加载 jdbc 元数据时,hibernate 将全局批处理大小设置为 0,这意味着禁用批处理操作。在这种情况下,使用session
范围的批处理操作的唯一方法。就像下面的代码示例
entityManager
.unwrap( Session.class )
.setJdbcBatchSize( 10 );
所以禁用此属性时要小心
【讨论】:
以上是关于休眠缓慢以获取 Postgres 连接的主要内容,如果未能解决你的问题,请参考以下文章