Help

Controls

PermLinkWikiLink

Built with Seam

You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.

Forum: Seam Users Forum ListTopic List
05. Aug 2008, 00:32 CET | Link

I'm sure this must be simple but I cannot see what I am doing wrong. I have a program that read in files and creates records in the database. Its about storing calls and telephone numbers. A call has 2 numbers it must relate to. I read in the file and create the telephone number classes I create a call and set the telephone numbers. then I call persist()

This went wrong because 2 calls can be made to the same phone number resulting in a unique constraint voilation . so far I can understand. However, i cannot find a solution for this situation.

First I tried finding the telephone numbers first with em.find() and persisting them when not found. The inserting them to the call and calling persist() on the call(). Calling persist() on the call results in a the same unique constraint voilation.

The I used merge() instead of persist() on the new telephonenumbers. That results in a deadlock?!?

I have been banging my head on this for far too long. I guess it must be simple but I cant see it right now. How should I do this?

Does it matter that there are multiple thread concurrently adding calls and telephone numbers to the database?


@Entity
@Name("telephonenumber")
public class TelephoneNumber implemeents serializable {
    private String all;
    private String country;
    private String number;


    @Id
    @Column(length=30)
    public String getAll() {
        return all;
    }

    // All other getters and setters
}


@Entity
@Name("call")
Public class Call implements Serializable {
    private long id;
    private TelephoneNumber from;
    private TelephoneNumber to;
    private Date start;

    @Id
    public void setId(Long callId) {
        return id;
    }

    @ManyToOne
    public TelephoneNumber getFrom() {
        return from;
    }

    @ManyToOne
    public TelephoneNumber getTo() {
        return to;
    }
    
    // All other getters and setters
}

6 Replies:
05. Aug 2008, 08:06 CET | Link

Well, you don't have any @JoinColumn on the many to one relationships that's for sure. But that may not be your only problem. Serializable needs to have a capital S on your TelephoneNumber entity, and implements is misspelled on your TelephoneNumber entity too. Can you clean up your code, try it, and post again?

 
Dan Hinojosa Seam :: Groovy :: Swing Developer/Consultant/Instructor Albuquerque, NM
06. Aug 2008, 16:49 CET | Link

Hello, Im behind the devlopment machine now so I can cut and paste code instead of typing over.

Telephone Number:


package nl.unc.mmt.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

import nl.unc.mmt.util.TelephoneNumberType;

import org.jboss.seam.annotations.Name;

/**
 * Utility class for telephone numbers.
 * @author Hugo Pragt All rights reserverd
 *
 */
@Entity
@Name("telephonenumber")
@NamedQueries({
    @NamedQuery(name="telephonenumber.findByNumber", query="select nr from TelephoneNumber nr where nr.number =:number")
})
public class TelephoneNumber implements Serializable {

    private static final long serialVersionUID = -1134570748748658402L;
    private String cli;
    private String cps;
    private String countrycode;
    private String number;
    private TelephoneNumberType type = TelephoneNumberType.UNKNOWN;
    private Short category;
    
    /**
     * whether this telephone number is a national, international etc number.
     * defaults to UNKNOWN
     * @return the type of the number
     * @see TelephoneNumberType
     */
    public TelephoneNumberType getType() {
        return type;
    }

    /**
     * @param type the type of the number
     * @see TelephoneNumberType
     */
    public void setType(TelephoneNumberType type) {
        this.type = type;
    }

    /**
     * @return the category of the number
     */
    public Short getCategory() {
        return category;
    }

    /**
     * @param category the category of the number to set
     */
    public void setCategory(Short category) {
        this.category = category;
    }

    /**
     * @return all digits of telephone number
     */
    @Id
    @Column(length=24)
    public String getCli() {
        return cli;
    }

    /**
     * @param digits id to set
     * @see #setCps(String)
     * @see #setCountrycode(String)
     * @see #setNumber(String)
     */
    public void setCli(String digits) {
        cli = digits;
    }

    /**
     * @return the Carrier PreSelect code 
     */
    public String getCps() {
        return cps;
    }

    /**
     * @param cps the Carrier PreSelect code to set
     */
    public void setCps(String cps) {
        this.cps = cps;
    }
    /**
     * @return the country code (without prefix zero's)
     */
    public String getCountrycode() {
        return countrycode;
    }

    /**
     * @param countrycode the country code to set
     */
    public void setCountrycode(String countrycode) {
        this.countrycode = countrycode;
    }

    /**
     * @return the number without CPS or country code
     */
    public String getNumber() {
        return number;
    }

    /**
     * @param number the number without CPS or country code
     */
    public void setNumber(String number) {
        this.number = number;
    }
    
    /**
     * outputs correctly formatted telephone number.
     * non-filled fields are ignored resulting in an ampty string for a
     * non-initialised telephone number. 
     * @return CPS + CountryCode + Number
     */
    @Override()
    public String toString() {
        StringBuffer result = new StringBuffer();
        if (cps != null) {
            result.append(cps);
        }
        if (countrycode != null) {
            result.append("00");
            result.append(countrycode);
        }
        if (number != null) {
            result.append(number);
        }
        return result.toString();
    }
    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        } if (! (obj instanceof TelephoneNumber)) {
            return false;
        }
        TelephoneNumber other = (TelephoneNumber)obj;
        if (cli == null) {
            return other.cli == null;
        }
        return cli.equals(other.cli);
    }

    /**
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        if (cli == null) {
            return 0;
        }
        return cli.hashCode();
    }

}

Call

I have removed some of the 80+ fields in this class


package nl.unc.mmt.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

import nl.unc.mmt.util.LDCStatus;
import nl.unc.mmt.util.ericsson.AxeCDR;

import org.jboss.seam.annotations.Name;

/**
 * A CDR read directly from data source by the CDR creator.
 * @author Hugo Pragt. All rights reserved
 * 	
 */
@Entity
@Name("cdr")
public class Cdr implements Serializable {

    private static final long serialVersionUID = 4003988589514561342L;

        private Long id;

	/**
	 * true = this is a (fake) test CDR
	 * default = false
	 */
	private boolean test = false;

	private TelephoneNumber anumber;
	
	private TelephoneNumber aNumber_UserPresented;

	private TelephoneNumber bnumber;

	private TelephoneNumber bNumber_AfterAnalyses;

	private TelephoneNumber xnumber;

	private Date start;

	private long duration;

	private boolean beingProcessed = false;

	@Id
	public Long getId() {
		return id;
	}

	public void setId(Long cdrId) {
		this.id = cdrId;
	}
	// http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html
	@Column(columnDefinition="tinyint", length=4)
	public boolean isTest() {
		return test;
	}

	public void setTest(boolean isTest) {
		this.test = isTest;
	}

	// http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html
	@Column(columnDefinition="tinyint", length=4)
	public boolean isRedirected() {
		return redirected;
	}

//	@ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
	@ManyToOne
	public TelephoneNumber getAnumber() {
		return anumber;
	}

	public void setAnumber(TelephoneNumber number) {
		anumber = number;
	}

//    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
	@ManyToOne
	public TelephoneNumber getANumber_UserPresented() {
		return aNumber_UserPresented;
	}

	public void setANumber_UserPresented(TelephoneNumber number) {
		aNumber_UserPresented = number;
	}

//    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
	@ManyToOne
	public TelephoneNumber getBnumber() {
		return bnumber;
	}

	public void setBnumber(TelephoneNumber number) {
		bnumber = number;
	}

//    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
	@ManyToOne
	public TelephoneNumber getBNumber_AfterAnalyses() {
		return bNumber_AfterAnalyses;
	}

	public void setBNumber_AfterAnalyses(TelephoneNumber number_AfterAnalyses) {
		bNumber_AfterAnalyses = number_AfterAnalyses;
	}

//    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
	@ManyToOne
	public TelephoneNumber getXnumber() {
		return xnumber;
	}

	public void setXnumber(TelephoneNumber number) {
		xnumber = number;
	}

	public Date getStart() {
		return start;
	}

	public void setStart(Date start) {
		this.start = start;
	}

	/**
	 * 
	 * @return chargeable duration in milliseconds
	 */
	public long getDuration() {
		return duration;
	}

	/**
	 * 
	 * @param duration chargeable duration in milliseconds
	 */
	public void setDuration(long duration) {
		this.duration = duration;
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer(Cdr.class.getSimpleName());
		sb.append("(id=");
		sb.append(id);
		sb.append(",Anumber=");
		sb.append(anumber);
		sb.append(",Bnumber=");
		sb.append(bnumber);
		sb.append(",duration=");
		sb.append(duration);
		sb.append(')');
		return sb.toString();
	}


    /**
     * @return the beingProcessed
     */
    @Column(columnDefinition="tinyint", length=4)
    public boolean isBeingProcessed() {
        return beingProcessed;
    }

    /**
     * @param beingProcessed the beingProcessed to set
     */
    public void setBeingProcessed(boolean beingProcessed) {
        this.beingProcessed = beingProcessed;
    }

}

call writing method


	private CorruptedCdr handleRecord(String record) {

        String[] values = null;
        if (record != null) {
            values = record.split(",");
        }
        Cdr cdr = create(values);
        cdr.setTest(true); // TODO remove setTest(true)
        Cdr cdr2 = em.find(Cdr.class, cdr.getId());
        if (cdr2 == null) {
            em.persist(cdr); // changed from merge to persist to avoid double PK's
        } else {
            log.warn("Overwriting {0}!", cdr2);
            em.merge(cdr);
        }
          log.debug("persisting new cdr {0}", cdr);
    }
    try {
        em.flush(); // TODO remove?
    } catch(PersistenceException e) {
        log.warn("while storing {0} in database: {1}", cdr, e);
        throw e;
    }
        return null;

Error log


2008-08-04 23:54:15,171 INFO  [STDOUT] Hibernate: 
    insert 
    into
        TelephoneNumber
        (type, number, category, cps, countrycode, cli) 
    values
        (?, ?, ?, ?, ?, ?)
2008-08-04 23:54:15,171 WARN  [org.hibernate.util.JDBCExceptionReporter] SQL Error: 1213, SQLState: 40001
2008-08-04 23:54:15,187 ERROR [org.hibernate.util.JDBCExceptionReporter] Deadlock found when trying to get lock; try restarting transaction
06. Aug 2008, 20:22 CET | Link
Arbi Sookazian

are you running load tests or accessing the EntityManager in a servlet (not thread safe)?

you should post this on the hibernate forum.

Rating:  *
06. Aug 2008, 20:38 CET | Link

I'm using the entity manager from the ejb3 container (Jboss4)

The reason I'm posting here is that the only thing I can come up with to explain the error is the transaction demarcation

Is there anything obviously wrong with my code which I'm just overlooking?

H

ps. Thanks for looking!

07. Aug 2008, 06:55 CET | Link

I bet your mysql log file will hold many answers for you.

 
Dan Hinojosa Seam :: Groovy :: Swing Developer/Consultant/Instructor Albuquerque, NM
Rating:  * *
17. Aug 2008, 12:49 CET | Link

solved. The answer was to store the input in the database and from there handle the data. End of deadlocks .
Hurray!