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.  [ 2 posts ] 
Author Message
 Post subject: Unexplained delete on jointable during add
PostPosted: Thu Apr 14, 2011 8:31 am 
Newbie

Joined: Thu Nov 05, 2009 11:31 am
Posts: 8
I am using Hibernate as the JPA provider in a NetBeans 6.9.1 application. I don't know what hibernate ships with 6.9.1.

I have 2 entities, slots and documents where in a given time slot (1 hour typically) there will be multiple documents processed. Furthermore, given a document it may appear in multiple time slots.

What I am seeing are periodic deletes against the join table. In no case am I instigating a delete or remove. Since the join table is dynamically created the rows do not have a version for MVCC and the delete forces a table lock. This, in turn, slows the other threads down and occasionally triggers a 1205, timeout waiting for lock. Consequently, there are 1 1/2 problems here, performing the delete at all is one, dying while waiting for the table lock is another. The underlying db is mysql with the innodb engine (5.1).
Code:
package analytics.models;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;

import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;

/**
*
* @author walt
*/
@Entity
@Table(name = "Documents", catalog = "Analytics")
@NamedQueries({
    @NamedQuery(name = "Document.findAll", query = "SELECT a FROM Document a"),
    @NamedQuery(name = "Document.findById", query = "SELECT a FROM Document a WHERE a.docKey.docid = :id"),
    @NamedQuery(name = "Document.findByIdDocType", query = "SELECT a FROM Document a WHERE a.docKey.docid = :id and a.docKey.type = :doc")})
public class Document implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    @Basic(optional=false)
    @Column(name="id")
    private Integer id;
    @Basic(optional = false)
    @Column(name = "docKey")
    private DocumentKey docKey;
    @Basic(optional = false)
    @Column(name = "inserts")
    private int inserts;
    @Basic(optional = false)
    @Column(name = "deletes")
    private int deletes;


    @ManyToMany(fetch=FetchType.LAZY)
    @JoinTable(name = "slot_doc",
        joinColumns = {
        @JoinColumn(name="doc_id")
        },
        inverseJoinColumns = {
        @JoinColumn(name="slot_id")
        }
    )

    private Collection<ActivityTimeSlot> times;
    @Basic(optional = false)
    @Version
    @Column(name = "version")
    private int version;


    public Document() {
       times = new ArrayList<ActivityTimeSlot>(0);
        inserts = 0;
        deletes = 0;
    }

    @Override
    public int hashCode() {
        return docKey.hashCode();
    }

    @Override
    public boolean equals(Object object) {
        return docKey.equals(object);
    }

    public int getDeletes() {
        return deletes;
    }

    public void setDeletes(int deletes) {
        this.deletes = deletes;
    }

    public void incrDeletes() {
        deletes++;
    }

    public void incrInserts() {
        inserts++;
    }
    public int getInserts() {
        return inserts;
    }

    public void setInserts(int inserts) {
        this.inserts = inserts;
    }
   
    public Pair getPair() {
       return new Pair(inserts, deletes);
    }

    @Override
    public String toString() {
        return docKey.toString();
    }


    public Collection<ActivityTimeSlot> getTimes() {
            return times;
    }
    public void setTimes(Collection<ActivityTimeSlot>times) {
            this.times = times;
    }

    public DocumentKey getDocKey() {
        return docKey;
    }

    public void setDocKey(DocumentKey docKey) {
        this.docKey = docKey;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void addSlot(ActivityTimeSlot slot) {
        slot.getDocuments().add(this);
        times.add(slot);
    }
}


Code:
package analytics.models;

import java.io.Serializable;
import java.util.ArrayList;
import javax.persistence.Entity;
import javax.persistence.Id;

import java.util.Collection;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;

/**
*
* @author walt
*/
@Entity
@Table(name = "ActivityTimeSlot", catalog = "Analytics")
@NamedQueries({
    @NamedQuery(name = "ATS.findAll", query = "SELECT a FROM ActivityTimeSlot a"),
    @NamedQuery(name = "ATS.findById", query = "SELECT a FROM ActivityTimeSlot a WHERE a.slotKey.slotDate = :date"),
    @NamedQuery(name = "ATS.findMaxDateByEngineDocCnty", query = "SELECT max(a.slotKey.slotDate) FROM ActivityTimeSlot a where a.slotKey.engine= :engine and a.slotKey.docType = :docType and a.slotKey.language = :country"),
    @NamedQuery(name = "ATS.findByDateEngineLangDocType", query = "SELECT a FROM ActivityTimeSlot a WHERE a.slotKey.slotDate = :date and a.slotKey.engine = :engine and a.slotKey.language = :country and a.slotKey.docType = :docType")})
public class ActivityTimeSlot implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    @Basic(optional=false)
    @Column(name="id")
    private Integer id;
    @Basic(optional = false)
    @Column(name = "slotKey")
    private ActivityTimeSlotKey slotKey;

    @Basic(optional = false)
    @Column(name = "slotHour")
    private int slotHour;
    @Basic(optional = false)
    @Column(name = "inserts")
    private int inserts;
    @Basic(optional = false)
    @Column(name = "deletes")
    private int deletes;
    @Basic(optional = false)
    @Column(name = "active")
    private int active;
    @ManyToMany(fetch=FetchType.LAZY, mappedBy="times")
    @JoinTable(name = "slot_doc",
        joinColumns = {
        @JoinColumn(name="slot_id")
        },
        inverseJoinColumns = {
        @JoinColumn(name="doc_id")
        }
    )
    private Collection<Document> documents;
    @Basic(optional = false)
    @Version
    @Column(name = "version")
    private int version;
   
   
    public ActivityTimeSlot() {
        documents = new ArrayList<Document>(0);
    }

    public Collection<Document> getDocuments() {
            return documents;
    }

    public void setDocuments(Collection<Document>documents) {
            this.documents = documents;
    }

    public int getHour() {
        return slotHour;
    }

    public void setHour(int slotHour) {
        this.slotHour = slotHour;
    }

     @Override
    public int hashCode() {
        int hash = 0;
        hash += (slotKey != null ? slotKey.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof ActivityTimeSlot)) {
            return false;
        }
        ActivityTimeSlot other = (ActivityTimeSlot) object;
        if ((this.slotKey == null && other.slotKey != null) || (this.slotKey != null && !this.slotKey.equals(other.slotKey))) {
            return false;
        }
        return true;
    }

    public int getDeletes() {
        return deletes;
    }

    public void setDeletes(int deletes) {
        this.deletes = deletes;
    }


    public int getInserts() {
        return inserts;
    }

    public void setInserts(int inserts) {
        this.inserts = inserts;
    }
   
    public Pair getPair() {
       return new Pair(inserts, deletes);
    }

    @Override
    public String toString() {
        return slotKey.toString();
    }

   public int getActive() {
      return active;
   }

   public void setActive(int active) {
            this.active = active;
   }

        public void incrInserts() {
            inserts++;
        }

        public void incrDeletes() {
            deletes++;
        }

    public int getSlotHour() {
        return slotHour;
    }

    public void setSlotHour(int slotHour) {
        this.slotHour = slotHour;
    }

    public ActivityTimeSlotKey getSlotKey() {
        return slotKey;
    }

    public void setSlotKey(ActivityTimeSlotKey slotKey) {
        this.slotKey = slotKey;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void addDocument(Document doc) {
        if (doc != null) {
            doc.getTimes().add(this);
            documents.add(doc);
        }
    }
}


The salient section of code that populates the tables

Code:
            temComposites.getTransaction().begin();
            for (Updeventlog event : eventsList) {
                currentEvent = event.getUpdEventLogEventId();
                String tmp = formatter.format(event.getUpdEventLogEpoch());
                Date epoch = null;
                try {
                    epoch = formatter.parse(tmp);
                } catch (ParseException ex) {
                    Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, null, ex);
                }
                queryTimeSlot.setParameter("date", epoch);
                cal.setTime(epoch);
                Tuple tuple = holding.get(epoch);
                if (tuple == null) {
                    tuple = new Tuple();
                    holding.put(epoch, tuple);
                }
                /*
                 * this instance won't change that frequently so it is more
                 * efficient to check to see if the current instance in this
                 * LUW and hour is correct
                 */
                if (!(ats != null && ats.getSlotKey().getSlotDate().getTime() == epoch.getTime())) {
                    try {
                        ats = (ActivityTimeSlot) queryTimeSlot.getSingleResult();
                        insertATS = false;
                    } catch (Exception e) {
                        insertATS = true;
                        ats = new ActivityTimeSlot();
                        atsk = new ActivityTimeSlotKey();
                        atsk.setSlotDate(epoch);
                        atsk.setLanguage(language);
                        atsk.setDocType(docType);
                        atsk.setEngine(engine);
                        ats.setHour(cal.get(Calendar.HOUR_OF_DAY));
                        ats.setSlotKey(atsk);
                    }

                }
                if (processMM) {
                    queryDocument.setParameter("id", event.getUpdEventLogDocId());
                    try {
                        doc = (Document) queryDocument.getSingleResult();
                        insertDoc = false;
                    } catch (Exception e) {
                        doc = new Document();
                        docKey = new DocumentKey();
                        docKey.setDocid(event.getUpdEventLogDocId());
                        docKey.setType(docType);
                        doc.setDocKey(docKey);
                        insertDoc = true;
                    }
                }
                try {
                    ats.addDocument(doc);
                } catch (Exception e) {
                    Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, "{0}", e);
                    System.exit(-1);
                }
                if (event.getUpdEventLogMisc().indexOf("=D") != -1) {
                    if (processMM) {
                        doc.incrDeletes();
                    }
                    if (interimMap.containsKey(event.getUpdEventLogDocId()) == true) {
                        tuple.incrDeletes();
                        ats.incrDeletes();
                        interimMap.remove(event.getUpdEventLogDocId());
                    }
                } else {
                    if (processMM) {
                        doc.incrInserts();
                    }
                    if (interimMap.containsKey(event.getUpdEventLogDocId()) == false) {
                        Inter interim = new Inter();
                        interim.date = epoch;
                        interim.docid = event.getUpdEventLogDocId();
                        interimMap.put(interim.docid, interim);
                        ats.incrInserts();
                        tuple.incrInserts();
                    }
                }
                if (insertATS) {
                    try {
                        temComposites.persist(ats);
                    } catch (PersistenceException e) {
                        ActivityTimeSlot merge = temComposites.merge(ats);
                    }
                }
                if (processMM && insertDoc) {
                    try {
                        temComposites.persist(doc);
                    } catch (PersistenceException e) {
                        temComposites.merge(doc);
                    }
                }
            }
            temComposites.getTransaction().commit();


I see no place there where I would be triggering a delete action. The goal of this code is to initially populate the tables/

If someone would explain what is triggering the delete on the join table I would appreciate it. My goal is to negate whatever reason Hibernate thinks the section of the join table must be removed. When I did catch the sql it was in the order of 'delete from slot_doc where slot_id = 1; Which means it is removing the entire first time slot.

Thanks.


Top
 Profile  
 
 Post subject: Re: Unexplained delete on jointable during add
PostPosted: Mon Apr 18, 2011 1:52 pm 
Newbie

Joined: Thu Nov 05, 2009 11:31 am
Posts: 8
bump?


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