Please excuse the layout, i couldn't make HTML tables for some reason so the tables might be difficult to read.
Hello,
We are having troubles with hibernate not correctly deleting/updating records(or us not using it correctly :-) ) in a MySQL database. We have a Nbp data type that
has a set mapping for Qoe objects. Basically we create an Nbpobject that contains two Qoe objects. This works fine and we will see in the database something like:
Qoe Table.
---------------------------------------------------------------------------------------------------------------------------------------------------
id | minBandwidth | maxBandwidth | avgBandwidth | calculator | qoe_hib_id
---------------------------------------------------------------------------------------------------------------------------------------------------
196613 | -1 | -1 | -1 | GameQoECalculator | 131074
196612 | -1 | -1 | 10.0555555556 | FileDownloadQoECalculator | 131074
---------------------------------------------------------------------------------------------------------------------------------------------------
Nbp Table
--------------------------------------------------------
id | nbpName
--------------------------------------------------------
131074 | organiser@here:Proposal.
--------------------------------------------------------
This is correct. If we ask hibernate to delete a Nbp object using:
Code:
// Given:
// Nbp object --- the Nbp object we want to delete from the database.
Session session = openSession();
tx = session.beginTransaction();
// delete the object
session.delete(object);
tx.commit();
It will correctly remove the Nbp object from the database as well as the Qoe objects. This is good also. The problem is when we try to update the Nbp object. If we update
the Nbp object so that instead of having the above two Qoe's associated with it, we update the Nbp so that it has a single Qoe associated with it i.e. the GameQoECalculator
Qoe object (We remove the QoeFileDownloadCalculator object), then it does some funny stuff with the database. So we load the Qoe from the database, and remove one of
the Qoe objects from the set, and call:
Code:
// Given:
// Nbp object --- the modified Nbp we want to save to the database.
// String key --- The unique key used to identify the Nbp (In this case it is the nbpName)
Session session = openSession();
tx = session.beginTransaction();
// find the existing object (gets the existing object from the database using the given key to identify it)
Nbp existingObject = findObject(key);
// found?
if (existingObject != null)
{
// get its Hibernate id and assign to new object for update
object.setId(existingObject.getId());
}
session.saveOrUpdateCopy(object);
tx.commit();
After doing this, we will have some "resource leaks" in the database. With the above example the database tables now look like:
Qoe Table.
---------------------------------------------------------------------------------------------------------------------------------------------------
id | minBandwidth | maxBandwidth | avgBandwidth | calculator | qoe_hib_id
---------------------------------------------------------------------------------------------------------------------------------------------------
196614 | -1 | -1 | -1 | GameQoECalculator | 131074
196613 | -1 | -1 | -1 | GameQoECalculator | NULL
196612 | -1 | -1 | 10.0555555556 | FileDownloadQoECalculator | NULL
---------------------------------------------------------------------------------------------------------------------------------------------------
Nbp Table
--------------------------------------------------------
id | nbpName
--------------------------------------------------------
131074 | organiser@here:Proposal.
--------------------------------------------------------
As you can see in the above, it has correctly updated the Nbp, as in if i query this Nbp using hibernate, it will retrieve the new updated one. The problem is that it leaves some
"leaked" rows in the database. I.e. the old Qoe values that were associated with the Nbp, and just creates a new one to associate with the new/updated Nbp.
Currently to set the new Qoe objects i am just replacing the old ones with new ones (Not necessarily with the same ID). If i modify the new Qoe objects to have the same ID as
the old ones it should work (I havn't tested this yet) except for the case when i remove a Qoe object from the set. Is this functionality what i should expect or am i doing
something incorrectly? As a work around i thought usually we could just delete the object from the database and then add the new/updated one. But in this particular
application that is not possible as other threads may access the database and be expecting to find the object there.
If anyone has any suggestions or help, i would greatly appreciate it. Thanks,
Brendon.
I have included some of the details of the system below, that might be of use in understanding the above text.
Hibernate version 2.1.2
Java Version: 1.5.0-beta-b32c
MySQL Version: 4.0.18
Note: Files have been modified slightly to simplify this post.
-----------------File: Nbp.hbm.xml-------------------------------
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="com.nortelnetworks.convene.app.data">
<class name="Nbp" table="nbp">
<id name="id" type="long" unsaved-value="null">
<generator class="hilo"/>
</id>
<property name="nbpName" type="string" length="100" not-null="true" />
<set name="qoe" cascade="all">
<key column="qoe_hib_id" />
<one-to-many class="Qoe" />
</set>
</class>
</hibernate-mapping>
-----------------File: Nbp.hbm.xml-------------------------------
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="com.nortelnetworks.convene.app.data">
<class name="Qoe" table="qoe">
<id name="id" type="long" unsaved-value="null">
<generator class="hilo"/>
</id>
<!-- Required properties for this given QoE -->
<property name="minBandwidth" type="double" not-null="true" />
<property name="maxBandwidth" type="double" not-null="true" />
<property name="avgBandwidth" type="double" not-null="true" />
<property name="calculator" type="string" not-null="true" />
<property name="serializedCreationData" type="string" not-null="true" />
</class>
</hibernate-mapping>
-----------------File: hibernate.cfg.xml-------------------------------
Code:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">org.gjt.mm.mysql.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/@DB@?autoReconnect=true</property>
<property name="connection.username">@USER@</property>
<property name="connection.password">@PASSWORD@</property>
<property name="hibernate.c3p0.minPoolSize">5</property>
<property name="hibernate.c3p0.maxPoolSize">20</property>
<property name="hibernate.c3p0.timeout">1800</property>
<property name="hibernate.c3p0.max_statement">50</property>
<property name="show_sql">false</property>
<property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
<!-- Mapping files -->
<mapping resource="User.hbm.xml"/>
<mapping resource="NetworkElement.hbm.xml"/>
<mapping resource="PortFilter.hbm.xml"/>
<mapping resource="Nbp.hbm.xml"/>
<mapping resource="Participant.hbm.xml"/>
<mapping resource="SystemData.hbm.xml"/>
<mapping resource="Filter.hbm.xml"/>
<mapping resource="Qoe.hbm.xml"/>
</session-factory>
</hibernate-configuration>