-->
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.  [ 8 posts ] 
Author Message
 Post subject: save or update as atomic action
PostPosted: Thu Sep 25, 2008 7:16 am 
Beginner
Beginner

Joined: Thu Jun 14, 2007 4:33 am
Posts: 39
hi, im using hibernate and spring with declarative transactions:

now i have an importer that persists a list of domainobjects:

Code:
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void doImport(List<Domain> domains) {
         int count = 0;
         for (Domain d : domains) {
 
            //do some stuff with data

             this.dao.saveOrUpdate(d);     
             count ++;

             if (count % 50 == 0) {
                this.m_sf.currentSession.flush();
                this.m_sf.currentSession.clear();
                count = 0;
             }
        }
}


now on the very first import with an empty database this function will succeed. but what if the same data allready partially exists in the database and i only want to update fields that have been changed?

obvious on each domain-object i could query the database if a record allready exists (with businesskey) and then do an update, but i think this would slow down things. furthermore this action woudlnt be atomic - between doing the check an inserting the data, someone else could have inserted this record (allthough performance is the more important factor ).

another approach would be, trying to insert the data. if the record allready exists an ConstraintViolationException would be thrown. but the api-documentation states clearly: "If the Session throws an exception, the transaction must be rolled back and the session discarded. The internal state of the Session might not be consistent with the database after the exception occurs. " and of course this is not what i want.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 25, 2008 8:38 pm 
Expert
Expert

Joined: Mon Nov 26, 2007 2:29 pm
Posts: 443
The beans on that List<Domain>, are they still connected to your session in any way, or is it just a list of freshly created beans, without an assigned id?

Or either?

_________________
Gonzalo Díaz


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 25, 2008 9:26 pm 
Beginner
Beginner

Joined: Thu Jun 14, 2007 4:33 am
Posts: 39
sorry i wasnt clear on that. List<Domain> contains freshly created beans not assigned to the session and without id.

the Domain-class has several properties, one of them mapped with unique-key + not-null constraint

currently i querry the database for this property. if i get an instance i update, if not i do an insert:

Code:
for (Domain p : domainlist) {
      Domain tp = dao.findByCostumer_Number(p.costumer_number);
      if (tp != null) {
                tp = updateInstance(tp, p);
                tp = dao.makePersistent(tp);
      } else
                tp = dao.makePersistent(p);
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 25, 2008 10:30 pm 
Expert
Expert

Joined: Mon Nov 26, 2007 2:29 pm
Posts: 443
It is still unclear what that "dao" object of yours does, especially, how does it obtain its sessions...

Whatever it does inside to obtain a session, can you repeat it just outside your for-loop, and then simply call session.merge(domain) ?

The idea of session.merge() is to reattach an object to the session, independently of its previous state. So it is ideal for this case.

_________________
Gonzalo Díaz


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2008 9:23 am 
Beginner
Beginner

Joined: Thu Jun 14, 2007 4:33 am
Posts: 39
the session is injected via spring, so i dont need to care about that. also the transaction is started through spring. the transaction simply spoken starts on function-call and ends when leaving it. all i need to do is marking a function with the annotation
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
and some configuration in the spring context


hmm merge really seams to do the job, thx!
but is there any way to tell hibernate only to update properties that are not-null?

to make an example e.g. my domain-object is:
Code:
class EmailAddress{
   String costumernumber;
   String address;
   String usage;
}


my database allready contains a record for the given costumernumber - which is unique. in this case the address changed (the data is red from another database). the usage is incremented each time a special application reads the email-address in my database.

the point is: my datasource does not contain any information about that usage-field, so eventually it would be null each time i get the updated EmailAddress from my it.

so an EmailAddress in my List<EmailAddress> now would contain the new address and the costumernumber, but the usage field is null since it would not contain any new data.. now i dont want hibernate to update this field if its null.

is that possible?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2008 10:14 am 
Expert
Expert

Joined: Mon Nov 26, 2007 2:29 pm
Posts: 443
Looks like you don't need to persist that usage field.
Why don't you just remove it from your mapping?

_________________
Gonzalo Díaz


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2008 10:26 am 
Beginner
Beginner

Joined: Wed Sep 24, 2008 5:44 pm
Posts: 34
Code:
<class
        name="ClassName"                              (1)
        table="tableName"                             (2)
        discriminator-value="discriminator_value"     (3)
        mutable="true|false"                          (4)
        schema="owner"                                (5)
        catalog="catalog"                             (6)
        proxy="ProxyInterface"                        (7)
        dynamic-update="true|false"                   (8)
        dynamic-insert="true|false"                   (9)
        select-before-update="true|false"             (10)
        polymorphism="implicit|explicit"              (11)
        where="arbitrary sql where condition"         (12)
        persister="PersisterClass"                    (13)
        batch-size="N"                                (14)
        optimistic-lock="none|version|dirty|all"      (15)
        lazy="true|false"                             (16)
        entity-name="EntityName"                      (17)
        check="arbitrary sql check condition"         (18)
        rowid="rowid"                                 (19)
        subselect="SQL expression"                    (20)
        abstract="true|false"                         (21)
        node="element-name"
/>


(8)      dynamic-update (optional, defaults to false): Specifies that UPDATE SQL should be generated at runtime and contain only those columns whose values have changed.


(9)    dynamic-insert (optional, defaults to false): Specifies that INSERT SQL should be generated at runtime and contain only the columns whose values are not null.


(10)    select-before-update (optional, defaults to false): Specifies that Hibernate should never perform an SQL UPDATE unless it is certain that an object is actually modified. In certain cases (actually, only when a transient object has been associated with a new session using update()), this means that Hibernate will perform an extra SQL SELECT to determine if an UPDATE is actually required.


Does one of these do what you want?

eek Annotations! See:
http://www.hibernate.org/hib_docs/annot ... ty-hibspec


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 29, 2008 7:15 am 
Beginner
Beginner

Joined: Thu Jun 14, 2007 4:33 am
Posts: 39
hei thx! that one will help me out!

//edit: @gonzao_diaz
no i want to read that field in any case but dont want to write it in this special case. maybe two different mappings of this class could do the job..


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 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.