例:学生(多端)和班级(一端)的持久化类的配置问题:这里我们定义持久化类:Student.java和StuClass,java。同时设置Student.hbm.xml和StuClass.hbm.xml文件。项目的整体结构如下:
在Studentjava文件中的属性设置如下(包含定义是属性的时候需要注意的一些事项):
private int StuId;
private String StuName;
private String Sex;
private String StuNum;
private Date Birthday;
private String Policital;
private String Nation;
private String Phone;
private Map
//一定要使用它的实现类来进行初始化
private StuClass stuClass;//在多端持久类中创建的class属性
public StuClass getStuClass() {
return stuClass;
}
同时,我们在一端的StuClass.java文件中的定义属性如下(这里需要注意的是在设置Student属性的时候我们尽量使用的是set集合(当然,list和map集合也可以):
private int ClassId;
private String ClassName;
private String ClassNum;
//在一端创建的student集合属性
private Set student;
接着我们在Student.hbm,xml中的配置如下:
注意:我们在使用
下面是在StuClass.hbm.xml中的配置信息:
注意:在设置set集合的时候,其中的name属性指的是在该一端实体类中定义的student集合属性;key属性指定的是本持久化类的主键名称;
在
Cascade:级联属性表示的是再删除数据库中对应的列的时候相关联的数据库中的字段的操作情况。其中的:delete,表示级联删除;save表示级联保存;save-update表示的是在进行级联的时候自动查询是否存在相关的对象,存在的话进行比较并进行更新,如果没有存在,进行保存;evict,表示的是当清除session缓存中的相关对象的时候,与之相关的所有对象都得删除。
}
同时对于
inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为false表示本端维护关系,如果inverse为true,则本端不能维护关系,会交给另一端维护关系,本端失效。所以一对多关联映射我们通常在多的一端维护关系,让一的一端失效,所以设置inverse属性为true。(PS:尽量设置多端维护关系的原因是如果设置一端维护关系,那么在执行数据库插入的时候会额外增加几条update语句,会影响执行效率,这一点是必须要注意的。
分析原因:这句话的意思是:“非法尝试将集合与两个打开的会话关联。集合:[x x x.XXX.XXX#x]”,分析我的代码,这段报错是在我的StudentAction类中的Add方法中进行数据库插入的时候出现的(我个人观点:应该是在插入学生信息的时候,出现了两个session共用一个collection的情况,具体的深层原因还不明确)
解决办法:将Add方法中的session.save(Object o)改为session.merge()。这样改的目的是,merge执行的时候,Hibernate首先会查询在后端的数据库中是否存在该对象,如果存在那么进行对比后的更新操作,如果不存在,会进行插入数据库的操作。从而避免了相关错误的出现。
分析原因:这句话的意思是:“具有相同标识符值的其他对象已与XXX关联。”也就是说明,在session流中,已经出现了相关的对象。这一报错产生的地方是我的StudentAction中的Edit()方法中。下面是修改前的代码:
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
//创建事务对象
Transaction transaction = session.beginTransaction();
//得到相关的实体对应的序号
int id = (int) application.getAttribute("id");
//根据序号得到相关的实体信息
Student stutemp = session.get(Student.class, id);
//更新得到的实体信息
stutemp.setStuName(student.getStuName());
stutemp.setBirthday(student.getBirthday());
stutemp.setPhone(student.getPhone());
stutemp.setNation(student.getNation());
stutemp.setPolicital(student.getPolicital());
stutemp.setSex(student.getSex());
stutemp.setStuNum(student.getStuNum());
stutemp.setSchool(student.getSchool());
stutemp.setStuClass(student.getStuClass());
//判断是否到这一步停止了
System.out.println("stu-edit-stop-here-before-merge!");
//使用的是session的update方法(这里使用的是merge方法主要是因为在sessionh中有两个实体通用一个标志位
session.merge(stutemp);
经过分析可知,在执行session.merge()方法之前,我已经通过session.get()方法得到了一个持久化类的对象(load是懒加载,get是直接得到),那么,在执行merge()方法的时候,根据它的原理可知,会先进行查询,然后根据查询结果进行操作。那么如此看来问题出现的原因也就明了了,就是在merge()方法查询的时候发现了一个有一样标志放入session中的对象,所以报错。
解决办法:只需要在执行的merge()方法之前加一个session.clear()即可。表示清空所有缓存(不管是相关还是不相关都清除)。