hibernate复习第(二)天
今日要点:
关联映射
多对一(Employee - Department)
一对多(Department - Employee)
一对一(Person - IdCard)
多对多(teachet - student)
组件映射(User - Name)
集合映射(set,list,map,bag)
inverse和cascade(Employee - Department)
多对一:
<many-to-one name="depart" column="depart_id"/>
name:对应employee类的depart字段;
column:对应在employee表中的外键列名
如果上面这样设置代表employee表的depart_id这个列是外键对应Department表的主键
------------------------------------------------
property-ref:如果该列对应的不是外键表的主键的话,需要使用property-ref属性
property-ref:
(optional) The name of a property of the associated class that is joined to this foreign key.
If not specified, the primary key of the associated class is used.也就是说如果不指定property-ref,默认表示外键连接的是其他表的主键,如果指定了property-ref,则连接的是对应javabean的property-ref指定属性对应的表的字段
一般情况下,外键对应的都是其他表的主键
如果连column都没有写,则表示外键列对应的列名就是name名
not-null=“true”:<many-to-one name="depart" column="depart_id" not-null="true"/> 加入not-null=“true”。表示外键的列不能为空
一对多:
<set name="employees">
<key column="depart_id" /><!-- 对应的关联列 名 -->
<one-to-many class="Employee"/><!-- class表示Set中子元素的类型 -->
</set>
多对一和一对多不好分开,我就索性不分开了。
例子:
package cn.itcast.domain; import java.util.Set; public class Department { private int id; private String name; private Set<Employee> employees; public Set<Employee> getEmployees() { return employees; } public void setEmployees(Set<Employee> employees) { this.employees = employees; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Department() { super(); } public Department(int id, String name) { super(); this.id = id; this.name = name; } }
<?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 package="cn.itcast.domain"> <class name="Department"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="employees" > <key column="depart_id" /> <!-- 对应的关联列 名,默认关联列是本id --> <one-to-many class="Employee" /> <!-- Set中子元素的类型 --> </set> </class> </hibernate-mapping>
package cn.itcast.domain; public class Employee { private int id; private String name; private Department depart; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Department getDepart() { return depart; } public void setDepart(Department depart) { this.depart = depart; } public Employee() { super(); } public Employee(int id, String name, Department depart) { super(); this.id = id; this.name = name; this.depart = depart; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", depart=" + depart + "]"; } }
<?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 package="cn.itcast.domain"> <class name="Employee"> <id name="id" > <generator class="native"/> </id> <property name="name" unique="true"/> <many-to-one name="depart" column="depart_id" cascade="save-update"/><!-- not-null="true"这个属性有点贱,先不写 --> </class> </hibernate-mapping>
package cn.itcast.test; import org.hibernate.Session; import org.hibernate.Transaction; import cn.itcast.dao.HibernateUtil; import cn.itcast.domain.Department; import cn.itcast.domain.Employee; public class Mang2OneDemo { public static void main(String[] args) { add(); // Employee emp=query(1); // System.out.println(emp.getName()+"---"+emp.getDepart().getName()); //我在外面这样查询,得到的是报错信息没有Session,应该设计多对一默认使用了延迟加载吧 } static Department add(){ Session s=null; Transaction tx=null; try{ Department depart=new Department(); depart.setName("depart name"); Employee emp=new Employee(); emp.setName("employee name"); emp.setDepart(depart);//对象模型上建立两个对象的关联。这个不写则emp表中的dept对应字段为空 s=HibernateUtil.getSession(); tx=s.beginTransaction(); s.save(depart);//这时候执行insert语句,depart变成持久状态,depart的id属性为1,name为depart name s.save(emp);//这时候执行insert语句,emp变成持久状态,将emp中数据插入employee表。depart对象在depart表中能找到对应数据,符合关联,commit后所有操作成功。 /* 替换了位置 */ // s.save(emp);//执行插入语句,emp变成持久态,这时候emp中的depart对象的id属性没有值 // s.save(depart);//执行插入语句,修改了depart的id属性,所以hibernate检测到了持久化对象的改变,执行update语句。update语句之后,数据库表中能找到对应的主外数据。commit之后可以操作成功。 /* 只写一个保存emp */ // s.save(emp);//执行插入语句,执行插入语句,emp变成持久态,这时候emp中的depart对象的id没有值,name却有值,就是dept_id属性暂时为空。commit之后发现depart表中没有数据可以匹配的Department字段,报错。就是depart数据没有id,持久化不够。 /* * hibernate自动维护关系模型 */ tx.commit(); return depart; }finally{ if(s!=null) s.close(); } } static Employee query(int id){ Session s=null; try{ s=HibernateUtil.getSession(); Employee emp=(Employee) s.get(Employee.class, id); System.out.println(emp.getDepart().getName()); // Hibernate.initialize(emp.getDepart());//Hibernate的初始化对象方法可以手动加载该对象避免报错 return emp; }finally{ if(s!=null) s.close(); } } }
package cn.itcast.test; import java.util.HashSet; import java.util.Set; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import cn.itcast.dao.HibernateUtil; import cn.itcast.domain.Department; import cn.itcast.domain.Employee; public class One2ManyDemo { public static void main(String[] args) { Department depart=add1(); Department dp=query(depart.getId()); // HashSet<Employee> hs=(HashSet<Employee>) dp.getEmployees(); //org.hibernate.collection.PersistentSet 这里会抛出异常,因为在hibernate中使用的集合元素其实都是经过hibernate封装过得,使得可以支持懒加载等操作,以set为例,是Set的子类却不是HashSet的子类i System.out.println("dp:"+dp.getEmployees()); // System.out.println("dp:"+Arrays.toString(dp.getEmployees())); } static Department add(){//这里插入数据使用的是多对一 Session s=null; Transaction tx=null; try{ Department depart=new Department(); depart.setName("depart name"); Employee emp1=new Employee(); emp1.setName("emp name1"); emp1.setDepart(depart); Employee emp2=new Employee(); emp2.setName("emp name2"); emp2.setDepart(depart); s=HibernateUtil.getSession(); tx=s.beginTransaction(); s.save(depart); s.save(emp1); s.save(emp2); tx.commit(); return depart; }finally{ if(s!=null) s.close(); } } static Department add1(){//这个使用的就是多对一 Session s=null; Transaction tx=null; try{ Set<Employee> emps=new HashSet<Employee>(); // List<Employee> emps=new ArrayList<Employee>(); // Map<String,Employee> emps=new HashMap<String,Employee>(); // Employee[] emps=new Employee[2]; Department depart=new Department(); depart.setName("depart name"); Employee emp1=new Employee(); emp1.setName("emp name1"); emp1.setDepart(depart); Employee emp2=new Employee(); emp2.setName("emp name2"); emp2.setDepart(depart); emps.add(emp2); emps.add(emp1); // emps.put(emp1.getName(), emp1); // emps.put(emp2.getName(), emp2); // emps[0]=emp2; // emps[1]=emp1; // // depart.setEmployees(emps); s=HibernateUtil.getSession(); tx=s.beginTransaction(); s.save(emp1); s.save(emp2); // s.save(depart); tx.commit(); return depart; }finally{ if(s!=null) s.close(); } } static Department query(int id){ Session s=null; try{ s=HibernateUtil.getSession(); Department depart=(Department) s.get(Department.class, id); Hibernate.initialize(depart.getEmployees()); return depart; }finally{ if(s!=null) s.close(); } } }
一对一:
分为两种,基于主键的一对一和基于外键的一对一。
第一种:
基于主键的one-to-one
<id name="id">
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<one-to-one name="idCard" constrainted="true"/>
例子:
package cn.itcast.domain; import java.util.Date; public class IDCard { private int id; private Date usefulLife; private Person person; public int getId() { return id; } public void setId(int id) { this.id = id; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public IDCard() { super(); } public Date getUsefulLife() { return usefulLife; } public void setUsefulLife(Date usefulLife) { this.usefulLife = usefulLife; } }
package cn.itcast.domain; public class Person { private int id; private String name; private IDCard idcard; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public IDCard getIdcard() { return idcard; } public void setIdcard(IDCard idcard) { this.idcard = idcard; } public Person() { super(); } public Person(int id, String name, IDCard idcard) { super(); this.id = id; this.name = name; this.idcard = idcard; } }
<?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 package="cn.itcast.domain"> <class name="IDCard" table="id_card"> <!-- 驼峰式命名法是java规范,在数据库中的规范是使用下划线,所以我们给个名字 --> <id name="id"> <!-- 这个id即是主键也是外键 --> <generator class="foreign"> <param name="property">person</param> <!-- 表示这个外键的值是从person属性里面的到的,根据下面的one-to-one知道对应person的什么属性--> </generator> <!-- <generator class="native"/> --> </id> <property name="usefulLife" column="useful_life"/> <one-to-one name="person" constrained="true"/> <!--加上constrained=true这样hibernate映射表的时候自动映射出外键 --> </class> </hibernate-mapping>
<?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 package="cn.itcast.domain"> <class name="Person"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <one-to-one name="idcard"/> <!-- --> </class> </hibernate-mapping>
package cn.itcast.test; import java.util.Date; import org.hibernate.Session; import org.hibernate.Transaction; import cn.itcast.dao.HibernateUtil; import cn.itcast.domain.IDCard; import cn.itcast.domain.Person; public class One2OneDemo { public static void main(String[] args) { add(); query(1); } static Person add(){ Session s=null; Transaction tx=null; try{ s=HibernateUtil.getSession(); IDCard idCard=new IDCard(); idCard.setUsefulLife(new Date()); Person p=new Person(); p.setName("p1"); p.setIdcard(idCard); idCard.setPerson(p);//附表必须依赖于父表才能存在,父表可以没有字表 tx=s.beginTransaction(); s.save(p); s.save(idCard); tx.commit(); return p; }finally{ if(s!=null) s.close(); } } static Person query(int id){ /* * 查询主对象的时候 * 多对一的时候查询从对象是使用两次查询得到结果 * 一对一查询从对象是使用连接表的形式查询出来 */ Session s=null; try{ s=HibernateUtil.getSession(); // Person p=(Person) s.get(Person.class, id); // System.out.println(p.getIdcard().getUsefulLife()); IDCard idcard=(IDCard) s.get(IDCard.class, id); System.out.println(idcard.getPerson().getName()); return null; }finally{ if(s!=null) s.close(); } } }
第二种:
基于外键的one-to-one
基于外键的one-to-one,可以描述为多对一,加unique="true"约束
<one-to-one name="idCard" property-ref="person"/>
<many-to-one name="person" column="person_id" unique="true" not-null="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 package="cn.itcast.domain"> <class name="Person"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!-- <one-to-one name="idcard"/> --> <one-to-one name="idcard" property-ref="person"/><!-- property-ref对应的是java类中的关联属性 ,去掉的话变成了单向关联,之前是因为默认主键关联而且真的主键关联所以不需要配置--> </class> </hibernate-mapping>
<?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 package="cn.itcast.domain"> <class name="IDCard" table="id_card"> <!-- 驼峰式命名法是java规范,在数据库中的规范是使用下划线,所以我们给个名字 --> <id name="id"> <!-- 这个id即是主键也是外键 --> <generator class="foreign"> <param name="property">person</param> <!-- 表示这个外键的值是从person属性里面的到的,根据下面的one-to-one知道对应person的什么属性--> </generator> <!-- <generator class="native"/> --> </id> <property name="usefulLife" column="useful_life"/> <!-- <one-to-one name="person" constrained="true"/> 加上constrained=true这样hibernate映射表的时候自动映射出外键 --> <many-to-one name="person" column="person_id" unique="true"/> <!-- many-to-one连接使用的是column而不是property-ref --> </class> </hibernate-mapping>
一些说明以及属性:
主键为其他表的外键:
<id name="id">
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
constraint=“true”。在one-to-one中加上这个属性可以让hibernate操作数据表自动生成外键约束。如果不加上这个属性在一对一的时候是不会生成外键约束的
unique=“true”表示该列唯一
one-to-one中的property-ref:property-ref对应的是java类中的关联属性 ,去掉的话变成了单向关联,之前是因为默认主键关联而且真的是主键关联所以不需要配置
java中命名规范使用驼峰式命名法,sql中使用的是一个单词加_加另一个单词,且单词全部小写的规范
一对一关联中:附表必须依赖于母表才能存在,而母表不需要依赖附属表
查询主表对象时:多对一的关系是使用两次查询得到结果。一对一关系是直接使用连接表形式得到结果
多对多:
在操作和性能方面都不太理想,所以多对多的映射使用比较少,实际使用中最好转换成一对多的对象模型;hibernate会为我们创建中间关联表,转换成两个一对多
<set name="teacher" table="teacher_student">
<key column="teacher_id"/>
<many-to-many class="Student" column="student_id"/>
</set>
package cn.itcast.domain; import java.util.Set; public class Student { private int id; private String name; private Set<Teacher> teachers; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Teacher> getTeachers() { return teachers; } public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; } public Student(int id, String name, Set<Teacher> teachers) { super(); this.id = id; this.name = name; this.teachers = teachers; } public Student() { super(); } }
package cn.itcast.domain; import java.util.Set; public class Teacher { private int id; private String name; private Set<Student> students; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } public Teacher(int id, String name, Set<Student> students) { super(); this.id = id; this.name = name; this.students = students; } public Teacher() { super(); } }
<?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 package="cn.itcast.domain"> <class name="Student"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="teachers" table="teacher_student" > <key column="student_id" /> <many-to-many class="Teacher" column="teacher_id"/> </set> </class> </hibernate-mapping>
<?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 package="cn.itcast.domain"> <class name="Teacher"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="students" table="teacher_student"><!-- table告诉hibernate中间表是teacher_student --> <key column="teacher_id"/><!-- key中的column表示与teacher表的关联列 --> <many-to-many class="Student" column="student_id"/><!-- class表示放置的对象是什么,这里的column表示与student表的关联列 --> </set> </class> </hibernate-mapping>
package cn.itcast.test; import java.util.HashSet; import java.util.Set; import org.hibernate.Session; import org.hibernate.Transaction; import cn.itcast.dao.HibernateUtil; import cn.itcast.domain.Student; import cn.itcast.domain.Teacher; public class Many2ManyDemo { public static void main(String[] args) { add(); query(1); } static void add(){ Session s=null; Transaction tx=null; try{ s=HibernateUtil.getSession(); Set<Teacher> ts=new HashSet<Teacher>(); Set<Student> ss=new HashSet<Student>(); Teacher t1=new Teacher(); t1.setName("t1 name"); ts.add(t1); Teacher t2=new Teacher(); t2.setName("t2 name"); ts.add(t2); Student s1=new Student(); s1.setName("s1 name"); ss.add(s1); Student s2=new Student(); s2.setName("s2 name"); ss.add(s2); /* * 对多多关系的建立和前面的一对多等不同,它是向中间表插入数据而不是更新外键 */ // t1.setStudents(ss); // t2.setStudents(ss); /* * 关系的维护可以是任意一个表的对象,但不可以重复。因为student增加teachers和teacher增加students插入中间表的数据是一样的 * 多对多生成的中间表的主键是多个键的联合主键 PRIMARY KEY (`student_id`,`teacher_id`), */ s1.setTeachers(ts); s2.setTeachers(ts); tx=s.beginTransaction(); s.save(t1); s.save(t2); s.save(s1); s.save(s2); tx.commit(); }finally{ if(s!=null) s.close(); } } static void query(int id){ Session s=null; try{ s=HibernateUtil.getSession(); Teacher t=(Teacher)s.get(Teacher.class, id); System.out.println("students:"+t.getStudents().size()); }finally{ if(s!=null) s.close(); } } }
hibernate处理多对多的方法是创建中间表,转移成为两个一对多的问题。
<set name="teachers" table="teacher_student" >
<key column="student_id" />
<many-to-many class="Teacher" column="teacher_id"/>
</set>
table:创建的中间表的表名,两个映射文件中table应该相等
key中的column :指的是中间表和本表的关联字段,默认关联的是本表的id字段,如果不是需要使用property-ref指出
many-to-many中的class:表示该集合中的元素是什么类型,Column表示中间表使用什么列和改类型元素进行关联
一些说明:
对多多关系的建立和前面的一对多等不同,它是向中间表插入数据而不是更新外键
关系的维护可以是任意一个表的对象,但不可以重复。因为student增加teachers和teacher增加students插入中间表的数据是一样的
多对多生成的中间表的主键是多个键的联合主键 PRIMARY KEY (`student_id`,`teacher_id`),
注意:多对多的效率是比较低的,当多的一段数据量比较大,那么就会出现性能问题。帖子问题:热门的帖子有几万条回复,一般都是使用分页查询的,一般我们这种情况不会建立一对多的关系,我们是使用人工做的,子查询并带有分页做的,系统在设置的时候帖子和评论的一对多并不会存在,这是考虑到效率上的问题。一般一对多是在多的数量不会很大的时候使用,例如用户和权限,用户和email。使用一对多的时候需要慎重,所以我们有时候建立单向关系,不需要一对多而是多对一。这些关联关系用得最多的是多对一这种关联关系。
组件映射(User-Name)
关联的属性是个复杂类型的持久化类,但不是实体。即:数据库表中没有表与该属性对应,但是该类的属性要永久保存的。
<component name="name" class="Name">
<property name="firstName" column="first_name"/>
<property name="lastName" column="last_name"/>
</component>
使用场景简单模拟:
就是User对象中的Name不是一个普通类型的而是一个自定义类型,那个类型中有两个属性firstName和lastName。如果可以使用多个表,我们可以考虑使用一对一或者多对一,但是我们不希望使用太多表,因为我们觉得Name这么点属性建一个新表不好,所以我们希望将name的属性也存储到User表中去。但是在User类中属性类型是Name类型,这时候就可以使用组件关联
package cn.itcast.domain; public class Name { private String firstName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
package cn.itcast.domain; import java.util.Date; public class User { private int id; private Name name; private Date birthday; public int getId() { return id; } public void setId(int id) { this.id = id; } public Name getName() { return name; } public void setName(Name name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
<?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 package="cn.itcast.domain"> <class name="User"> <id name="id"> <generator class="native"/> </id> <property name="birthday"/> <component name="name" class="Name"> <property name="firstName" column="first_name"/> <property name="lastName" column="last_name"/> </component> </class> </hibernate-mapping>
package cn.itcast.test; import java.util.Date; import org.hibernate.Session; import org.hibernate.Transaction; import cn.itcast.dao.HibernateUtil; import cn.itcast.domain.Name; import cn.itcast.domain.User; public class ComponentDemo { public static void main(String[] args) { add(); } static void add(){ Session s=null; Transaction tx=null; try{ s=HibernateUtil.getSession(); Name name=new Name(); name.setFirstName("first name"); name.setLastName("last name"); User user=new User(); user.setName(name); user.setBirthday(new Date()); tx=s.beginTransaction(); s.save(user); tx.commit(); }finally{ if(s!=null) s.close(); } } }
学习hibernate如何处理对象之间的额关联关系的底层细节时,可以从两方面去考虑:一是如何将对象之间的关联关系保存到数据库中,二是如何检索出关联的对象
hibernate中的各种集合:set、List、bag、array、Map (bean和测试类中我就不列出来了)
set:
无序,不允许重复
前面我们进行多对一都使用的set,set就不介绍了
<set name="employees" > <key column="depart_id" /> 对应的关联列 名,默认关联列是本id <one-to-many class="Employee" /> Set中子元素的类型 </set>
List:
list和set的区别主要体现在list是有序的,而set是无序的,bean中简单改动,映射文件中的改动就和这个区别有关。
<list name="employees">
<key column="depart_id" /><!-- 注意key的位置要在首位 -->
<list-index column="order_id" /><!-- 为了保证数据的有序性,所以我们需要提供一个list的索引列,它会进入你的数据库表 -->
<one-to-many class="Employee" />
</list>
bag:
使用list的时候,数据库表中多处一列用来保持数据的有序性,有时候我们不需要数据具有有序性,却还想使用list集合,这时候我们就使用bag。bag是hibernate特有的
<bag name="employees">
<key column="depart_id" />
<one-to-many class="Employee" /> <!-- bag集合只能使用在List中 -->
</bag>
Map:
map与set的区别在于它是一种键值对的存在形式,通常可用来表示唯一
这个举个例子:就是我们的员工表中让员工的姓名是唯一的,但是我们使用set集合插入数据的时候,就算写在该property写了unique,报错是在保存数据的时候抛出异常,我们可以使用Map集合解决这个问题。让用户的name属性作为key,用户的对象作为值,这样后面的是会将前面的覆盖而不是报错了。
<map name="employees">
<key column="depart_id" />
<map-key type="java.lang.String"/>
<one-to-many class="Employee" />
</map>
array:
我只知道数据是有序的
<array name="employees">
<key column="depart_id" />
<index column="order_id"/> <!-- 这里使用的是index,用来保证有序 -->
<one-to-many class="Employee" />
</array>
hibernate中各种集合容器的选择:
使用hibernate,绝大多数的情况下使用的是set,set是不允许重复的。如果习惯性使用List,但是不想要保持顺序,使用bag进行映射,想保存顺序使用List映射
hibernate中的集合注意:
在持久化类中我们使用的集合全部使用接口而不是具体的实现类
例子(代码我就不贴出来了):
使用将demo中的department.getEmps得到的set集合转换成为HashSet报ClassCastException
原因:org.hibernate.collection.PersistentSet,在hibernate中使用的集合元素其实都是经过hibernate封装过得,使得可以支持懒加载等操作,以set为例,是Set的子类却不是HashSet的子类
第二个例子:将持久化类中的Set替换成为HashSet。IllegalArgumentEcxeption非法参数异常,这是因为HashSet无法转换成为hibernate.collection.PersistentSet
级联cascade:
Cascade用来说明当前主对象进行某种操作时是否对其关联的从对象进行类似的操作。 缺省状态下,hibernate如果持久化类中存在其他持久化类的对象的话,是不会对该对象进行操作的,增加不会对该对象进行增,删不会进行删。所以我们前面的额save操作都是先save子对象再save父对象,子对象的数据再数据表中可以找得到就可以进行外键的更新。 如果希望hibernate自动进行更新等操作,可以在set上面添加级联属性cascade 常见的cascade属性: none(默认值,不进行任何操作) all(所有的,对我进行什么操作,对相级联的对象做同样的操作) save-update(保存和更新的时候做级联) delete(删除的时候做级联) lock() delete-orphan(在one-to-many的时候才可以使用,指的是将一删掉就会将1下的所有多删除) 。。。。等等 需要多个级联操作可以使用逗号分隔即可。 配置在具有多个对象关联的地方,比如一对一,一对多等
不使用级联的话我们没操作一个对象都需要对其子对象进行持久化操作,使用了就是hibernate根据级联帮助我们进行。例子:
<many-to-one name="depart" column="depart_id" cascade="save-update"/><!-- not-null="true"这个属性有点贱,先不写 -->
这样的话,对雇员表的增加和更新操作会级联操作部门表。可以省代码。具体实现代码太乱了,不想整理了,在前面多对一中的代码中有使用
拒绝维护关系:inverse属性
如果设置了inverse属性为false,则表示放弃对象关系的维护。也就是就算你s给该对象属性赋值了但是它不会进行外键的更新。 一般的,在多对一的情况下,我们将一的一方设置放弃维护关联关系,将关联关系交给多来维护,这样可以省略2条update语句,因为其实多的一方和一的一方对对象关系的维护的语句其实是一样的,也就是重复了一部分。如果多维护了关联关系,并且一先进行了save,那么可以省略2条update语句 inverse使用的限制: 不能再有序的集合使用。因为inverse=true放弃维护关联,所以就无法保持有序 inverse属性只会在集合属性才有。 我们知道在多对多的时候不能两方都进行关系的维护,是因为中间表的主键约束冲突。解决这个问题的方法就是在任意一端设置inverse=true,放弃对象关系的维护 注意:如果放弃了维护关系,那么级联会失效
例子:
<set name="employees" inverse="true"><!-- cascade="save-update" -->
<key column="depart_id" /> <!-- 对应的关联列 名,默认关联列是本id -->
<one-to-many class="Employee" /> <!-- Set中子元素的类型 -->
</set>
具体例子也乱了,不想整理,在前面的多对一代码中有