本次学习是在hibernate3环境下,没有结合struts2和Spring,测试是直接用java类的main方法在控制台输出。
oracle数据库(其他数据库也可以,都是相似的)、hibernate3.jar等架包。
a.创建工程,引入hibernate和驱动开发包
b.在src下添加hibernate.cfg.xml主配置
c.根据数据表创建Entity实体类
d.编写实体类和数据表的映射文件xxx.hbm.xml
e.利用Hibernate API实现增删改查操作
1、在src下添加hibernate.cfg.xml主配置,配置内容如下:
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration> <session-factory> <!-- 连接数据库的驱动--> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <!-- 连接数据库的地址--> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost :1521:orcl</property> <!-- 连接数据库的用户名--> <property name="hibernate.connection.username">hr</property> <!-- 连接数据库的密码--> <property name="hibernate.connection.password">orcl</property>
<property name="hibernate.connection.pool.size">20 </property> <property name="hibernate.show_sql">true </property> <property name="jdbc.fetch_size">50 </property> <property name="jdbc.batch_size">23 </property> <property name="jdbc.use_scrollable_resultset">false </property> <property name="Connection.useUnicode">true </property>
<!--hibernate.dialect 只是Hibernate使用的数据库方言,就是要用Hibernate连接那种类型的数据库服务器。--> <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect </property>
<!--指定映射文件--> <mapping resource="com/neusoft/test/entity/User.hbm.xml" /> </session-factory> </hibernate-configuration> |
2、根据数据表创建Entity实体类,com/neusoft/test/entity/User.java,代码如下:
package com.neusoft.test.entity;
public class User { private int id; private String userName; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } 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; } } |
需要注意的是实体类定义的字段最好与数据库(oracle不区分大小写)中的字段一致,如果不一致会麻烦一些,且配置容易出错。
3、编写实体类和数据表的映射文件com/neusoft/test/entity/User.hbm.xml,该配置文件存放的位置不是固定的,但是要与hibernate.cfg.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 package="com.neusoft.test.entity"> <class name="User" table="demo_user_t"> <id name="id"> <column name="id"></column> <!--主键生成策略,sequence是oracle自增策略,别的数据库要使用各自适用的 --> <generator /> </id> <property name="userName" column="userName"/> <property name="password" /> </class> </hibernate-mapping> |
name属性对应的是实体类中的属性字段,必须是一致的(区分大小写),如果该字段与数据库表中的字段是一致的,则不需要column;如果不一致,则需要column指明该字段是与数据库中哪个字段是对应的。
数据库的表名为demo_user_t,含有字段id、userName、password。
4、测试,进行增删改查。新建一个test1.java。代码如下:
package com.neusoft.test.action;
import java.util.List; import org.hibernate.*; import com.neusoft.test.entity.User; import com.neusoft.test.utils.HibernateUtil;
public class test1 { /** * main函数,选择要执行的动作 */ public static void main(String args[]) { testFindAll(); }
/** * 测试添加操作 */ public static void testAdd() { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); User user = new User(); user.setId(1);// user.setId()要根据主键生成策略而定 user.setuserName("1"); user.setPassword("1"); session.save(user);// 保存 tx.commit();// 提交事务 session.close();// 关闭session }
/** * 测试更新操作 */ public static void testUpdate() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); // 按ID=1主键做条件查询 User user = (User) session.load(User.class, 1); user.setuserName("11"); user.setPassword("11"); session.update(user); tx.commit(); session.close(); }
/** * 测试删除操作 */ public static void testDelete() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); User user = new User(); user.setId(1); // User user = (User)session.get(User.class, 1); session.delete(user);// 执行一个delete语句,按ID做条件删除 tx.commit(); session.close(); }
/** * 测试查询操作 */ @SuppressWarnings("unchecked") public static void testFindAll() { Session session = HibernateUtil.getSession(); // 利用Query执行一个HQL查询语句 Query query = session.createQuery("from User"); List<User> list = query.list(); for (User u : list) { System.out.println(u.getId() + " " + u.getuserName() + " " + u.getPassword()); } session.close(); }
public static void testFindById() { Session session = HibernateUtil.getSession(); // 利用Query执行一个HQL查询语句 User user = (User) session.get(User.class, 1); System.out.println(user.getId() + " " + user.getuserName() + " " + user.getPassword()); session.close(); }
@SuppressWarnings("unchecked") public static void testFindByName() { Session session = HibernateUtil.getSession(); // 利用Query执行一个HQL查询语句 Query query = session.createQuery("from User where userName='1'"); List<User> list = query.list(); for (User u : list) { System.out.println(u.getId() + " " + u.getuserName() + " " + u.getPassword()); } session.close(); } } |
需要一个自定义的hibernate工具类HibernateUtil,代码如下:
package com.neusoft.test.utils;
import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration;
public class HibernateUtil { // static SessionFactory sessionFactory= new Configuration().configure().buildSessionFactory(); static SessionFactory sessionFactory = new Configuration().configure( "hibernate.cfg.xml").buildSessionFactory(); static Session session = sessionFactory.openSession();
public static Session getSession() { return session; }
public static void closeSession() { // TODO Auto-generated method stub session.close(); } } |
首先要说明,有多个实例化类时,可以定义定义多个映射文件xxx.hbm.xml,然后在主配文件hibernate.cfg.xml中指定所有映射文件;也可以只定义一个映射文件,在映射文件中定义多个实例化类(class的定义)。
还有一点要注意,一个实例化类只能被映射文件定义一次。如果要对同一个表进行不同功能的操作,则建多个与之对应的实例化类,然后在映射文件中定义不同功能的实例化类。
每次做完一个小test要将数据库表内的数据清空,否则会对其他的测试产生影响,有可能报错。
1 、 映射集合属性
(1)List集合映射:
数据库表students
schools
映射文件中添加如下配置:
<class name="Student" table="students"> <id name="id"> <column name="id"></column> <generator /> </id> <property name="name" /> <property name="age" /> <list name="schools" table="schools"> <!-- 外键,对应该表的某个字段,默认参考上面定义的id --> <key column="student_id" not-null="true"></key> <list-index column="list_order"></list-index> <element type="string" column="school_name"></element> </list> </class> |
实例化类如下:
package com.neusoft.test.entity;
import java.util.ArrayList; import java.util.List;
@SuppressWarnings("unchecked") public class Student { private int id; private String name; private int age; private List<String> schools = new ArrayList(); 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 int getAge() { return age; } public void setAge(int age) { this.age = age; } public List getSchools() { return schools; } public void setSchools(List schools) { this.schools = schools; } } |
测试类如下:
package com.neusoft.test.action;
import java.util.ArrayList; import java.util.List;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Student; import com.neusoft.test.utils.HibernateUtil;
public class TestListStudent { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction();
//添加 Student student = new Student(); student.setAge(12); student.setName("aqq"); List list = new ArrayList(); list.add("zqas"); list.add("zxxdfg"); list.add("zaadfg"); student.setSchools(list); session.save(student); tx.commit();// 提交事务
//查询 Query query = session.createQuery("from Student"); List<Student> list1 = query.list(); for (Student s : list1) { System.out.print("id:" + s.getId() + " 姓名:" + s.getName() + " 年龄:" + s.getAge() + " 上过的学校:"); List<String> list2 = s.getSchools(); for (String str : list2) { System.out.print(str + " "); } System.out.println(); } session.close();// 关闭session } } |
(2)Set集合映射
映射文件配置:
<class name="Student_set" table="students"> <id name="id"> <column name="id"></column> <generator /> </id> <property name="name" /> <property name="age" /> <set name="schools" table="schools"> <key column="student_id" not-null="true"></key> <element type="string" column="school_name"></element> </set> </class> |
实例化类如下:
package com.neusoft.test.entity;
import java.util.HashSet; import java.util.Set;
@SuppressWarnings("unchecked") public class Student_set { private int id; private String name; private int age; private Set<String> schools=new HashSet();
public Set<String> getSchools() { return schools; } public void setSchools(Set<String> schools) { this.schools = schools; } 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 int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
测试类如下:
package com.neusoft.test.action;
import java.util.HashSet; import java.util.List; import java.util.Set;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Student_set; import com.neusoft.test.utils.HibernateUtil;
public class TestSetStudent { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); Student_set student = new Student_set(); student.setAge(20); student.setName("mm"); Set set = new HashSet(); set.add("zxc1"); set.add("zxc2"); student.setSchools(set); session.save(student); tx.commit();// 提交事务
Query query = session.createQuery("from Student_set"); List<Student_set> list = query.list(); for (Student_set s : list) { System.out.print("id:" + s.getId() + " 姓名:" + s.getName() + " 年龄:" + s.getAge() + " 上过的学校:"); Set<String> list2 = s.getSchools(); for (String str : list2) { System.out.print(str + " "); } System.out.println(); } session.close();// 关闭session } } |
(3)Map集合属性
新建数据库表scores
映射文件配置:
<class name="Student_map" table="students"> <id name="id"> <column name="id"></column> <generator /> </id> <property name="name" /> <property name="age" /> <map name="scores" table="scores"> <key column="student_id" not-null="true"></key> <map-key type="string" column="course"></map-key> <element type="integer" column="score"></element> </map> </class> |
实例化类:
package com.neusoft.test.entity;
import java.util.HashMap; import java.util.Map;
@SuppressWarnings("unchecked") public class Student_map { private int id; private String name; private int age; private Map scores = new HashMap();
public Map getScores() { return scores; } public void setScores(Map scores) { this.scores = scores; } 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 int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
测试类:
package com.neusoft.test.action;
import java.util.HashMap; import java.util.List; import java.util.Map;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Student_map; import com.neusoft.test.utils.HibernateUtil;
public class TestMapStudent { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); Student_map student = new Student_map(); student.setAge(18); student.setName("yuiu"); Map map=new HashMap(); map.put("数学",85); map.put("语文",95); map.put("英语",89); student.setScores(map); session.save(student); tx.commit();// 提交事务
Query query = session.createQuery("from Student_map"); List<Student_map> list = query.list(); for (Student_map s : list) { System.out.print("id:" + s.getId() + " 姓名:" + s.getName() + " 年龄:" + s.getAge() + " 成绩:"); Map map1 = s.getScores();
// 第一种Map遍历 // Iterator it = map.entrySet().iterator(); // while (it.hasNext()) { // Map.Entry entry = (Map.Entry) it.next(); // Object key = entry.getKey(); // Object value = entry.getValue(); // System.out.print(key + ":" + value + " "); // }
// 第二种Map遍历 for (Object o : map1.keySet()) { System.out.print(o + ":" + map1.get(o) + " "); } // 第三种Map遍历 // for (Iterator i = map.keySet().iterator(); i.hasNext();) { // Object obj = i.next(); // System.out.print(obj +":" + map.get(obj) + " "); // } System.out.println(); } session.close();// 关闭session } } |
(4)映射组件属性
组件属性的意思是持久化类的属性既不是基本数据类型,也不是 String 字符串,而是某个组件变量,该组件属性的类型可以是自定义类。
显然无法直接用 property 映射 name 属性。为了映射组件属性, Hibernate 提供了 component 元素。每个 component 元素映射一个组件属性,组件属性必须指定该属性的类型,component 元素中的 class 属性用于确定组件的类型。
新建数据库表worker_table
映射文件配置:
<class name="Worker" table="worker_table"> <id name="id"> <column name="id"></column> <generator /> </id> <property name="age" /> <component name="name"> <property name="last" /> <property name="first" /> </component> </class> |
实例化类:
package com.neusoft.test.entity;
public class Worker { private int id; private int age; private Name name;
public Name getName() { return name; } public void setName(Name name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
辅助类:
package com.neusoft.test.entity;
public class Name { private String last; private String first;
public String getLast() { return last; } public void setLast(String last) { this.last = last; } public String getFirst() { return first; } public void setFirst(String first) { this.first = first; } } |
测试类:
package com.neusoft.test.action;
import java.util.List;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Name; import com.neusoft.test.entity.Worker; import com.neusoft.test.utils.HibernateUtil;
public class TestWorker { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); Worker worker=new Worker(); Name name= new Name(); name.setLast("Cloze"); name.setFirst("Tom"); worker.setAge(25); worker.setName(name); session.save(worker); tx.commit();// 提交事务
Query query = session.createQuery("from Worker"); List<Worker> worker1 = query.list(); for (Worker w : worker1) { System.out.println("id:" + w.getId() + " 姓名:" + w.getName().getLast() + " " + w.getName().getFirst() + " 年龄:" + w.getAge()); } session.close();// 关闭session }
} |
(5)集合组件属性映射
集合除了存放 String 字符串以外,还可以存放组件类型。实际上,更多情况下,集合组件存放的都是组件类型。
新建数据库表company_table
映射文件配置:
<class name="Worker2" table="worker_table"> <id name="id"> <column name="id"></column> <generator /> </id> <property name="age" /> <component name="name"> <property name="last" /> <property name="first" /> </component> <list name="company" table="company_table"> <key column="id" not-null="true"/> <list-index column="list_order"/> <composite-element> <property name="name"></property> <property name="address"></property> </composite-element> </list> </class> |
实例化类:
package com.neusoft.test.entity;
import java.util.ArrayList; import java.util.List;
@SuppressWarnings("unchecked") public class Worker2 { private int id; private int age; private Name name; private List<Company> company = new ArrayList();
public List<Company> getCompany() { return company; } public void setCompany(List<Company> company) { this.company = company; } public Name getName() { return name; } public void setName(Name name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
辅助类:
package com.neusoft.test.entity;
public class Company { private String name; private String address;
public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } |
测试类:
package com.neusoft.test.action;
import java.util.ArrayList; import java.util.List;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Company; import com.neusoft.test.entity.Name; import com.neusoft.test.entity.Worker2; import com.neusoft.test.utils.HibernateUtil;
public class TestWorkerAndCompany { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); List list = new ArrayList(); Worker2 worker=new Worker2(); worker.setAge(22); Name name= new Name(); name.setLast("Cloze"); name.setFirst("Tom"); worker.setName(name); Company company=new Company(); company.setName("aaa"); company.setAddress("aaaaaaaaaa"); list.add(company); Company company2=new Company(); company2.setName("bbbb"); company2.setAddress("bbbbbbbbbb"); list.add(company2); Company company3=new Company(); company3.setName("ccc"); company3.setAddress("ccccccc"); list.add(company3); worker.setCompany(list); session.save(worker); tx.commit();// 提交事务
Query query = session.createQuery("from Worker2"); List<Worker2> worker1 = query.list(); for (Worker2 w : worker1) { System.out.println("id:" + w.getId() + " 姓名:" + w.getName().getLast() + " " + w.getName().getFirst() + " 年龄:" + w.getAge() + " 工作过的公司:"); for(Company c :w.getCompany()){ System.out.println(c.getName()+" "+c.getAddress()); } System.out.println(); } session.close();// 关闭session } } |
2 、 关联关系映射
(1)单向 N-1
单向 N-1 关联只需从 N 的一端可以访问 1 的一端。模型:多个人(Person)对应同一个地址(Address)。只需要从人实体端找到相应的地址实体。无须关心从某个地址找到全部住户。
Person 端增加了 Address 属性,该属性不是一个普通的组件属性,而是引用了另外一个持久化类,使用 many-to-one 元素映射 N-1 的持久化属性。
many-to-one 元素的作用类似于 property 元素,用于映射持久化类的某个属性,区别是改元素映射的是关联持久化类。与 property 元素类似,many-to-one 元素也必须拥有 name 属性,用于确定该属性的名字,column 属性确定外键列的列名.
新建数据库表person_table
address_table
映射配置:
<class name="Person" table="person_table"> <id name="personid"> <column name="personid"></column> <generator /> </id> <property name="name" /> <property name="age" /> <!-- 多对一,column是Address在该表中的外键列名 --> <many-to-one name="address" column="addressid"></many-to-one> </class> <class name="Address" table="address_table"> <id name="addressid"> <column name="addressid"></column> <generator /> </id> <property name="addressdetail" /> </class> |
实例化类1:
package com.neusoft.test.entity;
public class Person { private int personid; private String name; private int age; private Address address;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } } |
实例化类2:
package com.neusoft.test.entity;
public class Address { private int addressid; private String addressdetail; private int personid;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public int getAddressid() { return addressid; } public void setAddressid(int addressid) { this.addressid = addressid; } public String getAddressdetail() { return addressdetail; } public void setAddressdetail(String addressdetail) { this.addressdetail = addressdetail; } } |
测试类:
package com.neusoft.test.action;
import java.util.List;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Address; import com.neusoft.test.entity.Person; import com.neusoft.test.utils.HibernateUtil;
public class AddManyToOne { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); Person person=new Person(); person.setName("aa"); person.setAge(22); Address address=new Address();
// 新建一个地址,然后添加给person address.setAddressdetail("wqesdasdasd"); person.setAddress(address); session.save(address);
// 直接添加已有的地址 // address.setAddressid(1); // person.setAddress(address);
session.save(person); tx.commit();// 提交事务
Query query = session.createQuery("from Person"); List<Person> list = query.list(); for (Person p : list) { System.out.println("id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge() + " 地址:" + p.getAddress().getAddressdetail()); } session.close();// 关闭session } } |
(2)基于外键的单向 1-1
单向 1-1,POJO 与 N-1 没有丝毫区别。
基于外键的单向 1-1 映射文件:只需要在原有的 many-to-one 元素添加 unique=“true”,用以表示 N 的一端必须唯一即可,N的一端增加了唯一约束, 即成为单向 1-1。
(3)基于主键的单向 1-1
基于主键关联的持久化类不能拥有自己的主键生成器,它的主键由关联类负责生成。增加one-to-one元素来映射关联属性,必须为one-to-one元素增加constrained="true"属性,表明该类的主键由关联类生成。
映射配置:
<class name="Person2" table="person_table"> <id name="personid"> <column name="personid"></column> <!-- 基于主键关联时,主键生成策略是foreign,表明根据关联类生成主键 --> <generator> <!-- 关联持久化类的属性名 --> <param name="property">address</param> </generator> </id> <property name="name" /> <property name="age" /> <!-- 关联映射 基于主键 1-1 --> <one-to-one name="address" constrained="true"></one-to-one> </class> <class name="Address" table="address_table"> <id name="addressid"> <column name="addressid"></column> <generator /> </id> <property name="addressdetail" /> </class> |
实例化类:
package com.neusoft.test.entity;
public class Person2 { private int personid; private String name; private int age; private Address address;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } } |
测试类:
package com.neusoft.test.action;
import java.util.List;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Address; import com.neusoft.test.entity.Person2; import com.neusoft.test.utils.HibernateUtil;
public class AddOneToOne { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); Person2 person=new Person2(); person.setName("aa"); person.setAge(22); Address address=new Address();
// 新建一个地址,然后添加给person address.setAddressdetail("wqesdasdasd"); person.setAddress(address); session.save(address);
session.save(person); tx.commit();// 提交事务
Query query = session.createQuery("from Person2"); List<Person2> list = query.list(); for (Person2 p : list) { System.out.println("id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge() + " 地址:" + p.getAddress().getAddressdetail()); } session.close();// 关闭session } } |
(4)单向的 1-N
单向 1-N 关联的 POJO 需要使用集合属性。因为一的一端需要访问 N 的一端,而 N 的一端将以集合的形式表现。
不推荐使用单向的 1-N 关联:使用 1 的一端控制关联关系时,会额外多出 update 语句。插入数据时无法同时插入外键列,因而无法为外键列添加非空约束
映射配置:
<class name="Person3" table="person_table"> <id name="personid"> <column name="personid"></column> <generator /> </id> <property name="name" /> <property name="age" /> <!-- 单向1-N --> <set name="address" table="address_table"> <key column="personid"></key> <one-to-many /> </set> </class> <class name="Address" table="address_table"> <id name="addressid"> <column name="addressid"></column> <generator /> </id> <property name="addressdetail" /> </class> |
实例化类:
package com.neusoft.test.entity;
import java.util.Set;
public class Person3 { private int personid; private String name; private int age; private Set<Address> address;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Set<Address> getAddress() { return address; } public void setAddress(Set<Address> address) { this.address = address; } } |
测试类:
package com.neusoft.test.action;
import java.util.HashSet; import java.util.List; import java.util.Set;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Address; import com.neusoft.test.entity.Person3; import com.neusoft.test.utils.HibernateUtil;
public class TestOneToMany{ @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); Person3 person=new Person3(); person.setName("gfg"); person.setAge(35); Set set=new HashSet();
Address address=new Address(); address.setAddressdetail("zxcvzxc"); session.save(address); set.add(address);
Address address2=new Address(); address2.setAddressdetail("esdasd"); session.save(address2); set.add(address2);
Address address3=new Address(); address3.setAddressid(105); set.add(address3); person.setAddress(set); session.save(person); tx.commit();// 提交事务
Query query = session.createQuery("from Person3"); List<Person3> list = query.list(); for (Person3 p : list) { System.out.println("id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge() + " 地址:" ); Set<Address> address1=p.getAddress(); for(Address a: address1){ System.out.println(a.getAddressdetail()); } } session.close();// 关闭session } } |
(5)单向的 N-N
与映射集合属性类似,必须为set,list等集合元素添加 key 子元素,用以映射关联的外键列。与集合映射不同的是,建立 N-N 关联时,集合中的元素使用 many-to-many,而不是使用 element 子元素
N-N 的关联必须使用连接表。
新建数据库表person_address_table
映射配置:
<class name="Person4" table="person_table"> <id name="personid"> <column name="personid"></column> <generator /> </id> <property name="name" /> <property name="age" /> <!-- 单向N-N --> <!-- person_address_table为额外的表,表列必须含有key对应的字段和elt,其中elt是固定的 --> <set name="address" table="person_address_table"> <key column="personid" /> <many-to-many/> </set> </class> <class name="Address" table="address_table"> <id name="addressid"> <column name="addressid"></column> <generator /> </id> <property name="addressdetail" /> </class> |
实例化类:
package com.neusoft.test.entity;
import java.util.Set;
public class Person4 { private int personid; private String name; private int age; private int addressid; private Set<Address> address;
public int getAddressid() { return addressid; } public void setAddressid(int addressid) { this.addressid = addressid; } public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Set<Address> getAddress() { return address; } public void setAddress(Set<Address> address) { this.address = address; } } |
测试类:
package com.neusoft.test.action;
import java.util.HashSet; import java.util.List; import java.util.Set;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Address; import com.neusoft.test.entity.Person4; import com.neusoft.test.utils.HibernateUtil;
public class TestManyToMany { @SuppressWarnings("unchecked") public static void main(String args[]) {
Address address1=new Address(); address1.setAddressdetail("zxcvzxc");
Address address2=new Address(); address2.setAddressdetail("esdasd");
Set set_address=new HashSet(); set_address.add(address1); set_address.add(address2);
Person4 person1=new Person4(); person1.setName("gfg"); person1.setAge(35); person1.setAddress(set_address);
Person4 person2=new Person4(); person2.setName("gfg"); person2.setAge(35); person2.setAddress(set_address);
Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction();
session.save(address1); session.save(address2); session.save(person1); session.save(person2);
tx.commit();// 提交事务
Query query = session.createQuery("from Person4"); List<Person4> list = query.list(); for (Person4 p : list) { System.out.println("id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge() + " 地址:" ); Set<Address> address=p.getAddress(); for(Address a: address){ System.out.println(a.getAddressdetail()); } } session.close();// 关闭session } } |
(6)双向 1-N和N-1
对于 1-N 的关联,Hibernate 推荐使用双向关联,而且不要让 1 的一端控制关联关系,而是使用 N 的一端控制关联关系。
双向 1-N 与 N-1 是完全相同的。
1 的一端需要使用集合属性元素来映射关联关系。集合属性元素同样需要增加 key 元素,还需要使用 one-to-many 元素来映射关联属性。
N 的一端需要增加 many-to-one 元素来映射关联属性。
映射配置:
<hibernate-mapping package="com.neusoft.test.entity"> <class name="Person" table="person_table"> <id name="personid"> <column name="personid"></column> <generator /> </id> <property name="name" /> <property name="age" /> <!-- 双向1-N(N-1) cascade级联关系 inverse=true:将控制权抛出(给双向的另一方) --> <set name="address" table="address_table" cascade="save-update" inverse="true"> <key column="personid"></key> <one-to-many/> </set> </class>
<class name="Address" table="address_table"> <id name="addressid"> <column name="addressid"></column> <generator /> </id> <property name="addressdetail" /> <many-to-one name="person" column="personid"></many-to-one> </class> </hibernate-mapping> |
注意:在上面的配置文件中,两个持久化类的配置文件都需要指定外键列的列名,此时不可以省略。因为不使用连接表的1-N关联的外键,而外键只保存在N一端的表中,如果两边指定的外键列名不同,将导致关联映射出错。如果不指定外键列的列名,该列名由系统自动生成,而系统很难保存自动生成的两个列名相同。
实例化类1:
package com.neusoft.test.entity;
import java.util.Set;
public class Person { private int personid; private String name; private int age; private Set<Address> address;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Set<Address> getAddress() { return address; } public void setAddress(Set<Address> address) { this.address = address; } } |
实例化类2:
package com.neusoft.test.entity;
public class Address { private int addressid; private String addressdetail; private Person person;
public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public int getAddressid() { return addressid; } public void setAddressid(int addressid) { this.addressid = addressid; } public String getAddressdetail() { return addressdetail; } public void setAddressdetail(String addressdetail) { this.addressdetail = addressdetail; } }
|
测试类:
package com.neusoft.test.action;
import java.util.HashSet; import java.util.List; import java.util.Set;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Address; import com.neusoft.test.entity.Person; import com.neusoft.test.utils.HibernateUtil;
public class test { @SuppressWarnings("unchecked") public static void main(String args[]) { Person person = new Person(); person.setName("ghgh"); person.setAge(33);
Address address = new Address(); address.setAddressdetail("gdsfasg"); address.setPerson(person);
Address address2 = new Address(); address2.setAddressdetail("rtyrtyt"); address2.setPerson(person);
Set set = new HashSet(); set.add(address); set.add(address2); person.setAddress(set);
Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); session.save(person); session.save(address); session.save(address2); tx.commit();// 提交事务
//从1的一段query Query query = session.createQuery("from Person"); List<Person> list = query.list(); for (Person p : list) { System.out.println("id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge() + " 地址:"); Set<Address> address1 = p.getAddress(); for (Address a : address1) { System.out.println(a.getAddressdetail()); } }
//从N的一段query Query query1 = session.createQuery("from Address"); List<Address> list1 = query1.list(); for (Address a : list1) { System.out .println(" 地址id:" + a.getAddressid() + " 详情:" + a.getAddressdetail() + " 人id:" + a.getPerson().getPersonid() + " 人名:" + a.getPerson().getName() + " 年龄:" + a.getPerson().getAge()); } session.close();// 关闭session } } |
(7)inverse
只有集合标记(set、map、list、array、bag)才有inverse属性。
在 Hibernate 中,inverse 指定了关联关系的方向。关联关系中 inverse = false 的为主动方,由主动方负责维护关联关系。
在没有设置 inverse=true 的情况下,父子两边都维护父子关系 。
在 1-N 关系中,将 many 方设为主控方(inverse = false) 将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多);若将 1 方设为主控方会额外多出 update 语句。插入数据时无法同时插入外键列,因而无法为外键列添加非空约束。
(8)cascade
只有关系标记才有cascade属性:many-to-one,one-to-one ,set(map, bag, idbag, list, array) + one-to-many(many-to-many)
级联指的是当主控方执行操作时,关联对象(被动方)是否同步执行同一操作。
pojo和它的关系属性的关系就是“主控方 -- 被动方”的关系,如果关系属性是一个set,那么被动方就是set中的每一个元素。一个操作因级联cascade可能触发多个关联操作。前一个操作叫“主控操作”,后一个操作叫“关联操作”。
inverse 指的是关联关系的控制方向,而cascade指的是层级之间的连锁操作。
cascade属性的可选值:
all : 所有情况下均进行关联操作。
none:所有情况下均不进行关联操作。这是默认值。
save-update:在执行save/update/saveOrUpdate时进行关联操作。
delete:在执行delete时进行关联操作
delete-orphan:表示删除孤儿,delete-orphan在前者的基础上增加了一点,针对持久化对象,如果它和它所关联的对象的引用关系不存在了,则进行级联删除。
all-delete-orphan:包含all和delete-orphan的行为
(9)双向N-N关联
双向N-N关联需要两端都使用集合属性,两端都增加对集合属性的访问。双向N-N关联也必须使用连接表。
双向N-N的关联映射需要在两边增加集合元素,用于映射集合属性。集合属性应增加key子元素用以映射外键列,集合元素里还应增加many-to-many子元素关联实体类
注意:在双向N-N关联的两边都需定连接表的表名及外键列的列名。两个集合元素set的table元素的值必须指定,而且必须相同。set元素的两个子元素:key和many-to-many都必须指定column属性,其中,key和many-to-many分别指定本持久化类和关联类在连接表中的外键列名,因
此两边的key与many-to-many的column属性交叉相同。也就是说,一边的set元素的key的cloumn值为a,many-to-many的column为b;则另一边的set元素的key的column值b,many-to-many的column值为a.
映射配置:
<class name="Person2" table="person_table"> <id name="personid"> <column name="personid"></column> <generator /> </id> <property name="name" /> <property name="age" /> <!-- 双向N-N --> <!-- person_address_table为额外的表,表列必须含有key对应的字段和elt,其中elt是固定的 --> <set name="address" table="person_address_table"> <key column="personid" /> <many-to-many column="addressid"/> </set> </class> <class name="Address2" table="address_table"> <id name="addressid"> <column name="addressid"></column> <generator /> </id> <property name="addressdetail" /> <!-- 双向N-N --> <!-- person_address_table为额外的表,表列必须含有key对应的字段和elt,其中elt是固定的 --> <set name="person" inverse="true" table="person_address_table"> <key column="addressid" /> <many-to-many column="personid"/> </set> </class> |
实例化类1:
package com.neusoft.test.entity;
import java.util.Set;
public class Person2 { private int personid; private String name; private int age; private Set<Address2> address;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Set<Address2> getAddress() { return address; } public void setAddress(Set<Address2> address) { this.address = address; } }
|
实例化类2:
package com.neusoft.test.entity;
import java.util.Set;
public class Address2 { private int addressid; private String addressdetail; private Set<Person2> person;
public Set<Person2> getPerson() { return person; } public void setPerson(Set<Person2> person) { this.person = person; } public int getAddressid() { return addressid; } public void setAddressid(int addressid) { this.addressid = addressid; } public String getAddressdetail() { return addressdetail; } public void setAddressdetail(String addressdetail) { this.addressdetail = addressdetail; } } |
测试类:
package com.neusoft.test.action;
import java.util.HashSet; import java.util.List; import java.util.Set;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Address2; import com.neusoft.test.entity.Person2; import com.neusoft.test.utils.HibernateUtil;
public class test2 { @SuppressWarnings("unchecked") public static void main(String args[]) {
Address2 address1 = new Address2(); address1.setAddressdetail("zxcvzxc");
Address2 address2 = new Address2(); address2.setAddressdetail("esdasd");
Person2 person1 = new Person2(); person1.setName("gfg"); person1.setAge(35);
Person2 person2 = new Person2(); person2.setName("gfg"); person2.setAge(35);
Set set_address = new HashSet(); set_address.add(address1); set_address.add(address2);
Set set_person = new HashSet(); set_person.add(person1); set_person.add(person2);
person1.setAddress(set_address); person2.setAddress(set_address); address1.setPerson(set_person); address2.setPerson(set_person);
Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction();
session.save(address1); session.save(address2); session.save(person1); session.save(person2);
tx.commit();// 提交事务
Query query = session.createQuery("from Person2"); List<Person2> list = query.list(); for (Person2 p : list) { System.out.println("id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge() + " 地址:"); Set<Address2> address = p.getAddress(); for (Address2 a : address) { System.out.println(a.getAddressdetail()); } }
Query query1 = session.createQuery("from Address2"); List<Address2> list1 = query1.list(); for (Address2 a : list1) { System.out.println(" 地址id:" + a.getAddressid() + " 地址详细:" + a.getAddressdetail()); Set<Person2> person = a.getPerson(); for (Person2 p : person) { System.out.println(" 人id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge()); } } session.close();// 关闭session } } |
(10)双向1-1关联
单向的1-1关联有三种映射策略:基于主键,基于外键和使用连接表。双向的1-1关联同样有这三种映射策略。
双向的1-1关联需要修改POJO类,让两边都增加对关联类的访问
基于外键的双向1-1关联
映射配置:
<!-- 双向1-1主实体 --> <class name="Person3" table="person_table"> <id name="personid"> <column name="personid"></column> <generator /> </id> <property name="name" /> <property name="age" /> <one-to-one name="address" cascade="all" property-ref="person"></one-to-one> </class> <!-- 双向1-1从属实体 --> <class name="Address3" table="address_table"> <id name="addressid"> <column name="addressid"></column> <generator /> </id> <property name="addressdetail" /> <!-- unique="true" 确定是双向的1-1 --> <many-to-one name="person" column="personid" unique="true"></many-to-one> </class> |
实例化类1:
package com.neusoft.test.entity;
public class Person3 { private int personid; private String name; private int age; private Address3 address;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Address3 getAddress() { return address; } public void setAddress(Address3 address) { this.address = address; } } |
实例化类2:
package com.neusoft.test.entity;
public class Address3 { private int addressid; private String addressdetail; private Person3 person;
public Person3 getPerson() { return person; } public void setPerson(Person3 person) { this.person = person; } public int getAddressid() { return addressid; } public void setAddressid(int addressid) { this.addressid = addressid; } public String getAddressdetail() { return addressdetail; } public void setAddressdetail(String addressdetail) { this.addressdetail = addressdetail; } } |
测试类:
package com.neusoft.test.action;
import java.util.List;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Address3; import com.neusoft.test.entity.Person3; import com.neusoft.test.utils.HibernateUtil;
@SuppressWarnings("unchecked") public class test3 { public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); Person3 person=new Person3(); person.setName("uytua"); person.setAge(28); Address3 address=new Address3();
// 新建一个地址,然后添加给person address.setAddressdetail("wqesdasdasd"); address.setPerson(person); person.setAddress(address);
session.save(address); session.save(person); tx.commit();// 提交事务
Query query = session.createQuery("from Person3"); List<Person3> list = query.list(); for (Person3 p : list) { System.out.println("id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge() + " 地址:" + p.getAddress().getAddressdetail()); } session.close();// 关闭session } } |
基于主键的双向1-1关联
基于主键的映射策略:指一端的主键生成器使用foreign略,表明根据对方的主键来生成自己的主键,自己并不能独立生成主键。
任意一边都可以采用foreign主键生成器,表明根据对方主键生成自己的主键。
采用foreign主键生成器策略的一端增加one-to-one元素映射关联属性,其one-to-one属性还应增加constrained=“true”属性;另一端增加one-to-one元素映射关联属性。
constrained(约束) :表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。
映射配置:
<!-- 基于主键的双向1-1关联 --> <class name="Person4" table="person_table"> <id name="personid"> <column name="personid"></column> <generator /> </id> <property name="name" /> <property name="age" /> <one-to-one name="address" cascade="all"></one-to-one> </class> <class name="Address4" table="address_table"> <id name="addressid"> <column name="addressid"></column> <generator> <param name="property">person</param> </generator> </id> <property name="addressdetail" /> <one-to-one name="person" constrained="true"></one-to-one> </class> |
实例化类1:
package com.neusoft.test.entity;
public class Person4 { private int personid; private String name; private int age; private Address4 address;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Address4 getAddress() { return address; } public void setAddress(Address4 address) { this.address = address; } } |
实例化类2:
package com.neusoft.test.entity;
public class Address4 { private int addressid; private String addressdetail; private Person4 person;
public Person4 getPerson() { return person; } public void setPerson(Person4 person) { this.person = person; } public int getAddressid() { return addressid; } public void setAddressid(int addressid) { this.addressid = addressid; } public String getAddressdetail() { return addressdetail; } public void setAddressdetail(String addressdetail) { this.addressdetail = addressdetail; } } |
测试类:
package com.neusoft.test.action;
import java.util.List;
import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Address4; import com.neusoft.test.entity.Person4; import com.neusoft.test.utils.HibernateUtil;
@SuppressWarnings("unchecked") public class test4 { public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction(); Person4 person=new Person4(); person.setName("uytua"); person.setAge(28); Address4 address=new Address4();
// 新建一个地址,然后添加给person address.setAddressdetail("wqesdasdasd"); address.setPerson(person); person.setAddress(address);
session.save(address); session.save(person); tx.commit();// 提交事务
Query query = session.createQuery("from Person4"); List<Person4> list = query.list(); for (Person4 p : list) { System.out.println("id:" + p.getPersonid() + " 姓名:" + p.getName() + " 年龄:" + p.getAge() + " 地址:" + p.getAddress().getAddressdetail()); } session.close();// 关闭session } } |
3 、继承映射
对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。Hibernate 的继承映射可以理解持久化类之间的继承关系。例如:人和学生之间的关系。学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。
Hibernate支持三种继承映射策略:
每个具体类一张表(table per concrete class) 将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系开数据模型中考虑域模型中的继承关系和多态。
每个类分层结构一张表(table per class hierarchy) 对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。
每个子类一张表(table per subclass) 域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。
( 1 ) subclass 继承映射 ( 单表继承 )
采用 subclass 元素的继承映射可以实现对于继承关系中的子类使用同一个表。(所有父类和子类都映射同一个表)
在这种映射策略下,整个继承树的所有实例都保保存在同一个表内。因为父类和子类的实例全部保存在同一个表中,因此需要在该表内增加一列,使用该列来区分每行记录到低是哪个类的实例----这个列被称为辨别者列(discriminator)。
在这种映射策略下,使用 subclass 来映射子类,使用 discriminator-value 指定辨别者列的值。
新建数据库表person_table
映射配置:
<hibernate-mapping package="com.neusoft.test.entity"> <class name="Person" table="person_table" lazy="false"> <id name="personid"> <generator /> </id> <discriminator column="type" type="string" /> <property name="name" /> <property name="age" /> <subclass name="Student" discriminator-value="Student"> <property name="school_name" /> </subclass> <subclass name="Worker" discriminator-value="Worker"> <property name="company_name" /> </subclass> </class> </hibernate-mapping> |
实体类1:
package com.neusoft.test.entity;
public class Person { private int personid; private String name; private int age;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
实体类2:
package com.neusoft.test.entity;
public class Student extends Person { private String school_name;
public String getSchool_name() { return school_name; } public void setSchool_name(String schoolName) { school_name = schoolName; } } |
实体类3:
package com.neusoft.test.entity;
public class Worker extends Person { private String company_name;
public String getCompany_name() { return company_name; } public void setCompany_name(String companyName) { company_name = companyName; } } |
测试类:
package com.neusoft.test.action;
import java.util.Iterator; import java.util.List;
import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Person; import com.neusoft.test.entity.Student; import com.neusoft.test.entity.Worker; import com.neusoft.test.utils.HibernateUtil;
public class test { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction();
Person person = new Person(); person.setName("小丽"); person.setAge(22); Student student = new Student(); student.setName("小明"); student.setAge(19); student.setSchool_name("清华"); Worker worker = new Worker(); worker.setName("小王"); worker.setAge(26); worker.setCompany_name("neusoft");
session.save(person); session.save(student); session.save(worker); tx.commit();// 提交事务
List personList = session.createQuery("from Person").list(); for (Iterator iter = personList.iterator(); iter.hasNext();) { Person a = (Person)iter.next(); System.out.print(" 姓名:"+a.getName()+" 年龄:"+a.getAge()+" 职业:"); //能够正确鉴别出正直的类型,HQL是支持多态查询的。 if (a instanceof Student) { System.out.print("Student"); Student s=(Student)a; System.out.println(" 学校:"+s.getSchool_name()); } else if (a instanceof Worker) { System.out.print("Worker"); Worker w=(Worker)a; System.out.println(" 公司:"+w.getCompany_name()); }else System.out.println("什么都不是"); }
// List list = session.createQuery("from java.lang.Object").list(); // for (Iterator iter = list.iterator(); iter.hasNext();){ // Object o =iter.next(); // if (o instanceof Student) { // Student s=(Student)o; // System.out.print(" 姓名:"+s.getName()+" 年龄:"+s.getAge()+" 职业:"); // System.out.print("Student"); // System.out.println(" 学校:"+s.getSchool_name()); // } else if (o instanceof Worker) { // Worker w=(Worker)o; // System.out.print(" 姓名:"+w.getName()+" 年龄:"+w.getAge()+" 职业:"); // System.out.print("Worker"); // System.out.println(" 公司:"+w.getCompany_name()); // }else{ // Person p=(Person)o; // System.out.print(" 姓名:"+p.getName()+" 年龄:"+p.getAge()+" 职业:"); // System.out.println("什么都不是"); // } // } session.close();// 关闭session } } |
( 2 ) joined-subclass 继承映射 (具体表继承)
采用 joined-subclass 元素的继承映射,每个类映射一个表。(父类映射一个表,每个子类也映射各自的表,子类表字段不是完全的)
对象模型不用变化,存储模型需要变化。
采用这种映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。
在这种映射策略下,无须使用鉴别者列,但需要为每个子类使用 key 元素映射共有主键,该主键必须与父类标识属性的列名相同。但如果继承树的深度很深,可能查询一个子类实例时,需要跨越多个表,因为子类的数据一次保存在多个父类中。
子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中
新建数据库表person_table
student_table
worker_table
映射配置:
<class name="Person2" table="person_table"> <id name="personid"> <generator/> </id> <property name="name" /> <property name="age" /> <!--<joined-subclass>标签:继承映射 每个类映射成一个表 --> <joined-subclass name="Student2" table="student_table"> <!-- <key>标签:会在相应的表(当前映射的表)里,加入一个外键 , 参照指向当前类的父类(当前Class标签对象的表)--> <key column="id"/> <property name="school_name"/> </joined-subclass> <joined-subclass name="Worker2" table="worker_table"> <key column="id"/> <property name="company_name"/> </joined-subclass> </class> |
实体类1:
package com.neusoft.test.entity;
public class Person2 { private int personid; private String name; private int age;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
实体类2:
package com.neusoft.test.entity;
public class Student2 extends Person2 { private String school_name;
public String getSchool_name() { return school_name; } public void setSchool_name(String schoolName) { school_name = schoolName; } } |
实体类3:
package com.neusoft.test.entity;
public class Worker2 extends Person2 { private String company_name;
public String getCompany_name() { return company_name; } public void setCompany_name(String companyName) { company_name = companyName; } } |
测试类:
package com.neusoft.test.action;
import java.util.Iterator; import java.util.List;
import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.*; import com.neusoft.test.utils.HibernateUtil;
public class test2 { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction();
Person2 person = new Person2(); person.setName("小丽"); person.setAge(22); Student2 student = new Student2(); student.setName("小明"); student.setAge(19); student.setSchool_name("清华"); Worker2 worker = new Worker2(); worker.setName("小王"); worker.setAge(26); worker.setCompany_name("neusoft");
session.save(person); session.save(student); session.save(worker); tx.commit();// 提交事务
List personList = session.createQuery("from Person2").list(); for (Iterator iter = personList.iterator(); iter.hasNext();) { Person2 a = (Person2)iter.next(); System.out.print(" 姓名:"+a.getName()+" 年龄:"+a.getAge()+" 职业:"); //能够正确鉴别出正直的类型,HQL是支持多态查询的。 if (a instanceof Student2) { System.out.print("Student"); Student2 s=(Student2)a; System.out.println(" 学校:"+s.getSchool_name()); } else if (a instanceof Worker2) { System.out.print("Worker"); Worker2 w=(Worker2)a; System.out.println(" 公司:"+w.getCompany_name()); }else System.out.println("什么都不是"); } session.close();// 关闭session } } |
采用 union-subclass 元素可以实现将每一个实体对象映射到一个独立的表中。(父类映射一个表,每个子类映射各自的表,子类表的字段是完全的)
union-subclass 与 joined-subclass 映射策略类似:子类增加的属性也可以有非空约束 --- 即父类实例的数据保存在父表中,而子类实例的数据保存在子类表中。
与 joined-subclass 不同的是,子类实例的数据仅保存在子类表中,而在父类表中没有任何记录。
在这种映射策略下,子类表的字段会比父类表的映射字段要多,因为子类表的字段等于父类表的字段加子类增加属性的总和
在这种映射策略下,既不需要使用鉴别者列,也无须使用 key 元素来映射共有主键.
新建数据库表person_table
student_table
worker_table
映射配置:
<class name="Person3" table="person_table"> <id name="personid"> <generator/> </id> <property name="name" /> <property name="age" /> <!-- 使用<union-subclass>标签来映射"每个具体类映射成一张表"的映射关系 --> <union-subclass name="Student3" table="student_table"> <property name="school_name"/> </union-subclass> <union-subclass name="Worker3" table="worker_table"> <property name="company_name"/> </union-subclass> </class> |
实体类1:
package com.neusoft.test.entity;
public class Person3 { private int personid; private String name; private int age;
public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
实体类2:
package com.neusoft.test.entity;
public class Student3 extends Person3 { private String school_name;
public String getSchool_name() { return school_name; } public void setSchool_name(String schoolName) { school_name = schoolName; } } |
实体类3:
package com.neusoft.test.entity;
public class Worker3 extends Person3 { private String company_name;
public String getCompany_name() { return company_name; } public void setCompany_name(String companyName) { company_name = companyName; } } |
测试类:
package com.neusoft.test.action;
import java.util.Iterator; import java.util.List;
import org.hibernate.Session; import org.hibernate.Transaction;
import com.neusoft.test.entity.Person3; import com.neusoft.test.entity.Student3; import com.neusoft.test.entity.Worker3; import com.neusoft.test.utils.HibernateUtil;
public class test3 { @SuppressWarnings("unchecked") public static void main(String args[]) { Session session = HibernateUtil.getSession(); // 开启事务 Transaction tx = session.beginTransaction();
Person3 person = new Person3(); person.setName("小丽"); person.setAge(22); Student3 student = new Student3(); student.setName("小明"); student.setAge(19); student.setSchool_name("清华"); Worker3 worker = new Worker3(); worker.setName("小王"); worker.setAge(26); worker.setCompany_name("neusoft");
session.save(person); session.save(student); session.save(worker); tx.commit();// 提交事务
List personList = session.createQuery("from Person3").list(); for (Iterator iter = personList.iterator(); iter.hasNext();) { Person3 a = (Person3)iter.next(); System.out.print(" 姓名:"+a.getName()+" 年龄:"+a.getAge()+" 职业:"); //能够正确鉴别出正直的类型,HQL是支持多态查询的。 if (a instanceof Student3) { System.out.print("Student"); Student3 s=(Student3)a; System.out.println(" 学校:"+s.getSchool_name()); } else if (a instanceof Worker3) { System.out.print("Worker"); Worker3 w=(Worker3)a; System.out.println(" 公司:"+w.getCompany_name()); }else System.out.println("什么都不是"); } session.close();// 关闭session } } |
(4)三种继承关联映射的比较:
1、 第一种:它把所有的数据都存入一个表中,优点:效率好(操作的就是一个表);缺点:存在庸于字段,如果将庸于字段设置为非空,则就无法存入数据;
2、 第二种:层次分明,缺点:效率不好(表间存在关联表)
3、 第三种:主键字段不可以设置为自增主键生成策略。
建议使用第一种