Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java Hibernate unnecessary queries on detached objects

I'm inserting, updating and deleting many detached objects with hibernate and a c3p0 connectionpool. The problem is that hibernate does not batch the statements but instead does a

select @@session.tx_read_only

between every session.persist/insert/update/delete(object). Profiling the sql-connection it looks like this:

select @@session.tx_read_only
insert...
select @@session.tx_read_only
insert...
select @@session.tx_read_only
insert...
select @@session.tx_read_only
insert...
select @@session.tx_read_only
insert...
select @@session.tx_read_only

with select @@session.tx_rad_only always returning "0" (of course). It doesn't matter whether i use a stateless or stateful session. The resulting performance is not acceptable and far of any expectation.

My Hibernate Konfiguration:

 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:4040/xy?zeroDateTimeBehavior=convertToNull</property>
    <property name="hibernate.connection.username">xy</property>
    <property name="hibernate.connection.password">xy</property>
    <property name="hibernate.connection.autocommit">false</property>
    <property name="hibernate.show_sql">false</property>
    <property name="hibernate.format_sql">false</property>
    <property name="hibernate.use_sql_comments">false</property>
    <property name="hibernate.query.factory_class">org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</property>
    <property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.timeout">300</property>
    <property name="hibernate.c3p0.max_statements">250</property>
    <property name="hibernate.c3p0.idle_test_period">3000</property>
    <property name="hibernate.jdbc.batch_size">250</property>
    <property name="hibernate.connection.release_mode">auto</property>
    <property name="hibernate.order_inserts">true</property>
    <property name="hibernate.order_updates">true</property>
    <property name="hibernate.cache.use_second_level_cache">false</property>
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
    <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="net.sf.ehcache.configurationResourceName">hibernate_ehcache.xml</property>

I'm using:

<dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>4.3.5.Final</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.31</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.4.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>ejb3-persistence</artifactId>
        <version>1.0.2.GA</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
        <version>4.3.4.Final</version>
    </dependency>

I have nearly no expirience with hibernate and it is a good guess i made a huge mistake so please feel free to suggest anything. I switched to hibernate because the ORM functionality and am coming from plain jdbc prepared statements with a blazing fast performance. The MYSQL-Server is in a good configuration-state.

edit1: i'm aware of: Unnecessary queries in Hibernate - MySql I've got no transactional annotations in my entities nor a defined isolationlevel anywhere

edit2: i changed my connectionpool to bonecp - and the problem continues. Seems to be clearly a hibernate copnfiguration issue.

edit3: tried many different things and found maybe a trace of a hint: If I manualy session.flush() every 5 inserts (=size of batch e.g.)[tried the batch-example AGAIN from hibernate], the select @@session.tx_read_only query appears double - every 5 queries. I therefore assume that select @@session.tx_read_only is related to flushing. are there any ways to prevent hibernate from flushing every single insert/update? I tried so far: session.setFlushMode(FlushMode.COMMIT/NEVER/etc) without any change in the behaviour. Maybe I misconfigured anything... what does hibernate trigger to flush every insert? Unique constraint at the tables? hibernate validation framework? complex object-graphs? difficult concurrency? maybe a locking issue (Hibernate isn't sure if someone else locked the tables and doesn't batch but checks every single insert if the table is read only?)?

i found nothing related to this extrem (I assume) flushing bahaviour.

like image 398
Florian Bronder Avatar asked Jul 03 '14 21:07

Florian Bronder


People also ask

How do you persist a detached object in Hibernate?

Making A Detached Object Persistent Again Hibernate allows detached objects to be associated with a persistence context again. One way to achieve this is to use the update method of the session. The update method forces an update operation to be fired for the passed object.

What is dirty checking in Hibernate?

Hibernate monitors all persistent objects. At the end of a unit of work, it knows which objects have been modified. Then it calls update statement on all updated objects. This process of monitoring and updating only objects that have been changed is called automatic dirty checking in hibernate.

What are detached objects in Hibernate?

A detached entity is just an ordinary entity POJO whose identity value corresponds to a database row. The difference from a managed entity is that it's not tracked anymore by any persistence context. An entity can become detached when the Session used to load it was closed, or when we call Session.

Can we change the object state from detached to persistent?

You can again move a detached object to Persistent state by calling Session. update() or Session. saveOrUpdate() method.


2 Answers

We solved this issue by just setting useLocalSessionState=true in the connection string.

The below link explain the details of ReadOnly related changes happened from Mysql5.6 and the java connector 5.1.23. http://dev.mysql.com/doc/relnotes/connector-j/en/news-5-1-23.html

like image 127
Dhanas chenniappan Avatar answered Sep 28 '22 07:09

Dhanas chenniappan


You need to include all those CRUD operations in a single Transaction so all statements are executed in the same DB connection.

You can also enable the following Hibernate configurations:

<property name="hibernate.order_inserts" value="true"/>
<property name="hibernate.order_updates" value="true"/>
<property name="hibernate.jdbc.batch_size" value="50"/>

Those queries don't mean you don't have batching. It's a MySQL thing

Some drivers require special batching reordering directives:

<property name="hibernate.connection.url">jdbc:mysql://host:port/db?rewriteBatchedStatements=true</property
like image 39
Vlad Mihalcea Avatar answered Sep 28 '22 08:09

Vlad Mihalcea