-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Hibernate Transaction bug?
PostPosted: Mon Apr 25, 2005 9:56 am 
Newbie

Joined: Sat Sep 18, 2004 1:36 am
Posts: 12
Hello..

I'm currently using Hibernate 2.1.18,
with MySQL 4.1.10a



this is a snapshot of my code:
------------------------------------------------------------
CODE 1 (this works, but require like 1000 transactions)

Code:
for (int j=0;j<fieldUpdates.size();j++){
..
..
..
       Session sess = getSessionFactory().openSession();
       Transaction txFieldUpdate = sess.beginTransaction();
       for (int i=0; i<methods.size(); i++) {
              Bean aBean = new Bean();
              aBean.setSomething((String)fieldUpdates[j]);
              aBean.setSomething2((String)methods[i]);
              ...
              sess.save(aBean);
       }
       txFieldUpdate.commit();
       sess.close();
}



Generated SQL as shown via show_sql has:
Hibernate: insert into bean (table_name, item_id, field_name
, timestamp, deleted, inserted, field_update_id) values (?, ?, ?, ?, ?, ?, ?)

(the detail is not crucial. What's important is that the INSERT sql query is there).



------------------------------------------------------------
CODE 2 (this does not work, but if it works, it only require 1 transaction)

Code:
Session sess = getSessionFactory().openSession();
Transaction txFieldUpdate = sess.beginTransaction();
for (int j=0;j<fieldUpdates.size();j++){
..
..
..
       for (int i=0; i<methods.size(); i++) {
              Bean aBean = new Bean();
              aBean.setSomething((String)fieldUpdates[j]);
              aBean.setSomething2((String)methods[i]);
              ...
              sess.save(aBean);
       }
}
txFieldUpdate.commit();
sess.close();

------------------------------------------------------------

The generated SQL as shown by show_sql however, does not have INSERT statement. It instead use SELECT statement.

Have I done something silly in my CODE 2 above? It does not insert any records to the "Bean" table at all.
i would like the ability to do the insertion in just 1 transaction, since it would enable me to rollback the whole insertion. (and it's faster, am i correct?)
Just to give more information, there are around 1000 entries in fieldUpdates, and around entries in methods. :)
so technically (if i'm right), with code 2, there would be just 1 transaction. whereas in code 1, there would be 1000 transactions.


Thanks in advance for the help!




Regards,


Alex.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 25, 2005 5:22 pm 
Regular
Regular

Joined: Mon Jul 26, 2004 2:28 pm
Posts: 86
Location: Pensacola, Florida
I can't tell without your mapping, but it probably has to do with the way you have your id defined. Some things to look at:

1. Are you using a single column as the id when you really need a composite-id (as your example would suggest)?
2. What is the unsaved-value for the ID?
3. What generator are you using? "assigned" or "any"? If so, then you may need to use a version column or an interceptor to indicate to Hibernate when the object is saved
3. If you are using a composite ID, then you should consider either adding a surrogate key (preferred), using a version column, or implementing an interceptor that will indicate whether the object is saved

The only reason Hibernate would ignore a save( ) and not generate an insert statement is if it thought the object was already persisted and up-to-date. This could be because an object with the same id key(s)/value(s) is in the session, or if the ID generator is "assigned", in which case Hibernate does not know what do to.

- Jesse


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 25, 2005 7:22 pm 
Newbie

Joined: Sat Sep 18, 2004 1:36 am
Posts: 12
Hi, thanks for the reply..


Here is my mapping file and the actual code..

---------------------------------------------------------------------
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
   
<hibernate-mapping>
<!--
    Created by the Middlegen Hibernate plugin

    http://boss.bekk.no/boss/middlegen/
    http://hibernate.sourceforge.net/
-->

<class
    name="au.com.hybrid.warehouse.tables.ServerFieldLastUpdate"
    table="server_field_last_update"
>

    <id
        name="fieldUpdateId"
        type="java.lang.Long"
        column="field_update_id"
    >
        <generator class="hilo">
            <param name="table">server_field_last_update_key</param>
            <param name="column">next_value</param>
            <param name="max_lo">0</param>
        </generator>
    </id>

    <property
        name="tableName"
        type="java.lang.String"
        column="table_name"
        not-null="true"
        length="255"
    />
    <property
        name="itemId"
        type="java.lang.String"
        column="item_id"
        not-null="true"
        length="50"
    />
    <property
        name="fieldName"
        type="java.lang.String"
        column="field_name"
        not-null="true"
        length="100"
    />
    <property
        name="timestamp"
        type="java.sql.Timestamp"
        column="timestamp"
        length="19"
    />
    <property
        name="deleted"
        type="java.lang.String"
        column="deleted"
        not-null="true"
        length="2"
    />
    <property
        name="inserted"
        type="java.lang.String"
        column="inserted"
        not-null="true"
        length="2"
    />

    <!-- associations -->

</class>
</hibernate-mapping>

----------------------------------------------------------------------
CODE 1

Code:
for (int j=0;j<fieldUpdates.size();j++){
...
...
..
(**) Session sess = WarehouseSessionFactory.getSession(); // this method get the session
(**) Transaction txFieldUpdate = sess.beginTransaction();   
     for (int i=0; i<methods.size(); i++) {
          ServerFieldLastUpdate sfluBean = new ServerFieldLastUpdate();
     sfluBean.setTableName(tableName);
     sfluBean.setItemId(itemIdString);
     sfluBean.setInserted("Y");
     sfluBean.setTimestamp(new Date((new java.util.Date()).getTime()));
     sfluBean.setFieldName(methodName);
     sfluBean.setDeleted("N");
     sess.saveOrUpdate(sfluBean);
     }
(**) txFieldUpdate.commit();
(**) sess.close();
}


----------------------------------------------------------------------
CODE 2

Code:
Session sess = WarehouseSessionFactory.getSession(); // this method get the session
Transaction txFieldUpdate = sess.beginTransaction();   
for (int j=0;j<fieldUpdates.size();j++){
...
...
..
     for (int i=0; i<methods.size(); i++) {
          ServerFieldLastUpdate sfluBean = new ServerFieldLastUpdate();
     sfluBean.setTableName(tableName);
     sfluBean.setItemId(itemIdString);
     sfluBean.setInserted("Y");
     sfluBean.setTimestamp(new Date((new java.util.Date()).getTime()));
     sfluBean.setFieldName(methodName);
     sfluBean.setDeleted("N");
     sess.saveOrUpdate(sfluBean);
     }
}
txFieldUpdate.commit();
sess.close();

------------------------------------------------------------------------
A sidenote, that the two code are exactly the same, apart from that I move the
line marked by (**) in CODE 1 out of the loop. The reason being (as I had mentioned):
- performance (one session, one transaction, vs 1000 session, 1000 transaction)
- ability to rollback the whole insertion (it is possible to do in code 2, but it has
to be done manually, i.e. recording what has been inserted, and delete them manually)


and just to reply to some of your questions,
1. I'm using hilo algorithm for the primary key generation, and no, it's not a composite id at all
(and i don't think i need composite id for this, since CODE 1 works fine).

2. ".....could be because an object with the same id key(s)/value(s) is in the session"
Umm.. i don't think this is the problem here, since as you can see, the two codes are the same,
and I call "new ServerFieldLastUpdate()" each time, and setting different values. Also the fact
that code 1 works, i don't think this is the reason why code 2 does not work. Even if that was the reason, at least 1 object should get saved (and the following did not, since Hibernate
has detected that an object with the same id / value is in the session), but none of the object
get saved.


There wouldn't be a maximum size of objects a Session can store before being persisted, would it?
(I hope so.... )


Thanks in advance for the help!


Regards,

Alex.


Top
 Profile  
 
 Post subject: Problem solved.. some explanation please?? :)
PostPosted: Mon Apr 25, 2005 9:30 pm 
Newbie

Joined: Sat Sep 18, 2004 1:36 am
Posts: 12
Hello...

it turns out that the bug was in my own code.. (as it should be!)

--------------------------------------------------------------------
CODE 2
Code:
sess = WarehouseSessionFactory.getSession(); // this method get the session
Transaction txFieldUpdate = sess.beginTransaction();   
for (int j=0;j<fieldUpdates.size();j++){
...
...
..
     for (int i=0; i<methods.size(); i++) {
          ServerFieldLastUpdate sfluBean = new ServerFieldLastUpdate();
     sfluBean.setTableName(tableName);
     sfluBean.setItemId(itemIdString);
     sfluBean.setInserted("Y");
     sfluBean.setTimestamp(new Date((new java.util.Date()).getTime()));
     sfluBean.setFieldName(methodName);
     sfluBean.setDeleted("N");
     sess.saveOrUpdate(sfluBean);
     }
}
txFieldUpdate.commit();
sess.close();


-------------------------------------------------------------------

The problem was that in that line (...) i have called this method
ArrayList existingBeans = getServerFieldUpdateBeans(tableName, itemIdString)

Now, this is what's inside the method
---------------------------------------------------------------------
Code:
public ArrayList getServerFieldUpdateBeans(String tableName, String itemId)       {
try{
             sess = WarehouseSessionFactory.getSession();
             Object[] criteria = {tableName, itemId};

            Type[] types = {Hibernate.STRING, Hibernate.STRING};

            String query = "SELECT s FROM ServerFieldLastUpdate s WHERE s.tableName=? AND s.itemId=?";

            List result = sess.find(query, criteria , types);
.....
}catch(HibernateException e){
.....
}finaly{
   if (sess!=null) {
                try{
                    sess.flush();
                    sess.close();
                }catch(HibernateException e){
                    e.printStackTrace();
                    return null;
                }
            }
    }
     ......
}

---------------------------------------------------------------------------------

As you can see, they share the same session. Inside getServerFieldUpdateBeans(), the global session get replaced
& closed.
Now, what I wanted to know is... what happened upon calling
.commit() ? is it going to commit based on the old Session object,
or the new Session object?
My guess, the old one, while all the new objects are saved in
the new Session object.

Am I right?

Again, thanks a lot for the help!



Regards,


Alex.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 25, 2005 9:47 pm 
Regular
Regular

Joined: Mon Jul 26, 2004 2:28 pm
Posts: 86
Location: Pensacola, Florida
I'm not 100% sure. I can look at the source code when I get into work tomorrow. If no exceptions are being thrown then apparently the transaction will exit cleanly if the session is closed without performing any updates.

- Jesse


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.