(原创)Hibernate 使用过程中(尤其是多对多关联中的级联保存和级联删除)的注意事项(基于项目的总结)

时间:2024-03-29 15:37:08

一.先上知识点:

1.hibernate多对多关联关系中最重要的参数是(基于配置文件xxx.hbm.xml文件形式):

1):inverse属性,如果设置inverse=“true”就代表让对方参与维护第三方表格。//这个属性特别重要,多对多关系中最好有且只有一个维护第三方表格,如果两方都维护第三方表格,那么可能第三方表格会重复维护现象(有可能会造成第三方表格联合主键的重复)

2):lazy属性,这个属性代表延迟加载与否,在讲这个属性之前,先讲一个东西,就是在hibernate多对多关联关系中,在双方的类中都会出现一个Set<XXX>这个集合属性(在读取过程中,这个set集合会被hibernate封装成persistentSet集合),当在xxx.hbm.xml文件中设置lazy=“false”时,就说明,不会让延迟加载起作用,那么这个延迟加载加载什么东西呢?延迟加载的东西就是刚刚提到的Set<XXX>集合中的东西,打个比方,现在有多对多的User类和Educate类(员工多对多培训课程),在User类中的java代码如下:

package com.ssh.entities;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set; public class User {
private Long id;//员工编号
private String name;//员工用户名
private String password;//登录密码
private Byte sex;//性别
private Date birthday;//生日
private Date createtime;//创建时间
private Byte isadmin;//是否为管理员
private String content;//人员简介
private Set<Educate> educate=new HashSet<Educate>();
public Set<Educate> getEducate() {
return educate;
}
public void setEducate(Set<Educate> educate) {
this.educate = educate;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Byte getSex() {
return sex;
}
public void setSex(Byte sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public Byte getIsadmin() {
return isadmin;
}
public void setIsadmin(Byte isadmin) {
this.isadmin = isadmin;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public User(Long id, String name, String password, Byte sex, Date birthday,
Date createtime, Byte isadmin, String content) {
this.id = id;
this.name = name;
this.password = password;
this.sex = sex;
this.birthday = birthday;
this.createtime = createtime;
this.isadmin = isadmin;
this.content = content;
}
public User() {
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password
+ ", sex=" + sex + ", birthday=" + birthday + ", createtime="
+ createtime + ", isadmin=" + isadmin + ", content=" + content
+ "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
} }

上述代码中标红的就是一个Set<Educate>集合。

那我在User.hbm.xml文件中配置lazy="false"的时候,就是说明,当我前端或者后台需要加载user对象时,那这个带有对方(Educate类)的集合也会通过第三方表格顺带着把Educate类中的信息一起加载出来,

反之,当lazy="true"的时候就默认lazy延迟加载工程开启,也就是说Set集合中的东西,现在不会给加载出来。

3)cascade属性,我在项目中一般配置  cascade=“all”,这个就代表在级联操作时(保存、删除)会不会级联到关联的一方

总结:基于配置文件的hibernate 多对多就是lazy和inverse属性在起关键作用。

2.hibernate 多对多中的级联保存和删除:

1)保存,保存一般情况下不仅保存自己一方的对象到数据库,还需要顺带着把和另一方的关系也保存到第三方表格,那么这时,如果是自己这方是负责维护第三方表格的,那么当编辑自己对象的信息时(将集合中塞入对方对象到集合中,代表与对方的关系),在执行hibernate的session的saveOrupdate()方法时,不仅保存自己对象到数据库中,同时也会把维护关系保存到第三方表格中,如果自己这方没有负责维护第三方表格,那么即便自己这方的Set集合中添加了对方对象的信息,当执行hibernate的session的  saveorUpdate()方法时,只能是把自己的信息保存到自己对应的数据库中,与对方的关系(通过set集合中的信息进行设置,通过第三方的数据表格体现)的第三方表格,没有发生更新,也就是说没有达到想要的结果。

现在举例说明一下:

User类(如上)和User.hbm.xml文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ssh.entities.User" table="user">
<id column="id" name="id" type="java.lang.Long">
<generator class="native"></generator>
</id>
<property name="name" length="50" type="java.lang.String"/>
<property name="password" length="50" type="java.lang.String"/>
<property name="sex" length="4" type="java.lang.Byte"/>
<property name="birthday" length="23" type="java.util.Date"/>
<property name="createtime" length="23" type="java.util.Date"/>
<property name="isadmin" length="4" type="java.lang.Byte"/>
<property name="content" length="2000" type="java.lang.String"/>
<set name="educate" table="user_educate" lazy="false" cascade="all" inverse="false">
<key column="user_id"></key>
<many-to-many class="com.ssh.entities.Educate" column="educate_id"></many-to-many>
</set>
</class>
</hibernate-mapping>

Educate类和Educate.hbm.xml

package com.ssh.entities;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set; public class Educate {
private Long id;//培训标号
private String name;//培训名称
private String purpose;//培训目的
private Date begintime;//培训开始时间
private Date endtime;//培训结束时间
private String datum;//培训材料
private String teacher;//培训讲师
private String student;//培训人员
private Date createtime;//创建时间
private Byte educate;//培训是否完成
private String effect;//培训效果
private String summarize;//培训总结
private Set<User> user=new HashSet<User>(); public Set<User> getUser() {
return user;
}
public void setUser(Set<User> user) {
this.user = user;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPurpose() {
return purpose;
}
public void setPurpose(String purpose) {
this.purpose = purpose;
}
public Date getBegintime() {
return begintime;
}
public void setBegintime(Date begintime) {
this.begintime = begintime;
}
public Date getEndtime() {
return endtime;
}
public void setEndtime(Date endtime) {
this.endtime = endtime;
}
public String getDatum() {
return datum;
}
public void setDatum(String datum) {
this.datum = datum;
}
public String getTeacher() {
return teacher;
}
public void setTeacher(String teacher) {
this.teacher = teacher;
}
public String getStudent() {
return student;
}
public void setStudent(String student) {
this.student = student;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public Byte getEducate() {
return educate;
}
public void setEducate(Byte educate) {
this.educate = educate;
}
public String getEffect() {
return effect;
}
public void setEffect(String effect) {
this.effect = effect;
}
public String getSummarize() {
return summarize;
}
public void setSummarize(String summarize) {
this.summarize = summarize;
}
public Educate(Long id, String name, String purpose, Date begintime,
Date endtime, String datum, String teacher, String student,
Date createtime, Byte educate, String effect, String summarize) {
this.id = id;
this.name = name;
this.purpose = purpose;
this.begintime = begintime;
this.endtime = endtime;
this.datum = datum;
this.teacher = teacher;
this.student = student;
this.createtime = createtime;
this.educate = educate;
this.effect = effect;
this.summarize = summarize;
}
public Educate() {
}
@Override
public String toString() {
return "Educate [id=" + id + ", name=" + name + ", purpose=" + purpose
+ ", begintime=" + begintime + ", endtime=" + endtime
+ ", datum=" + datum + ", teacher=" + teacher + ", student="
+ student + ", createtime=" + createtime + ", educate="
+ educate + ", effect=" + effect + ", summarize=" + summarize
+ "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Educate other = (Educate) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
} }
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ssh.entities.Educate" table="educate">
<id column="id" name="id" type="java.lang.Long">
<generator class="native"></generator>
</id>
<property name="name" length="100" type="java.lang.String"></property>
<property name="purpose" length="500" type="java.lang.String"/>
<property name="begintime" length="23" type="java.util.Date"/>
<property name="endtime" length="23" type="java.util.Date"/>
<property name="datum" length="2000" type="java.lang.String"/>
<property name="teacher" length="50" type="java.lang.String"/>
<property name="student" length="50" type="java.lang.String"/>
<property name="createtime" length="23" type="java.util.Date"/>
<property name="effect" length="500" type="java.lang.String"/>
<property name="educate" length="1" type="java.lang.Byte"/>
<property name="summarize" length="2000" type="java.lang.String"/>
<set name="user" table="user_educate" lazy="true" cascade="all" inverse="true">
<key column="educate_id"></key>
<many-to-many class="com.ssh.entities.User" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>

后台控制的java代码(保存和另一方关系的代码):

public String insertcourse(){
String[] para=request.getParameterValues("edupara");
String userid=request.getParameter("userid"); if(para.length>0){
User us=userService.getUser(Long.parseLong(userid));
Set<Educate> edus=new HashSet<Educate>();
edus=us.getEducate();
for(String str: para ){
Educate educate=educateService.getForEdu(Long.parseLong(str));
/* Set users=new HashSet<User>();
users=educate.getUser();
System.out.println(users.size());
users.add(us);
System.out.println(users.size());
educate.setUser(users); educateService.saveorUpdate(educate);
*/
edus.add(educate);
}
us.setEducate(edus);
userService.saveOrUpdate(us);
}
return "insertcourse";

  2)删除级联的注意事项:

(1)如果不是User维持关联关系:

——若连接表user_educate中有参照user表中该记录的记录(即在user_educate表中存在user_id的记录)时,则删除失败。

——若连接表user_educate中没有参照user表中该记录的记录时,则可以成功地将该记录删除。

(2)如果是User维持关联关系:

——先将连接表user_educate中参照user表中该记录的记录删除,然后将该学生记录从user表中删除

最后附上后台处理的完整代码:

UserAction.java

package com.ssh.action;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.interceptor.ServletRequestAware; import com.opensymphony.xwork2.ActionSupport;
import com.ssh.entities.Educate;
import com.ssh.entities.User;
import com.ssh.service.EducateService;
import com.ssh.service.UserService; public class HumanAction extends ActionSupport implements ServletRequestAware{ /**
* @author zhangshitong
*/
private static final long serialVersionUID = 1L;
private String username;
private String password; private UserService userService; private InputStream inputStream; private HttpServletRequest request; private Long id; private List<Educate> eduList; private List<User> userList; private EducateService educateService; private User userForEdit; public void setEducateService(EducateService educateService) {
this.educateService = educateService;
} public void setId(Long id) {
this.id = id;
}
private User user;
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
public InputStream getInputStream() {
return inputStream;
} public void setUserService(UserService userService) {
this.userService = userService;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public String adduser(){
user.setCreatetime(new Date());
//user.setId(null);
System.out.println(user);
userService.saveOrUpdate(user);
user = null;
return "add";
} public String list(){
System.out.println(userService.getForList());
request.setAttribute("user", userService.getForList());
return "list";
} public String select(){
User usertemp=userService.getUser(id);
this.userForEdit=usertemp;
request.setAttribute("signalUser", usertemp);
return "edit";
} public String delete(){
userService.deleteUser(id);
try {
inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
try {
inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
return "ajax-success";
} public String modify(){
user.setEducate(userForEdit.getEducate());
user.setCreatetime(new Date());
System.out.println(user);
userService.saveOrUpdate(user);
return "modified";
} public String login(){
User user=userService.validName(username); if(user==null){
try {
inputStream = new ByteArrayInputStream("3".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
if(user.getPassword().equals(password)){
try {request.getSession().setAttribute("user", user);
inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
//ctx.getSession().put("user", user);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}else{
try {
inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} return "ajax-success";
} public String userselecteducate(){
System.out.println("这是查看员工选择课程时员工的id值:"+id);
Set eduSet=userService.getEducateInUser(id);
//System.out.println(eduSet);
List<Educate> eduList=new ArrayList<Educate>();
Iterator it=eduSet.iterator();
while(it.hasNext()){
Educate eduTemp=(Educate) it.next();
eduList.add(eduTemp);
}
request.setAttribute("edu", eduList);
request.setAttribute("name", username);
request.setAttribute("id", id);
return "userselecteducate";
} public String insertcourse(){
String[] para=request.getParameterValues("edupara");
String userid=request.getParameter("userid"); if(para.length>0){
User us=userService.getUser(Long.parseLong(userid));
Set<Educate> edus=new HashSet<Educate>();
edus=us.getEducate();
for(String str: para ){
Educate educate=educateService.getForEdu(Long.parseLong(str));
/* Set users=new HashSet<User>();
users=educate.getUser();
System.out.println(users.size());
users.add(us);
System.out.println(users.size());
educate.setUser(users); educateService.saveorUpdate(educate);
*/
edus.add(educate);
}
us.setEducate(edus);
userService.saveOrUpdate(us);
}
return "insertcourse";
} public String deletecourse(){
String userid=request.getParameter("userid");
User us=userService.getUser(Long.parseLong(userid));
Educate edu=educateService.getForEdu(id);
//edu.getUser().remove(us);
Set<Educate> educates=new HashSet<Educate>();
educates=us.getEducate();
educates.remove(edu);
us.setEducate(educates);
userService.saveOrUpdate(us);
try {
inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
try {
inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
return "ajax-success";
}
@Override
public void setServletRequest(HttpServletRequest arg0) {
// TODO Auto-generated method stub
this.request=arg0;
}
}

EducateAction类:

package com.ssh.action;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.interceptor.ServletRequestAware; import com.opensymphony.xwork2.ActionSupport;
import com.ssh.entities.Educate;
import com.ssh.entities.User;
import com.ssh.service.EducateService;
import com.ssh.service.UserService; public class EducateAction extends ActionSupport implements ServletRequestAware{ /**
* @author Administrator zhangshitong
*/
private static final long serialVersionUID = 1L; private Educate educate; private EducateService educateService; private HttpServletRequest request; private InputStream inputStream; private Long id; private UserService userService; public void setUserService(UserService userService) {
this.userService = userService;
} public void setId(Long id) {
this.id = id;
} public Long getId() {
return id;
}
public InputStream getInputStream() {
return inputStream;
}
public void setEducateService(EducateService educateService) {
this.educateService = educateService;
} public Educate getEducate() {
return educate;
} public void setEducate(Educate educate) {
this.educate = educate;
} public String addeducate(){
educate.setCreatetime(new Date());
System.out.println(educate);
educateService.saveorUpdate(educate);
return "addeducate";
} public String listeducate(){
List<Educate> list=educateService.getForList();
request.setAttribute("educate", list);
return "listeducate";
} public String delete(){
System.out.println("this is id's value:"+id);
//Set<User> users=new HashSet<User>();
//users=null;
List<User> userList=userService.getForList();
Educate edu=educateService.getForEdu(id);
Iterator<User> it=userList.iterator();
while(it.hasNext()){
User userListMember=it.next();
Set<Educate> setEducate=userListMember.getEducate();
if(setEducate.contains(edu)){
setEducate.remove(edu);
}
userService.saveOrUpdate(userListMember);
}
//edu.setUser(users);
//educateService.saveorUpdate(edu);
educateService.delete(id);
//educateService.deleteCascade(edu);
try {
inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
try {
inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
return "ajax-success";
} public String addcourse(){
List<Educate> list=educateService.getForList();
request.setAttribute("educate", list);
request.setAttribute("userid", id);
return "addcourse";
}
@Override
public void setServletRequest(HttpServletRequest arg0) {
// TODO Auto-generated method stub
this.request=arg0;
} }

spring的application配置文件(事务管理):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 导入资源文件 -->
<context:property-placeholder location="classpath:db.properties"/> <!-- 配置 C3P0 数据源 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean> <!-- 配置 SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="mappingLocations" value="classpath:com/ssh/entities/*.hbm.xml"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
</props>
</property>

</bean>
<!-- 配置 Spring 的声明式事务 --> <!-- 1. 配置 hibernate 的事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 2. 配置事务属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 3. 配置事务切入点, 再把事务属性和事务切入点关联起来 -->
<aop:config>
<aop:pointcut expression="execution(* com.ssh.dao.*.*(..))" id="txPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
</beans>

web.xml配置的过滤器:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>