Hibernate Save上的StackOverflowError

时间:2013-07-02 17:01:52

标签: java hibernate one-to-many composite-key stack-overflow

我有一个Student表,其中一个自动生成的id作为主键,一个到多个映射到Phone表。

My Phone表有一个复合主键PhonePK,其中包含电话号码和Student表的外键ID。

如果我只是做student.setPhones而不是做phonepk.setStudent,它抱怨 id不能为空。所以我正在设置student.setPhones和phonePk.setStudent。但是现在我在toString上遇到了stackoverflow错误。

我真的不喜欢在两个方面设置它,但不知道如何绕过id不能为null错误。我一直在问很多人,但他们无能为力。有人可以看一下吗?

Student.java

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

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;

@Entity
@SuppressWarnings("serial")
public class Student implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;

private String fName;

private String lName;

private String mName;

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "id")
private Set<Phone> phones;

/**
 * @return the fName
 */
public String getfName() {
    return fName;
}

/**
 * @return the id
 */
public int getId() {
    return id;
}

/**
 * @return the lName
 */
public String getlName() {
    return lName;
}

/**
 * @return the mName
 */
public String getmName() {
    return mName;
}

/**
 * @return the phones
 */
public Set<Phone> getPhones() {
    return phones;
}

/**
 * @param fName
 *            the fName to set
 */
public void setfName(final String fName) {
    this.fName = fName;
}

/**
 * @param id
 *            the id to set
 */
public void setId(final int id) {
    this.id = id;
}

/**
 * @param lName
 *            the lName to set
 */
public void setlName(final String lName) {
    this.lName = lName;
}

/**
 * @param mName
 *            the mName to set
 */
public void setmName(final String mName) {
    this.mName = mName;
}

/**
 * @param phones
 *            the phones to set
 */
public void setPhones(final Set<Phone> phones) {
    this.phones = phones;
}

/**
 * {@inheritDoc}
 */
@Override
public String toString() {
    return String.format("Student [id=%s, fname=%s, lname=%s, mname=%s, phones=%s]",      
id,
        fName, lName, mName, phones);
}

}

Phone.java

import java.io.Serializable;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

@Entity
@SuppressWarnings("serial")
public class Phone implements Serializable {

@EmbeddedId
private PhonePK PK;

private String color;

/**
 * @return the color
 */
public String getColor() {
    return color;
}

public PhonePK getPK() {
    return PK;
}

/**
 * @param color
 *            the color to set
 */
public void setColor(final String color) {
    this.color = color;
}

public void setPK(final PhonePK pK) {
    PK = pK;
}

/**
 * {@inheritDoc}
 */
@Override
public String toString() {
    return String.format("Phone [PK=%s, color=%s]", PK, color);
}

}

PhonePK.java

import java.io.Serializable;

import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Embeddable
@SuppressWarnings({ "serial" })
public class PhonePK implements Serializable {

@ManyToOne
@JoinColumn(name = "id", insertable = false, updatable = false)
private Student student;

private String phoneNumber;

public String getPhoneNumber() {
    return phoneNumber;
}

public Student getStudent() {
    return student;
}

public void setPhoneNumber(final String phoneNumber) {
    this.phoneNumber = phoneNumber;
}

public void setStudent(final Student student) {
    this.student = student;
}

/**
 * {@inheritDoc}
 */
@Override
public String toString() {
    return String.format("PhonePK [student=%s, phoneNumber=%s]", student, phoneNumber);
}

}

Main.java

import java.util.LinkedHashSet;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class Main {

 public static void main(final String args[]) {

    Configuration configuration = new Configuration();
    Transaction transaction = null;

    configuration.addAnnotatedClass(Student.class);
    configuration.addAnnotatedClass(Phone.class);
    configuration.configure("hibernate.cfg.xml");
    SessionFactory sessionFactory = configuration.buildSessionFactory();
    Session session = sessionFactory.openSession();

    Student student = new Student();
    student.setfName("Bob");
    student.setlName("Buster");

    Set<Phone> phones = new LinkedHashSet<Phone>();
    Phone phone = new Phone();
    phone.setColor("Black");
    PhonePK phonePK = new PhonePK();
    phonePK.setPhoneNumber("1111111111");
    phonePK.setStudent(student); // Do not do this? But won't work (id cannot be null  
    error) if
                                 // commented out??
    phone.setPK(phonePK);
    phones.add(phone);

    student.setPhones(phones);

    try {
        transaction = session.beginTransaction();
        System.out.println(student.toString()); // stackoverflow error!
        session.save(student);
        transaction.commit();
    } catch (HibernateException e) {
        transaction.rollback();
        e.printStackTrace();
    } finally {
        session.close();
    }

}
}

1 个答案:

答案 0 :(得分:2)

这是因为您定义了toString()方法的方式

学生toString()正在调用Phone toString(),它正在调用PhonePK的toString(),后者又调用学生的toString() ...导致无限循环。


让我们看看它是如何发生的详细方式

在学生toString()中,因为其中包含phones个实例变量。它会遍历每部手机并拨打电话toString()

public String toString() {
    return String.format("Student [id=%s, fname=%s, lname=%s, mname=%s, phones=%s]",      
id,
        fName, lName, mName, phones);
}



在电话toString()中,由于其中包含PK个实例变量。它将调用PhonePK toString()

public String toString() {
    return String.format("Phone [PK=%s, color=%s]", PK, color);
}



在PhonePK toString()中,由于其中包含phoneNumber个实例变量。它将调用电话toString()

public String toString() {
    return String.format("PhonePK [student=%s, phoneNumber=%s]", student, phoneNumber);
}