3

I have a project where I would like to use Hibernate for database access. In the application, the JPA api is used.

The persistence.xml file is this

<persistence 
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
    <persistence-unit name="hibernate.test"
        transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="hibernate.ejb.cfgfile" value="/hibernate/hibernate.cfg.xml"/>
        </properties>
    </persistence-unit>
</persistence>

The hibernate.cfg.xml file is the following

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory>
  <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
  <property name="hibernate.connection.password">password</property>
  <property name="hibernate.connection.url">jdbc:oracle:thin:@//server:1521/DBNAME</property>
  <property name="hibernate.connection.username">username</property>
  <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
  <!-- <property name="hibernate.hbm2ddl.auto">verify</property>  -->
  <property name="hibernate.default_catalog">SYS_SOMETHING</property>
  <property name="hibernate.default_schema">SYS_SOMETHING</property>
 </session-factory>
</hibernate-configuration>

The problem is with this setup, that the entityManagerFactory = Persistence.createEntityManagerFactory("hibernate.test");

call takes about 25 seconds to complete.

If I move the configuration directly to the persistence.xml file, the connection completes in 1 second. The error occurs with both Oracle and MySQL databases.

I can see the delay in the log file, nothing else is happening during this time

525 [pool-2-thread-1] INFO org.hibernate.cfg.Environment  - HHH000021: Bytecode provider name : javassist
21668 [pool-2-thread-1] DEBUG org.hibernate.service.internal.JaxbProcessor  - cfg.xml document did not define namespaces; wrapping in custom event reader to introduce namespace information

Complete log: http://pastebin.com/4NjPpFPe

This delay is only about 200ms if the cfg.xml is not used.

During this time, there process memory does not change, the cpu use is at 0% and there are 0 interactions according to sysinternals Process Monitor.

I would like to keep this setup because hibernate.cfg.xml is used for reverse engineering and hibernate tools also.

Tools used: java8 hibernate-4.3.8 ojdbc7 jpa-2.1

Thank you for any suggestions in advance.

Update:

Found the solution, now I'm a happy man!

The hibernate framework (or the xml parser, I'm not sure) would wait on a http request.

To fix the problem, replace

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

with

<!DOCTYPE hibernate-configuration SYSTEM "-//Hibernate/Hibernate Configuration DTD 3.0//EN">
  • Is the delay is only one time when the server starts? – Subir Kumar Sao Apr 16 '15 at 09:48
  • Every time when the application is started, when the EntityManagerFactory is created.The EntityManagers and queries etc are all fast. – Biró Krisztián Apr 16 '15 at 09:52
  • when you run your project and the server is started. how much time it take? what i want to say that to start a server like Jboss or tomcat or whatever server you running it's normal that it takes 25s !! – Fakher Apr 16 '15 at 12:46
  • This is a desktop application connecting to a remote database. – Biró Krisztián Apr 16 '15 at 12:53
  • 1
    FWIW "hibernate.cfg.xml" is nothing to do with JPA, and should be merged into persistence.xml – Neil Stockton Apr 16 '15 at 14:11
  • @NeilStockton I need the cfg.xml for reverse engineering and tooling. Filling in the same data in persistence.xml would be duplication and should be avoided. Hibernate supports this with the hibernate.ejb.cfgfile property. The connection works this way, but creating the EntityManagerFactory takes uncomfortably long time. – Biró Krisztián Apr 16 '15 at 15:01
  • @BiróKrisztián I have looked at the source code of hibernate jpa and it doesn't do anything _crazy_ (I mean, it will try to read your xml and then try to setup the session factory and all but nothing out of ordinary). And, because hibernate doesn't log much information when trying to "build" the session factory, I guess the most straightforward method is to debug it one by one by yourself. or is it possible if you publish your project in github or bitbucket? so i could try it and see which code takes many time. – kucing_terbang Apr 18 '15 at 17:17
  • 1
    @kucing_terbang Thank you very much for your time. I just had the time to do that.The process was hanging in a http request. Changing the xml DOCTYPE will fix the problem. I'll update the question with the solution. – Biró Krisztián Apr 22 '15 at 06:48

3 Answers3

2

Found the solution, now I'm a happy man!

The hibernate framework (or the xml parser, I'm not sure) would wait on a http request.

To fix the problem, replace

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

with

<!DOCTYPE hibernate-configuration SYSTEM "hibernate-configuration-3.0.dtd">

Edit: Replaced the "with" line, this will use the correct dtd file in release mode and in reverse engineering too (it was not possible to use reveng without specifying the actual file).

  • glad, it worked out in your case. still, it is just some kind of workaround as you're skipping internal validation of the XML schema. IMHO this is not a true solution, maybe you should submit a bug report to Hibernate issue tracker? – MWiesner Apr 26 '15 at 10:56
  • please consider to not mark this answer as a solution, as it is a workaround "only" – MWiesner Apr 26 '15 at 10:58
  • @MWiesner updated my answer, it should validate it. Eclipse recognizes it also. It seems like hibernate tries to access the dtd online, but it is behind a proxy server. If I skip that, the dtd in the package will be used. – Biró Krisztián May 19 '15 at 08:13
  • ok, seems reasonable, yet I can not confirm as I did not test it thoroughly. – MWiesner May 22 '15 at 07:06
1

This issue could be related to a property which regulates Hibernate's internal behavior to handle JDBC metadata on first attempt to create connection.

Try adding this property

"hibernate.temp.use_jdbc_metadata_defaults"

to your hibernate.cfg.xml. This helped me in a similar problem in a PostgreSQL environment to bring a "lame" startup back to "life". By default (i.e., not defined explicitly) this property is set to true which causes a full load of ALL metadata of your database via JDBC (which might obviously be slow in certain situations...).

The hibernate.cfg.xml file should then be used as follows

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory>
  <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
  <property name="hibernate.connection.password">password</property>
  <property name="hibernate.connection.url">jdbc:oracle:thin:@//server:1521/DBNAME</property>
  <property name="hibernate.connection.username">username</property>
  <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
  <!-- <property name="hibernate.hbm2ddl.auto">verify</property>  -->
  <property name="hibernate.default_catalog">SYS_SOMETHING</property>
  <property name="hibernate.default_schema">SYS_SOMETHING</property>
  <property name="hibernate.temp.use_jdbc_metadata_defaults">false</property>
 </session-factory>
</hibernate-configuration>
MWiesner
  • 8,868
  • 11
  • 36
  • 70
0

Alternatively you can load the dtd directly from the JAR file:

<!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
        "classpath://org/hibernate/hibernate-mapping-3.0.dtd">
Chin
  • 19,717
  • 37
  • 107
  • 164