Hibernate supprimer la requête

Lorsque j'essaie de supprimer une entrée d'une base de données, en utilisant

session.delete(object) 

Alors je peux ce qui suit:

1) si la ligne est présente dans DB, deux requêtes SQL sont exécutées: une select puis une delete

2) si la ligne n'est pas présente dans la base de données, seule la requête select est exécutée

Mais encore une fois ce n'est pas le cas pour update. Indépendamment de la présence D'une ligne de base de données, seule la requête de mise à jour est exécutée.

Faites-moi savoir pourquoi ce genre de comportement pour l'opération de suppression. N'est-ce pas un problème de performance puisque deux requêtes sont touchées plutôt qu'une?

Modifier:

J'utilise hibernate 3.2.5

Exemple de code:

SessionFactory sessionFactory = new Configuration().configure("student.cfg.xml").buildSessionFactory();
    Session session = sessionFactory.openSession();
    Student student = new Student();
    student.setFirstName("AAA");
    student.setLastName("BBB");
    student.setCity("CCC");
    student.setState("DDD");
    student.setCountry("EEE");
    student.setId("FFF");
    session.delete(student);
    session.flush();
            session.close();

Cfg.xml

<property name="hibernate.connection.username">system</property>
    <property name="hibernate.connection.password">XXX</property>
    <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
    <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521/orcl</property>      
    <property name="hibernate.jdbc.batch_size">30</property>
    <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
    <property name="hibernate.cache.use_query_cache">false</property>
    <property name="hibernate.cache.use_second_level_cache">false</property>
    <property name="hibernate.connection.release_mode">after_transaction</property>
    <property name="hibernate.connection.autocommit">true</property>
    <property name="hibernate.connection.pool_size">0</property>
    <property name="hibernate.current_session_context_class">thread</property>    
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">update</property>        

Hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.infy.model.Student" table="STUDENT">
    <id name="id" column="ID">
        <generator class="assigned"></generator>
    </id>
    <property name="firstName" type="string" column="FIRSTNAME"></property>
    <property name="lastName" type="string" column="LASTNAME"></property>
    <property name="city" type="string" column="CITY"></property>
    <property name="state" type="string" column="STATE"></property>
    <property name="country" type="string" column="COUNTRY"></property>        
</class>

31
demandé sur user182944 2012-11-03 19:35:37

4 réponses

La raison en est que pour supprimer un objet, Hibernate nécessite que l'objet soit dans un état persistant. Ainsi, Hibernate récupère d'abord l'objet (SELECT), puis le supprime (DELETE).

Pourquoi Hibernate doit récupérer l'objet en premier? La raison en est que les intercepteurs Hibernate peuvent être activés ( http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/events.html), et l'objet doit être passé à travers ces intercepteurs pour terminer son cycle de vie. Si les lignes sont supprimées directement dans la base de données, l'intercepteur ne fonctionne pas.

D'autre part, il est possible de supprimer des entités dans une seule instruction SQL DELETE en utilisant des opérations en bloc:

Query q = session.createQuery("delete Entity where id = X");
q.executeUpdate();
63
répondu Diego Pino 2012-11-05 21:50:34

Pour comprendre ce comportement particulier de l'hibernation, il est important de comprendre quelques concepts d'hibernation -

États De L'Objet Hibernate

Transitoire-un objet est en état transitoire s'il a été instancié et n'est toujours pas associé à une session Hibernate.

Persistant - une instance persistante a une représentation dans le base de données et une valeur d'identifiant. Il pourrait avoir juste été enregistré ou chargé, cependant, il est par définition dans le cadre d'une Session.

Détaché - une instance détachée est un objet qui a été persistant, mais sa Session est close.

Http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/objectstate.html#objectstate-overview

Opération Write-Behind

La prochaine chose à comprendre est 'Transaction Write behind'. Lorsque des objets attachés à une session hibernate sont modifiés ils ne le sont pas immédiatement propagé à la base de données. Hibernate le fait pour au moins deux raisons différentes.

  • pour effectuer des insertions et des mises à jour par lots.
  • pour propager uniquement la dernière modification. Si un objet est mis à jour plus d'une fois, il ne déclenche toujours qu'une seule instruction update.

Http://learningviacode.blogspot.com/2012/02/write-behind-technique-in-hibernate.html

Cache De Premier Niveau

Hibernate a quelque chose appelé 'Cache De Premier Niveau'. Chaque fois que vous passez un objet à save(), update() ou saveOrUpdate(), et chaque fois que vous récupérez un objet en utilisant load(), get(), list(), iterate() ou scroll(), cet objet est ajouté au cache interne de la Session. C'est là qu'il suit les modifications apportées à divers objets.

Intercepteurs Hibernate et écouteurs du cycle de vie des objets-

L'interface D'intercepteur et les rappels d'écouteur de la session à l'application permettent à l'application d'inspecter et / ou de manipuler propriétés d'un objet persistant avant qu'il ne soit enregistré, mis à jour, supprimé ou chargé. http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/listeners.html#d0e3069


Cette section a été mise à jour

En Cascade

Hibernate permet aux applications de définir des relations en cascade entre les associations. Par exemple, l'association 'cascade-delete' de parent à enfant entraîne la suppression de tous les enfants lorsqu'un parent est supprimé.

Alors, pourquoi sont-ils importants.

Pour pouvoir effectuer une écriture de transaction, pour pouvoir suivre plusieurs modifications d'objets (graphiques d'objets) et pour pouvoir exécuter des rappels de cycle de vie, hibernate doit savoir si l'objet est transient/detached et il doit avoir l'objet dans son cache de premier niveau avant d'apporter des modifications à l'objet sous-jacent et aux relations associées.

C'est pourquoi hibernate (parfois) émet un 'SELECT' déclaration de charger l'objet (si il n'est pas déjà chargé) dans son cache de premier niveau avant d'y apporter des modifications.

Pourquoi hibernate émet-il l'instruction 'SELECT' seulement parfois?

Hibernate émet une instruction 'SELECT' pour déterminer l'état dans lequel se trouve l'objet. Si l'instruction select retourne un objet, l'objet est dans detached état et si elle ne renvoie pas à un objet, l'objet est dans transient état.

Pour en Venir à votre scénario -

Supprimer - La 'Delete' a émis une instruction SELECT car hibernate doit savoir si l'objet existe ou non dans la base de données. Si l'objet existe dans la base de données, hibernate le considère comme detached, puis l'attache à nouveau à la session et traite le cycle de vie de suppression.

Update - puisque vous appelez explicitement 'Update' au lieu de 'SaveOrUpdate', hibernate suppose aveuglément que l'objet est dans l'état detached, attache de nouveau l'objet donné au cache de premier niveau de la session et traite la mise à jour cycle de vie. S'il s'avère que l'objet n'existe pas dans la base de données contrairement à l'hypothèse d'hibernate, une exception est levée lorsque la session est vidée.

SaveOrUpdate - Si vous appelez 'SaveOrUpdate', hibernate a à déterminer l'état de l'objet, de sorte qu'il utilise une instruction SELECT pour déterminer si l'objet est dans Transient/Detached état. Si l'objet est dans transient état, il traite le 'insert' cycle de vie et si l'objet est dans detached état, il traite le 'Update' cycle de vie.

20
répondu Sashi 2016-08-08 15:31:17

Je ne suis pas sûr mais:

  • Si vous appelez la méthode delete avec un objet non transitoire, cela signifie d'abord récupéré l'objet de la base de données. Il est donc normal de voir une instruction select. Peut-être à la fin vous voyez 2 Sélectionner + 1 Supprimer?

  • Si vous appelez la méthode delete avec un objet transitoire, il est possible que vous ayez un cascade="delete" ou quelque chose de similaire qui nécessite de récupérer d'abord l'objet afin que des "actions imbriquées" puissent être effectuées si c'est le cas requis.


Modifier: Appeler delete() avec une instance transitoire signifie faire quelque chose comme ça:

MyEntity entity = new MyEntity();
entity.setId(1234);
session.delete(entity);

Cela supprimera la ligne avec l'id 1234, même si l'objet est un simple pojo non récupéré par Hibernate, pas présent dans son cache de session, pas géré du tout par Hibernate.

Si vous avez une association d'entités, Hibernate doit probablement récupérer l'entité complète afin qu'elle sache si la suppression doit être cascadée vers les entités associées.

3
répondu Sebastien Lorber 2012-11-04 14:41:46

Au lieu d'utiliser

Session.supprimer(objet)

Utiliser

getHibernateTemplate().delete(object)

Au lieu de select requête et également pour delete utiliser getHibernateTemplate()

Dans select requête, vous devez utiliser DetachedCriteria ou Criteria

Exemple de requête select

List<foo> fooList = new ArrayList<foo>();
DetachedCriteria queryCriteria = DetachedCriteria.forClass(foo.class);
queryCriteria.add(Restrictions.eq("Column_name",restriction));
fooList = getHibernateTemplate().findByCriteria(queryCriteria);

En hibernate éviter l'utilisation de la session, ici Je ne suis pas sûr mais le problème se produit juste à cause de l'utilisation de la session

1
répondu Jubin Patel 2012-11-09 09:49:15