hibernate环境配置:导包。。。。
单向n-1:单向 n-1 关联只需从 n 的一端可以访问 1 的一端
<many-to-one> 元素来映射组成关系:
name: 设定待映射的持久化类的属性的名字
column: 设定和持久化类的属性对应的表的外键
class:设定待映射的持久化类的属性的类型
建立1所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer customerId;private String customerName;
建立n所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer orderId;private String orderName;private Customer customer;
在该包下建立上面 封装类对应的 hibernate映射文件Hibernate XML Mapping file(hbm.xml):Customer.hbm.xml,Order.hbm.xml;
在src目录下,建立 hibernate.cfg.xml配置文件;
root lxn123 com.mysql.jdbc.Driver jdbc:mysql:///hibernate4 org.hibernate.dialect.MySQLInnoDBDialect true true update 2 true 10 5 2 2000 2000 10 100 30
建立测试类,进行测试:
package com.atguigu.hibernate.test;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.hibernate.service.ServiceRegistry;import org.hibernate.service.ServiceRegistryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import com.atguigu.hibernate.one2many.Customer;import com.atguigu.hibernate.one2many.Order;import com.mysql.jdbc.Connection;public class HibernateTest { private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void init(){ Configuration configuration=new Configuration().configure(); ServiceRegistry serviceRegistry= new ServiceRegistryBuilder().applySettings(configuration.getProperties()) .buildServiceRegistry(); sessionFactory=configuration.buildSessionFactory(serviceRegistry); session=sessionFactory.openSession(); transaction=session.beginTransaction(); } @After public void destroy(){ transaction.commit(); session.close(); sessionFactory.close(); } @Test public void testDelect(){ //在不设定级联关系的情况下, 且 1 这一端的对象有 n 的对象在引用, 不能直接删除 1 这一端的对象 Customer customer=(Customer) session.get(Customer.class, 1); session.delete(customer); } public void testUpdate(){ Order order=(Order) session.get(Order.class, 3); order.getCustomer().setCustomerName("AAAAAA"); } public void many2oneTget(){ //1. 若查询多的一端的一个对象, 则默认情况下, 只查询了多的一端的对象. 而没有查询关联的 //1 的那一端的对象! Order order=(Order) session.get(Order.class, 3); System.out.println(order.getOrderName()); System.out.println(order.getCustomer().getClass().getName()); Customer customer=(Customer) session.get(Customer.class, 1); System.out.println(customer.getCustomerName()); } public void many2OneTsave(){ Customer customer = new Customer(); customer.setCustomerName("panpan"); Order order= new Order(); order.setOrderName("ggg"); Order order2=new Order(); order2.setOrderName("drrr"); //设定关联关系 order.setCustomer(customer); order2.setCustomer(customer); session.save(order); session.save(order2); session.save(customer); }}
-------------------------------------------------------------------------------------
双向 1-n:
双向 1-n 与 双向 n-1 是完全相同的两种情形
双向 1-n 需要在 1 的一端可以访问 n 的一端, 反之依然
<set> 元素来映射持久化类的 set 类型的属性: name: 设定待映射的持久化类的属性
<key> 元素设定与所关联的持久化类对应的表的外键 :column: 指定关联表的外键名
<one-to-many> 元素设定集合属性中所关联的持久化类: class: 指定关联的持久化类的类名
建立1所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer customerId;private String customerName; /** 1. 声明集合类型时, 需使用接口类型, 因为 hibernate 在获取* 集合类型时, 返回的是 Hibernate 内置的集合类型, 而不是 JavaSE 一个标准的* 集合实现. * 2. 需要把集合进行初始化, 可以防止发生空指针异常*/private Setorders=new HashSet ();
建立n所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer orderId;private String orderName;private Customer customer;
在该包下建立上面 封装类对应的 hibernate映射文件Hibernate XML Mapping file(hbm.xml):Customer.hbm.xml,Order.hbm.xml;
配置文件上边有,必须配置 需要关联的hibernate关联文件;
建立测试类,进行测试:这儿只写测试方法,sessionFactory等,就不写了,上边的测试类中有;
@Test public void testDelete(){ //在不设定级联关系的情况下, 且 1 这一端的对象有 n 的对象在引用, 不能直接删除 1 这一端的对象 Customer customer = (Customer) session.get(Customer.class, 1); session.delete(customer); } @Test public void testUpdat2(){ Customer customer = (Customer) session.get(Customer.class, 1); customer.getOrders().iterator().next().setOrderName("GGG"); } @Test public void testUpdate(){ Order order = (Order) session.get(Order.class, 1); order.getCustomer().setCustomerName("AAA"); } @Test public void testOne2ManyGet(){ //1. 对 n 的一端的集合使用延迟加载 Customer customer = (Customer) session.get(Customer.class, 7); System.out.println(customer.getCustomerName()); //2. 返回的多的一端的集合时 Hibernate 内置的集合类型. //该类型具有延迟加载和存放代理对象的功能. System.out.println(customer.getOrders().getClass()); //session.close(); //3. 可能会抛出 LazyInitializationException 异常 System.out.println(customer.getOrders().size()); //4. 再需要使用集合中元素的时候进行初始化. } @Test public void testMany2OneGet(){ //1. 若查询多的一端的一个对象, 则默认情况下, 只查询了多的一端的对象. 而没有查询关联的 //1 的那一端的对象! Order order = (Order) session.get(Order.class, 1); System.out.println(order.getOrderName()); System.out.println(order.getCustomer().getClass().getName()); session.close(); //2. 在需要使用到关联的对象时, 才发送对应的 SQL 语句. Customer customer = order.getCustomer(); System.out.println(customer.getCustomerName()); //3. 在查询 Customer 对象时, 由多的一端导航到 1 的一端时, //若此时 session 已被关闭, 则默认情况下 //会发生 LazyInitializationException 异常 //4. 获取 Order 对象时, 默认情况下, 其关联的 Customer 对象是一个代理对象! } public void testBoth(){ Customer customer=new Customer(); Order order=new Order(); Order order2=new Order(); customer.setCustomerName("AAAAA"); order.setOrderName("aaaaa"); order2.setOrderName("bbbbb"); //设定关联关系 order.setCustomer(customer); order2.setCustomer(customer); customer.getOrders().add(order); customer.getOrders().add(order2); session.save(customer); session.save(order); session.save(order2); }
------------------------------------------------------------------------------------
基于外键映射的 1-1:
对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素。为many-to-one元素增加unique=“true” 属性来表示为1-1关联
另一端需要使用one-to-one元素,该元素使用 property-ref 属性指定使用被关联实体主键以外的字段作为关联字段
建立一个 1所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer manId;private String manName; private Department dep;
建立另外一个 1所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer depId;private String depName; private Manager man;
在该包下建立上面 封装类对应的 hibernate映射文件Hibernate XML Mapping file(hbm.xml):
配置文件上边有,必须配置 需要关联的hibernate关联文件;
建立测试类,进行测试:这儿只写测试方法,sessionFactory等,就不写了,上边的测试类中有;
@Test public void testGet2(){ //在查询没有外键的实体对象时, 使用的左外连接查询, 一并查询出其关联的对象 //并已经进行初始化. Manager mgr = (Manager) session.get(Manager.class, 1); System.out.println(mgr.getManName()); System.out.println(mgr.getDep().getDepId()); } @Test public void testGet(){ //1. 默认情况下对关联属性使用懒加载 Department dept = (Department) session.get(Department.class, 1); System.out.println(dept.getDepName()); //2. 所以会出现懒加载异常的问题. // session.close();// Manager mgr = dept.getMgr();// System.out.println(mgr.getClass()); // System.out.println(mgr.getMgrName()); //3. 查询 Manager 对象的连接条件应该是 dept.manager_id = mgr.manager_id //而不应该是 dept.dept_id = mgr.manager_id Manager mgr = dept.getMan(); System.out.println(mgr.getManName()); } @Test public void testone2onesave(){ Department department=new Department(); Manager manager=new Manager(); department.setDepName("AAAAA"); manager.setManName("aaaaaa"); //设定关联关系 department.setMan(manager); manager.setDep(department); //保存操作 //建议先保存没有外键列的那个对象. 这样会减少 UPDATE 语句 session.save(manager); session.save(department); }
------------------------------------------------------------------------------------
基于主键映射的 1-1:
基于主键的映射策略:指一端的主键生成器使用 foreign 策略,表明根据”对方”的主键来生成自己的主键,自己并不能独立生成主键. <param> 子元素指定使用当前持久化类的哪个属性作为 “对方”;
采用foreign主键生成器策略的一端增加 one-to-one 元素映射关联属性,其one-to-one属性还应增加 constrained=“true” 属性;另一端增加one-to-one元素映射关联属性。 constrained(约束):指定为当前持久化类对应的数据库表的主键添加一个外键约束,引用被关联的对象(“对方”)所对应的数据库表主键
建立一个 1所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer depId;private String depName; private Manager man;
建立另一个 1所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer manId;private String manName; private Department dep;
在该包下建立上面 封装类对应的 hibernate映射文件Hibernate XML Mapping file(hbm.xml):
man
配置文件上边有,必须配置 需要关联的hibernate关联文件;
建立测试类,进行测试:这儿只写测试方法,sessionFactory等,就不写了,上边的测试类中有;
@Test public void testGet2(){ //在查询没有外键的实体对象时, 使用的左外连接查询, 一并查询出其关联的对象 //并已经进行初始化. Manager mgr = (Manager) session.get(Manager.class, 1); System.out.println(mgr.getManName()); System.out.println(mgr.getDep().getDepId()); } @Test public void testGet(){ //1. 默认情况下对关联属性使用懒加载 Department dept = (Department) session.get(Department.class, 1); System.out.println(dept.getDepId()); //2. 所以会出现懒加载异常的问题. Manager mgr = dept.getMan(); System.out.println(mgr.getManName()); } @Test public void testSave(){ Department department = new Department(); department.setDepName("DEPT-DD"); Manager manager = new Manager(); manager.setManName("MGR-DD"); //设定关联关系 manager.setDep(department); department.setMan(manager); //保存操作 //先插入哪一个都不会有多余的 UPDATE session.save(department); session.save(manager); }
------------------------------------------------------------------------------------
n-n:
单向n-n 的关联必须使用连接表 与 1-n 映射类似,必须为 set 集合元素添加 key 子元素,指定 CATEGORIES_ITEMS 表中参照 CATEGORIES 表的外键为 CATEGORIY_ID. 与 1-n 关联映射不同的是,建立 n-n 关联时, 集合中的元素使用 many-to-many. many-to-many 子元素的 class 属性指定 items 集合中存放的是 Item 对象, column 属性指定 CATEGORIES_ITEMS 表中参照 ITEMS 表的外键为 ITEM_ID
双向 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. 对于双向 n-n 关联, 必须把其中一端的 inverse 设置为 true, 否则两端都维护关联关系可能会造成主键冲突
这儿只写双向n-n;
建立一个n所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer id;private String name; private Set- items=new HashSet
- ();
建立另一个n所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer id;private String name; private Setcategorys=new HashSet ();
在该包下建立上面 封装类对应的 hibernate映射文件Hibernate XML Mapping file(hbm.xml):
配置文件上边有,必须配置 需要关联的hibernate关联文件;
建立测试类,进行测试:这儿只写测试方法,sessionFactory等,就不写了,上边的测试类中有;
@Test public void testGet(){ Category category = (Category) session.get(Category.class, 1); System.out.println(category.getName()); //需要连接中间表 Set- items = category.getItems(); System.out.println(items.size()); } @Test public void testSave(){ Category category1 = new Category(); category1.setName("C-AA"); Category category2 = new Category(); category2.setName("C-BB"); Item item1 = new Item(); item1.setName("I-AA"); Item item2 = new Item(); item2.setName("I-BB"); //设定关联关系 category1.getItems().add(item1); category1.getItems().add(item2); category2.getItems().add(item1); category2.getItems().add(item2); item1.getCategorys().add(category1); item1.getCategorys().add(category2); item2.getCategorys().add(category1); item2.getCategorys().add(category2); //执行保存操作 session.save(category1); session.save(category2); session.save(item1); session.save(item2); }
------------------------------------------------------------------------------------
映射继承关系:
对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。Hibernate 的继承映射可以理解持久化类之间的继承关系。例如:人和学生之间的关系。学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。
Hibernate支持三种继承映射策略:
使用 subclass 进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态。
使用 joined-subclass 进行映射: 对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。
使用 union-subclass 进行映射:域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。
采用 subclass 元素的继承映射:
采用 subclass 的继承映射可以实现对于继承关系中父类和子类使用同一张表;
因为父类和子类的实例全部保存在同一个表中,因此需要在该表内增加一列,使用该列来区分每行记录到低是哪个类的实例----这个列被称为辨别者列(discriminator);
使用 subclass 来映射子类,使用 class 或 subclass 的 discriminator-value 属性指定辨别者列的值 所有子类定义的字段都不能有非空约束。
建立父类所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer id;private String name;private int age;
建立子类所对应的封装类,子类继承父类person
package com.atguigu.hibernate.subclass;public class Student extends Person{ private String school; public String getSchool() { return school; } public void setSchool(String school) { this.school = school; } }
在该包下建立上面 封装类对应的 hibernate映射文件Hibernate XML Mapping file(hbm.xml):
配置文件上边有,必须配置 需要关联的hibernate关联文件;
建立测试类,进行测试:这儿只写测试方法,sessionFactory等,就不写了,上边的测试类中有;
/** * 缺点: * 1. 使用了辨别者列. * 2. 子类独有的字段不能添加非空约束. * 3. 若继承层次较深, 则数据表的字段也会较多. */ /** * 查询: * 1. 查询父类记录, 只需要查询一张数据表 * 2. 对于子类记录, 也只需要查询一张数据表 */ @Test public void testQuery(){ Listpersons = session.createQuery("FROM Person").list(); System.out.println(persons.size()); List stus = session.createQuery("FROM Student").list(); System.out.println(stus.size()); } /** * 插入操作: * 1. 对于子类对象只需把记录插入到一张数据表中. * 2. 辨别者列有 Hibernate 自动维护. */ @Test public void testSave(){ Person person = new Person(); person.setAge(11); person.setName("AA"); session.save(person); Student stu = new Student(); stu.setAge(22); stu.setName("BB"); stu.setSchool("ATGUIGU"); session.save(stu); }
采用 joined-subclass 元素的继承映射:
采用 joined-subclass 元素的继承映射可以实现每个子类一张表 采用这种映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。
在这种映射策略下,无须使用鉴别者列,但需要为每个子类使用 key 元素映射共有主键。
子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中;
建立父类所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer id;private String name;private int age;
建立子类所对应的封装类,子类继承父类person
package com.atguigu.hibernate.joined.subclass;public class Student extends Person{ private String school; public String getSchool() { return school; } public void setSchool(String school) { this.school = school; } }
在该包下建立上面 封装类对应的 hibernate映射文件Hibernate XML Mapping file(hbm.xml):
配置文件上边有,必须配置 需要关联的hibernate关联文件;
建立测试类,进行测试:这儿只写测试方法,sessionFactory等,就不写了,上边的测试类中有;
/** * 优点: * 1. 不需要使用了辨别者列. * 2. 子类独有的字段能添加非空约束. * 3. 没有冗余的字段. */ /** * 查询: * 1. 查询父类记录, 做一个左外连接查询 * 2. 对于子类记录, 做一个内连接查询. */ @Test public void testQuery(){ Listpersons = session.createQuery("FROM Person").list(); System.out.println(persons.size()); List stus = session.createQuery("FROM Student").list(); System.out.println(stus.size()); } /** * 插入操作: * 1. 对于子类对象至少需要插入到两张数据表中. */ @Test public void testSave(){ Person person = new Person(); person.setAge(11); person.setName("AA"); session.save(person); Student stu = new Student(); stu.setAge(22); stu.setName("BB"); stu.setSchool("ATGUIGU"); session.save(stu); }
采用 union-subclass 元素的继承映射:
采用 union-subclass 元素可以实现将每一个实体对象映射到一个独立的表中。
子类增加的属性可以有非空约束 --- 即父类实例的数据保存在父表中,而子类实例的数据保存在子类表中。
子类实例的数据仅保存在子类表中, 而在父类表中没有任何记录
在这种映射策略下,子类表的字段会比父类表的映射字段要多,因为子类表的字段等于父类表的字段、加子类增加属性的总和;
在这种映射策略下,既不需要使用鉴别者列,也无须使用 key 元素来映射共有主键.
使用 union-subclass 映射策略是不可使用 identity 的主键生成策略, 因为同一类继承层次中所有实体类都需要使用同一个主键种子, 即多个持久化实体对应的记录的主键应该是连续的. 受此影响, 也不该使用 native 主键生成策略, 因为 native 会根据数据库来选择使用 identity 或 sequence.
建立父类所对应的封装类,这儿只写属性,setter和getter就不写了;
private Integer id;private String name;private int age;
建立子类所对应的封装类,子类继承父类person
package com.atguigu.hibernate.joined.subclass;public class Student extends Person{ private String school; public String getSchool() { return school; } public void setSchool(String school) { this.school = school; } }
在该包下建立上面 封装类对应的 hibernate映射文件Hibernate XML Mapping file(hbm.xml):
配置文件上边有,必须配置 需要关联的hibernate关联文件;
建立测试类,进行测试:这儿只写测试方法,sessionFactory等,就不写了,上边的测试类中有;
@Test public void testUpdate(){ String hql = "UPDATE Person p SET p.age = 20"; session.createQuery(hql).executeUpdate(); } /** * 优点: * 1. 无需使用辨别者列. * 2. 子类独有的字段能添加非空约束. * * 缺点: * 1. 存在冗余的字段 * 2. 若更新父表的字段, 则更新的效率较低 */ /** * 查询: * 1. 查询父类记录, 需把父表和子表记录汇总到一起再做查询. 性能稍差. * 2. 对于子类记录, 也只需要查询一张数据表 */ @Test public void testQuery(){ Listpersons = session.createQuery("FROM Person").list(); System.out.println(persons.size()); List stus = session.createQuery("FROM Student").list(); System.out.println(stus.size()); } /** * 插入操作: * 1. 对于子类对象只需把记录插入到一张数据表中. */ @Test public void testSave(){ Person person = new Person(); person.setAge(11); person.setName("AA"); session.save(person); Student stu = new Student(); stu.setAge(22); stu.setName("BB"); stu.setSchool("ATGUIGU"); session.save(stu); }