遇到一个奇怪问题,数据已经保存至数据库,但entityManager.find却取不到数据,重启tomcat后,entityManager.find又可以取到数据,不知道大家是否遇到过?
1.mysql数据库,表如下:CREATE TABLE `school` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
);CREATE TABLE `course` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ;CREATE TABLE `student` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL DEFAULT '',
  `school_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
);CREATE TABLE `student_course` (
  `stu_id` int(10) NOT NULL,
  `cos_id` int(10) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `stu_id` (`stu_id`,`cos_id`),
  KEY `student_course_fk_cosId` (`cos_id`),
  CONSTRAINT `student_course_fk_stuId` FOREIGN KEY (`stu_id`) REFERENCES `student` (`id`),
  CONSTRAINT `student_course_fk_cosId` FOREIGN KEY (`cos_id`) REFERENCES `course` (`id`)
);
2.Java代码如下
采用spring 3 + struts2 + openjpa框架, Dao通过spring注入@Component
public class TestDao extends ActionSupport {
private static final long serialVersionUID = 1L;

@Resource(name="studentDao")
private IBaseDao<Student> stuDao;

@Resource(name="schoolDao")
private IBaseDao<School> schDao;

@Resource(name="courseDao")
private IBaseDao<Course> cosDao;

@Resource(name="studentCourseDao")
private IBaseDao<StudentCourse> stuCosDao;

@Override
public String execute() {
System.out.println("Called!!");
testSchCRUD();
//testQuery();
return SUCCESS;
}

public void testQuery() {
Student stu = stuDao.findByName("stu-1");
showStudent(stu);
}

public void testSchCRUD() {

// add school 
School sch = new School();
sch.setName("school");
schDao.save(sch);

// add courses
Course cos = new Course();
cos.setName("Math");
cosDao.save(cos);
cos = new Course();
cos.setName("Computer");
cosDao.save(cos);
cos = new Course();
cos.setName("English");
cosDao.save(cos);

// add students
Student stu = new Student();
stu.setName("stu-1");
stuDao.save(stu);
stu = new Student();
stu.setName("stu-2");
stuDao.save(stu);

// add students to school
School sch = schDao.findByName("school");
Student stu = stuDao.findByName("stu-1");
stu.setSchool(sch);
stuDao.save(stu);
showSchool(schDao.findByName("school"));

// student select courses
stu = stuDao.findByName("stu-1");
Course cos = cosDao.findByName("Math");
StudentCourse stuCos = new StudentCourse();
stuCos.setCourse(cos);
stuCos.setStudent(stu);
stuCosDao.save(stuCos);
showSchool(schDao.findByName("school"));
}

private void showSchool(School sch) {
if (null != sch) {
System.out.println("School Name:" + sch.getName());
System.out.println("Students:\nNo.\tName");
List<Student> stuList = sch.getStudents();
if (null != stuList && stuList.size() > 0) {
int index = 1;
for (Student stuIter : stuList) {
System.out.print(index + "\t");
showStudent(stuIter);
index++;
}
}
} else {
System.out.println("No School Data!!");
}
} private void showStudent(Student stu) {
if (null != stu) {
System.out.println(stu.getName());
int index = 1;
Set<StudentCourse> stuCosSet = stu.getStudentCourses();
if (stuCosSet != null && stuCosSet.size() > 0) {
System.out.println("\tCourses:");
for (StudentCourse stuCos : stuCosSet) {
System.out.printf("\t%d\t%s\n", index, stuCos.getCourse().getName());
index++;
}
}
} else {
System.out.println("No Student Data!!");
}
} public void setSchDao(SchoolDao schDao) {
this.schDao = schDao;
}
public void setStuDao(StudentDao stuDao) {
this.stuDao = stuDao;
} public void setCosDao(IBaseDao<Course> cosDao) {
this.cosDao = cosDao;
} public void setStuCosDao(IBaseDao<StudentCourse> stuCosDao) {
this.stuCosDao = stuCosDao;
}
}
package com.test.dao;
public interface IBaseDao<T> {
int save(T o);
T find(int id);
void remove(int id);
T findByName(String name);
}
@Repository
@Transactional
public class StudentDao implements IBaseDao<Student>{
@PersistenceContext
private EntityManager em;

@Override
public int save(Student stu) {
if (0 == stu.getId()) {
em.persist(stu);
} else {
em.merge(stu);
}
return stu.getId();
}

@Override
public void remove(int id) {
Student stu = em.find(Student.class, id);
if (stu != null) {
em.remove(stu);
}
}

@Override
public Student find(int id) {
Student stu = em.find(Student.class, id);
em.refresh(stu);
return stu;
}

@Override
public Student findByName(String name) {
Query query = em.createQuery("select stu from Student stu where stu.name = ?1");
query.setParameter(1, name);
query.setMaxResults(1);
return (Student) query.getSingleResult();
}
}
@Component
@Transactional
public class StudentCourseDao implements IBaseDao<StudentCourse> { @PersistenceContext
private EntityManager em;

@Override
public int save(StudentCourse o) {
// TODO Auto-generated method stub
if (0 == o.getId()) {
em.persist(o);
} else {
em.merge(o);
}
return o.getId();
} @Override
public StudentCourse find(int id) {
// TODO Auto-generated method stub
return em.find(StudentCourse.class, id);
} @Override
public void remove(int id) {
// TODO Auto-generated method stub
StudentCourse stuCos = em.find(StudentCourse.class, id);
if (stuCos != null) {
em.remove(stuCos);
}
} @Override
public StudentCourse findByName(String name) {
// TODO Auto-generated method stub
return null;
}}
@Repository
@Transactional
public class SchoolDao implements IBaseDao<School>{
@PersistenceContext
private EntityManager em;

@Override
public int save(School school) {
if (0 == school.getId()) {
em.persist(school);
} else {
em.merge(school);
}
return school.getId();
}

@Override
public void remove(int id) {
School sch = em.find(School.class, id);
if (sch != null) {
em.remove(sch);
}
}

@Override
public School find(int id) {
return em.find(School.class, id);
} @Override
public School findByName(String name) {
// TODO Auto-generated method stub
Query query = em.createQuery("select s from School s where s.name = ?1");
query.setParameter(1, name);
query.setMaxResults(1);
return (School) query.getSingleResult();
}
}
@Component
@Transactional
public class CourseDao implements IBaseDao<Course> { @PersistenceContext
private EntityManager em;

@Override
public int save(Course o) {
// TODO Auto-generated method stub
if (0 == o.getId()) {
em.persist(o);
} else {
em.merge(o);
}
return o.getId();
} @Override
public Course find(int id) {
// TODO Auto-generated method stub
return em.find(Course.class, id);
} @Override
public void remove(int id) {
// TODO Auto-generated method stub
Course cos = find(id);
if (null != cos) {
em.remove(cos);
}
}

public Course findByName(String name) {
Query query = em.createQuery("select c from Course c where c.name = ?1");
query.setParameter(1, name);
query.setMaxResults(1);
return (Course) query.getSingleResult();
}
}
@Entity
@Table(name="course")
public class Course implements Serializable {
private static final long serialVersionUID = 1L; @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(unique=true, nullable=false)
private int id; @Column(nullable=false, length=20)
private String name; //bi-directional many-to-one association to StudentCourse
@OneToMany(mappedBy="course", cascade = ALL, fetch = FetchType.EAGER)
private List<StudentCourse> studentCourses; public Course() {
} public int getId() {
return this.id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return this.name;
} public void setName(String name) {
this.name = name;
} public List<StudentCourse> getStudentCourses() {
return this.studentCourses;
} public void setStudentCourses(List<StudentCourse> studentCourses) {
this.studentCourses = studentCourses;
}

public void addStudentCourse(StudentCourse stuCos) {
if (null == this.studentCourses) {
this.studentCourses = new ArrayList<StudentCourse>();
}
this.studentCourses.add(stuCos);
}
}@Entity
@Table(name="school")
public class School implements Serializable {
private static final long serialVersionUID = 1L; @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(unique=true, nullable=false)
private int id; @Column(nullable=false, length=10)
private String name; //bi-directional many-to-one association to Student
@OneToMany(mappedBy="school", cascade = ALL, fetch = FetchType.EAGER)
private List<Student> students; public School() {
} public int getId() {
return this.id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return this.name;
} public void setName(String name) {
this.name = name;
} public List<Student> getStudents() {
return this.students;
} public void setStudents(List<Student> students) {
this.students = students;
}

public void addStudent(Student stu) {
if (null == this.students) {
this.students = new ArrayList<Student>();
}
this.students.add(stu);
}
}TestDao中testSchCRUD(),当给课程及学生建立联系后,通过find找不到相应的数据;如果关系的建立是通过One端类Student进行,那么find也可以找到;如果将tomcat重启,find也可以找到数据。已经被这个问题困扰很久了,急求各位找出原因。多谢!!openjpatransactionalspringmysql

解决方案 »

  1.   


    所有Dao类定义的开头,都有@Transactional标记,应该内部所有函数都是在一个事务内的吧?顺便问一下,CascadeType.DETACH 是什么作用?当在StudentCourse中增加这个级联时,find就可以取到数据了。@Entity
    @Table(name="student_course")
    public class StudentCourse implements Serializable {
    private static final long serialVersionUID = 1L; @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(unique=true, nullable=false)
    private int id; //bi-directional many-to-one association to Course
    @ManyToOne(cascade = {REFRESH, MERGE, PERSIST})
    @JoinColumn(name="cos_id", nullable=false)
    private Course course; //bi-directional many-to-one association to Student
    @ManyToOne(cascade = {REFRESH, MERGE, PERSIST, DETACH})
    @JoinColumn(name="stu_id", nullable=false)
    private Student student; public StudentCourse() {
    } public int getId() {
    return this.id;
    } public void setId(int id) {
    this.id = id;
    } public Course getCourse() {
    return this.course;
    } public void setCourse(Course course) {
    this.course = course;
    } public Student getStudent() {
    return this.student;
    } public void setStudent(Student student) {
    this.student = student;
    } @Override
    public boolean equals(Object obj) {
    if (!(obj instanceof StudentCourse)) {
    return false;
    }
    if (obj == this) {
    return true;
    }
    StudentCourse stuCos = (StudentCourse) obj;
    if (stuCos.getCourse().getId() == this.getCourse().getId() 
    && stuCos.getStudent().getId() == this.getStudent().getId()) {
    return true;

    return super.equals(obj);
    }
    }@Entity
    @Table(name="student")
    public class Student implements Serializable {
    private static final long serialVersionUID = 1L; @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(unique=true, nullable=false)
    private int id; @Column(nullable=false, length=10)
    private String name; //bi-directional many-to-one association to School
    @ManyToOne
    @JoinColumn(name="school_id")
    private School school; //bi-directional many-to-one association to StudentCourse
    @OneToMany(mappedBy="student", cascade = ALL, fetch = FetchType.EAGER)
    private Set<StudentCourse> studentCourses; public Student() {
    } public int getId() {
    return this.id;
    } public void setId(int id) {
    this.id = id;
    } public String getName() {
    return this.name;
    } public void setName(String name) {
    this.name = name;
    } public School getSchool() {
    return this.school;
    } public void setSchool(School school) {
    this.school = school;
    } public Set<StudentCourse> getStudentCourses() {
    return this.studentCourses;
    } public void setStudentCourses(Set<StudentCourse> studentCourses) {
    this.studentCourses = studentCourses;
    }

    public void addStudentCourse(StudentCourse stuCos) {
    if (null == this.studentCourses) {
    this.studentCourses = new HashSet<StudentCourse>();
    }
    this.studentCourses.add(stuCos);
    }
    }
      

  2.   

    你使用的em。merge(o)用于保存
    试一下 o = em.merge(o);
    关于 persist, merge
    看看这几个链接
    http://stackoverflow.com/questions/1069992/jpa-entitymanager-why-use-persist-over-merge
    http://stackoverflow.com/questions/4509086/what-is-the-difference-between-persist-and-merge-in-hibernate
    http://spitballer.blogspot.de/2010/04/jpa-persisting-vs-merging-entites.html
      

  3.   

    这个问题没有彻底解决,等待高手给出彻底解决方案目前了解到其中一个原因: lazy load --》》后来通过 jpa enhance,实现了一部分类的lazy load
      

  4.   

    dao类的开始,已经加上了  @Transactional annotaion, 所以不应该是这个问题运行环境是tomcat6, 会不会与这个有关系?