hibernate核心,一对多,多对多映射讲解,看了就完全搞明白了
- 格式:ppt
- 大小:3.12 MB
- 文档页数:30
2015年10月12日Hibernate笔记----Day4映射文件总结:(多对一、一对多、一对一、多对多)多对一:新建项目---引包---加包1、编写Java类,指明属性,生成get和set方法1)将n的一端类名属性加到1的一端。
2)1的一端无变化。
2、生成配置文件*.hbm.xml1)选中Java文件右键---new----other----"输入Hibernate"---选择Hibernate XML Maping2) 改:generator class="native"3)1的一端无变化,n的一端加入many-to-one如:<many-to-one name="customer"class="qjnu.wdw.day3.Customer"><column name="CUSTOMER_RK" /></many-to-one>(其中,name 必须与Customer.java中属性一致)3、添加关联的hibernate 映射文件*.hbm.xml如:<mapping resource="qjnu/wdw/day3/Customer.hbm.xml"/>4、测试类中先保存1的一端,再保存n的一端。
一对多:新建项目---引包---加包1、编写Java类,指明属性,生成get和set方法1)将n的一端类名属性加到1的一端。
2)1的一端加入n端的集合属性。
例如:private Set<Order> orders = new HashSet<>();2、生成配置文件*.hbm.xml1)选中Java文件右键---new----other----"输入Hibernate"---选择Hibernate XML Maping2) 改:generator class="native"3)1的一端加入one-to-many如:<set name="orders" table="ORDERS" inverse="true" cascade="all"> <key column="CUSTOMER"></key><one-to-many qjnu.wdw.day3.Order/></set>(其中,name 属性保持一致)n的一端加入many-to-one如:<many-to-one name="customer" class="qjnu.wdw.day3.Customer" ><column name="CUSTOMER" /></many-to-one>3、添加关联的hibernate 映射文件*.hbm.xml如:<mapping resource="qjnu/wdw/day3/Customer.hbm.xml"/>4、测试类中先保存1的一端,再保存n的一端。
Hibernate(6)——一对多和多对多关联关系映射(xml和注解)总结涉及的知识点总结如下:∙One to Many 映射关系o多对一单向外键关联(XML/Annotation)o一对多单向外键关联(XML/Annotation)o懒加载和积极加载o一对多双向外键关联(XML/Annotation)∙Many to Many 映射关系o多对多单向外键关联(XML/Annotation)o多对多双向外键关联(XML/Annotation)o set的inverse元素详解∙问题小结∙关联关系的优缺点多对一单向外键关联关系注意多对一关联是多方持有一方的引用。
看一个例子,去淘宝购物,那么一个淘宝用户可以对应多个购物订单,如图所示:多的一方是Orders,持有一方的引用,也就是Users,而在Users中无需作任何定义,从订单到用户的关系是单向多对一关联。
对应数据库就是:还有比如说学生和班级的关系,多个学生可以属于同一个班级,这就是从学生到班级也是典型的单向多对一关系,看代码实现:基于注解的多对一单向外键关联:单向多对一关联中,多方需要持有一方的引用,那么多方(学生类)需要额外配置,需要对持有的一方引用使用注解@ManyToOne (cascade={CascadeType.ALL}, fetch=FetchType.EAGER),设置为级联操作和饥渴的抓取策略,@JoinColumn(name="cid"),而一方(教室类)无需做任何多方的定义。
注意;多方必须保留一个不带参数的构造器!importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persistence.Id;//班级类,在多对一关系中属于一的方,不持有其他多余的配置,反而是被多方持有@Entitypublic class ClassRoom {private intcid;//班级编号private String cname;//班级名称// 自动增长的主键@Id@GeneratedValuepublicintgetCid() {returncid;}public void setCid(intcid) {this.cid = cid;}public String getCname() {returncname;}public void setCname(String cname) {ame = cname;}}View Code一方——班级类无需做多余的定义,下面是多方——学生实体和配置:importjavax.persistence.CascadeType;importjavax.persistence.Entity;importjavax.persistence.FetchType;importjavax.persistence.GeneratedValue;importjavax.persistence.Id;importjavax.persistence.JoinColumn;importjavax.persistence.ManyToOne;//学生实体类,属于多对一的多方,持有班级(一方)的引用@Entitypublic class Students {private intsid; //编号private String sname; //姓名private ClassRoom classroom;//学生班级//注意:多方一定要显式的定义不带参数的构造方法public Students() {}public Students(String sname){this.sname = sname;}// 多方使用注解:@ManyToOne// fetch=FetchType.EAGER,急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。
Hibernate教程---看这⼀篇就够了1 Hibernate概述1.1什么是hibernate框架(重点)1 hibernate框架应⽤在javaee三层结构中 dao层框架2 在dao层⾥⾯做对数据库crud操作,使⽤hibernate实现crud操作,hibernate底层代码就是jdbc,hibernate对jdbc进⾏封装,使⽤hibernate好处,不需要写复杂jdbc代码了,不需要写sql语句实现3 hibernate开源的轻量级的框架4 hibernate版本Hibernate3.xHibernate4.xHibernate5.x(学习)1.2 什么是orm思想(重点)1 hibernate使⽤orm思想对数据库进⾏crud操作2 在web阶段学习 javabean,更正确的叫法实体类3 orm:object relational mapping,对象关系映射⽂字描述:(1)让实体类和数据库表进⾏⼀⼀对应关系让实体类⾸先和数据库表对应让实体类属性和表⾥⾯字段对应(2)不需要直接操作数据库表,⽽操作表对应实体类对象画图描述2 Hibernate⼊门2.1 搭建hibernate环境(重点)第⼀步导⼊hibernate的jar包因为使⽤hibernate时候,有⽇志信息输出,hibernate本⾝没有⽇志输出的jar包,导⼊其他⽇志的jar包不要忘记还有mysql驱动的jar包第⼆步创建实体类package cn.itcast.entity;public class User {/*hibernate要求实体类有⼀个属性唯⼀的*/// private int uid;private String uid;private String username;private String password;private String address;// public int getUid() {// return uid;// }// public void setUid(int uid) {// this.uid = uid;// }public String getUsername() {return username;}public String getUid() {return uid;}public void setUid(String uid) {this.uid = uid;}public void setUsername(String username) {ername = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}}(1)使⽤hibernate时候,不需要⾃⼰⼿动创建表,hibernate帮把表创建第三步配置实体类和数据库表⼀⼀对应关系(映射关系)使⽤配置⽂件实现映射关系(1)创建xml格式的配置⽂件- 映射配置⽂件名称和位置没有固定要求- 建议:在实体类所在包⾥⾯创建,实体类名称.hbm.xml(2)配置是是xml格式,在配置⽂件中⾸先引⼊xml约束- 学过约束dtd、schema,在hibernate⾥⾯引⼊的约束dtd约束(3)配置映射关系<hibernate-mapping><!-- 1 配置类和表对应class标签name属性:实体类全路径table属性:数据库表名称--><class name="er" table="t_user"><!-- 2 配置实体类id和表id对应hibernate要求实体类有⼀个属性唯⼀值hibernate要求表有字段作为唯⼀值--><!-- id标签name属性:实体类⾥⾯id属性名称column属性:⽣成的表字段名称--><id name="uid" column="uid"><!-- 设置数据库表id增长策略native:⽣成表id值就是主键⾃动增长--><generator class="native"></generator></id><!-- 配置其他属性和表字段对应name属性:实体类属性名称column属性:⽣成表字段名称--><property name="username" column="username"></property><property name="password" column="password"></property><property name="address" column="address"></property></class></hibernate-mapping>第四步创建hibernate的核⼼配置⽂件(1)核⼼配置⽂件格式xml,但是核⼼配置⽂件名称和位置固定的- 位置:必须src下⾯- 名称:必须hibernate.cfg.xml(2)引⼊dtd约束(3)hibernate操作过程中,只会加载核⼼配置⽂件,其他配置⽂件不会加载第⼀部分:配置数据库信息必须的第⼆部分:配置hibernate信息可选的第三部分:把映射⽂件放到核⼼配置⽂件中<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- 第⼀部分:配置数据库信息必须的 --><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql:///hibernate_day01</property> <property name="ername">root</property><property name="hibernate.connection.password">root</property><!-- 第⼆部分:配置hibernate信息可选的--><!-- 输出底层sql语句 --><property name="hibernate.show_sql">true</property><!-- 输出底层sql语句格式 --><property name="hibernate.format_sql">true</property><!-- hibernate帮创建表,需要配置之后update: 如果已经有表,更新,如果没有,创建--><property name="hibernate.hbm2ddl.auto">update</property><!-- 配置数据库⽅⾔在mysql⾥⾯实现分页关键字 limit,只能使⽤mysql⾥⾯在oracle数据库,实现分页rownum让hibernate框架识别不同数据库的⾃⼰特有的语句--><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><!-- 第三部分:把映射⽂件放到核⼼配置⽂件中必须的--><mapping resource="cn/itcast/entity/User.hbm.xml"/></session-factory></hibernate-configuration>2.2 实现添加操作第⼀步加载hibernate核⼼配置⽂件第⼆步创建SessionFactory对象第三步使⽤SessionFactory创建session对象第四步开启事务第五步写具体逻辑 crud操作第六步提交事务第七步关闭资源@Testpublic void testAdd() {// 第⼀步加载hibernate核⼼配置⽂件// 到src下⾯找到名称是hibernate.cfg.xml//在hibernate⾥⾯封装对象Configuration cfg = new Configuration();cfg.configure();// 第⼆步创建SessionFactory对象//读取hibernate核⼼配置⽂件内容,创建sessionFactory//在过程中,根据映射关系,在配置数据库⾥⾯把表创建SessionFactory sessionFactory = cfg.buildSessionFactory(); // 第三步使⽤SessionFactory创建session对象// 类似于连接Session session = sessionFactory.openSession();// 第四步开启事务Transaction tx = session.beginTransaction();// 第五步写具体逻辑 crud操作//添加功能User user = new User();user.setUsername("⼩王");user.setPassword("250");user.setAddress("⽇本");//调⽤session的⽅法实现添加session.save(user);// 第六步提交事务mit();// 第七步关闭资源session.close();sessionFactory.close();}3 内容⽬录1 实体类编写规则2 hibernate主键⽣成策略(1)native(2)uuid3 实体类操作(1)crud操作(2)实体类对象状态4 hibernate的⼀级缓存5 hibernate的事务操作(1)事务代码规范写法6 hibernate其他的api(查询)(1)Query(2)Criteria(3)SQLQuery3.1 实体类编写规则1 实体类⾥⾯属性私有的2 私有属性使⽤公开的set和get⽅法操作3 要求实体类有属性作为唯⼀值(⼀般使⽤id值)4 实体类属性建议不使⽤基本数据类型,使⽤基本数据类型对应的包装类(1)⼋个基本数据类型对应的包装类- int – Integer- char—Character、- 其他的都是⾸字母⼤写⽐如 double – Double(2)⽐如表⽰学⽣的分数,假如 int score;- ⽐如学⽣得了0分,int score = 0;- 如果表⽰学⽣没有参加考试,int score = 0;不能准确表⽰学⽣是否参加考试l 解决:使⽤包装类可以了, Integer score = 0,表⽰学⽣得了0分,表⽰学⽣没有参加考试,Integer score = null;3.2 Hibernate主键⽣成策略1 hibernate要求实体类⾥⾯有⼀个属性作为唯⼀值,对应表主键,主键可以不同⽣成策略2 hibernate主键⽣成策略有很多的值3 在class属性⾥⾯有很多值(1)native:根据使⽤的数据库帮选择哪个值(2)uuid:之前web阶段写代码⽣成uuid值,hibernate帮我们⽣成uuid值3.3 实体类操作对实体类crud操作添加操作1 调⽤session⾥⾯的save⽅法实现根据id查询1 调⽤session⾥⾯的get⽅法实现修改操作1 ⾸先查询,修改值(1)根据id查询,返回对象删除操作1 调⽤session⾥⾯delete⽅法实现3.4 实体类对象状态(概念)1 实体类状态有三种(1)瞬时态:对象⾥⾯没有id值,对象与session没有关联(2)持久态:对象⾥⾯有id值,对象与session关联(3)托管态:对象有id值,对象与session没有关联2 演⽰操作实体类对象的⽅法(1)saveOrUpdate⽅法:实现添加、实现修改3.5 Hibernate的⼀级缓存什么是缓存1 数据存到数据库⾥⾯,数据库本⾝是⽂件系统,使⽤流⽅式操作⽂件效率不是很⾼。
Hibernate映射---多对多----将多对多拆分成两个一对多订单和商品的关系就是多对多,一个订单包含多个商品,一个商品可以生成多个订单.如果要想将订单和商品关联起来,还需要一张中间表,来表示二者的关联关系.那么当你需要查询某个订单下的商品时,需要关联查询三张表,这样的查询效率就比较低,所以使用时也要谨慎下面以订单和商品为例,学习多对多关联关系多对多双向关联拆分成两个一对多关联---查询订单下所有的产品Myeclipse在开发上对双向关联提供了支持.在表中设置好主键和外键关系在之前多对多双向关联中,只是一个订单对应产品数量为1,并且价格就是产品定价.那么如何实现下面的变化呢?第一:商品数量有变化,不是一个,而是10个或100个第二:商品价格的变化,早上和晚上是不一样的那么如何实现呢?在中间表中添加两个字段,分别是产品数量quantity,商品售出价格purchasePrice;下面我们来实现这个功能第一步:创建数据库.并建立好主外键关系第二步:选择三张表,生成映射文件和持久化类将多对多关联关系拆分成两个一对多关联关系.在生成映射文件和持久化类时,不要选择many-to-many实时监测选项,如下图;生成映射文件和持久化类如下图:第三步:修改Orders.java类和持久化文件,通常我们根据订单查找其下的产品,很少会根据产品查询该产品在哪个订单下.因此我们没有必要为product添加关联,修改后的文件如下:第四步:修改OrderItem.java文件和OrderItem.hbm.xml文件删除OrderItemId.java持久化类文件,然后修改OrderItem.java 文件,具体如下:第五步:编写测试类package com.entity;import java.util.Set;import org.hibernate.Session;import com.util.HibernateSessionFactory;public class HibernateTest {/*** @param args*/public static void main(String[] args) {HibernateTest hibernateTest = new HibernateTest();hibernateTest.get();}/*** 添加订单和产品*/public void add(){Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession( );session.beginTransaction();Orders order = new Orders();order.setRealname("刘备");order.setAddress("武汉");order.setPhone("999");order.setPostcode("4567");Product product1 = (Product) session.get(Product.class, 1);Product product2 = (Product) session.get(Product.class, 2);OrderItem item1 = new OrderItem(order,product1,100,195.00);OrderItem item2 = new OrderItem(order,product2,200,98.00);double total = 100*195.00+200*98.00;order.getOrderItems().add(item1);order.getOrderItems().add(item2);order.setTotal(total);session.save(order);session.beginTransaction().commit();}/*** 查询订单下的产品*/public void get(){Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession( );session.beginTransaction();Orders order = (Orders) session.get(Orders.class, 3);System.out.println(order.getRealname());System.out.println(order.getTotal());Set<OrderItem> items = order.getOrderItems();System.out.println("===================订单下的产品=======================");for(OrderItem i:items){System.out.println("产品名称:"+i.getProduct().getName());System.out.println("实际价格:"+i.getProduct().getPrice());System.out.println("购买价格:"+i.getPurchaseprice());System.out.println("购买数量:"+i.getQuantity());}session.beginTransaction().commit();}}----------------------------------------新增数据结果:。
Hibernate(6)——一对多和多对多关联关系映射(xml和注解)总结涉及的知识点总结如下:∙One to Many 映射关系o多对一单向外键关联(XML/Annotation)o一对多单向外键关联(XML/Annotation)o懒加载和积极加载o一对多双向外键关联(XML/Annotation)∙Many to Many 映射关系o多对多单向外键关联(XML/Annotation)o多对多双向外键关联(XML/Annotation)o set的inverse元素详解∙问题小结∙关联关系的优缺点多对一单向外键关联关系注意多对一关联是多方持有一方的引用。
看一个例子,去淘宝购物,那么一个淘宝用户可以对应多个购物订单,如图所示:多的一方是Orders,持有一方的引用,也就是Users,而在Users中无需作任何定义,从订单到用户的关系是单向多对一关联。
对应数据库就是:还有比如说学生和班级的关系,多个学生可以属于同一个班级,这就是从学生到班级也是典型的单向多对一关系,看代码实现:基于注解的多对一单向外键关联:单向多对一关联中,多方需要持有一方的引用,那么多方(学生类)需要额外配置,需要对持有的一方引用使用注解@ManyToOne (cascade={CascadeType.ALL}, fetch=FetchType.EAGER),设置为级联操作和饥渴的抓取策略,@JoinColumn(name="cid"),而一方(教室类)无需做任何多方的定义。
注意;多方必须保留一个不带参数的构造器!import ;import ;import ;//班级类,在多对一关系中属于一的方,不持有其他多余的配置,反而是被多方持有public class ClassRoom {private int cid;//班级编号private String cname;//班级名称// 自动增长的主键@Id@GeneratedValuepublic int getCid() {return cid;}public void setCid(int cid) {this.cid = cid;}public String getCname() {return cname;}public void setCname(String cname) {ame = cname;}}View Code一方——班级类无需做多余的定义,下面是多方——学生实体和配置:import ;import ;import ;import ;import ;import ;import ;//学生实体类,属于多对一的多方,持有班级(一方)的引用@Entitypublic class Students {private int sid; //编号private String sname; //姓名private ClassRoom classroom;//学生班级//注意:多方一定要显式的定义不带参数的构造方法public Students() {public Students(String sname){this.sname = sname;}// 多方使用注解:@ManyToOne// fetch=FetchType.EAGER,急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。
Hibernate注解(⼀对⼀、⼀对多、多对多)JPA(Java Persistence API)通过注解或XML描述对象与关系表的映射关系,并将运⾏期的实体对象持久化到数据库中。
JPA是⼀个规范,是⼀个标准,Hibernate是实现了这个标准的开源框架。
1、引⼊hibernate-jpa-2.0-api-1.0.0.Final.jar JPA规范对应的hibernate的jar包2、修改配置⽂件hibernate.cfg.xml 的映射关系<Mapping class=""><?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-configurationPUBLIC "-//Hibernate/Hibernate Configuration DTD//EN""/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- thread:⼀个线程中使⽤⼀个。
获取session会话时使⽤--><property name="current_session_context_class">thread</property><!-- 是否显⽰SQL语句,值为布尔型,默认false --><property name="hibernate.show_sql">true</property><!-- 是否格式化显⽰sql语句,让显⽰更美观,值为布尔型,默认false --><property name="hibernate.format_sql">false </property><!-- ⾃动建表update:每次执⾏时,⽆表则建表,⽆列则建列,只增不减create:每次启动的时候,删除原表,再次创建create-drop:每次启动时创建新表,当显式关闭sessionFactory时,删除表--><property name="hibernate.hbm2ddl.auto">update</property><!-- 连接数据库 --><property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/zxd_db</property><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><property name="ername">zxd</property><property name="hibernate.connection.password">123456</property><property name="dialect">org.hibernate.dialect.MySQLDialect</property><!-- 读取注解 --><mapping class="demo.entity.Book"/></session-factory></hibernate-configuration>3、实体配置package demo.entity;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;import org.hibernate.annotations.GenericGenerator;/*** 注解实体配置* JPA通过注解或XML描述对象与关系表的映射关系,并将运⾏期的实体对象持久化到数据库中。
Hibernate⼀对多,多对多,多对⼀检索策略⼀.概述我们先来谈谈检索数据时的两个问题:1.不浪费内存2.更好的检索效率以上说的问题都是我们想要避免的,接下来就引出了我们要讨论的话题---------------hibernate检索策略⼆.hibernate检索策略分为三种:1.类级别的检索策略2.⼀对多和多对多检索策略3.多对⼀和⼀对⼀关联的检索策略(1)类级别的检索策略分为⽴即检索和延迟检索,默认为延迟检索。
⽴即检索:⽴即加载检索⽅法指定的对象,⽴即发送SQL.延迟检索:延迟加载检索⽅法指定的对象,在使⽤具体的对象时,再进⾏加载,发送SQL.lazy有两个取值:false(⽴即加载)和 true(延迟加载)讨论⼀:当⽤get()⽅法检索数据时,在类级别检索策略不管是不是延迟加载都会⽴即检索接下来看看代码实现是不是跟我说的⼀样:配置⽂件中:测试类代码:@Testpublic void select1(){Session session = HibernateUtil.currentSession();Transaction tx = session.beginTransaction();House house = session.get(House.class, 1);System.out.println("===========================");// System.out.println(house.getType().getName());mit();HibernateUtil.closeSession();}接下来看看测试的效果:接下来我们把lazy设为true:效果:⼤家注意没,测试类有⼀⾏代码我是注释掉的,为的就是让我们很好的理解,如果我把下⾯的代码放开是什么效果呢?⼤家要注意现在我们的查询是get()⽅法:我们得到的结果是⼀样的,这样就说明了当使⽤类级别检索时,使⽤get()⽅法都会⽴即加载。