Hibernate

    技术2022-05-11  86

    Hibernate3.0 预备知识 : Core Java JDBC SQL   Hibernate 理论基础 1.     什么是 hibernate? 2.     hibernate 的知识内容 3.     什么是对象持久化 ? 对象持久化有什么用 ?( 解决的问题 ) 4.     如何对象持久化 ? 5.     如何用数据库的方法做对象持久化 ? 6.     ORM( 对象关系映射 ) 是什么 ? 有什么作用 ? 7.     ORM 从对象到表所要考虑的问题 8.     什么是 ORM 框架 ? 有什么用 ? 9.     使用 hibernate 的方法做对象持久化的工作 , 程序员应该怎么做 ? 10.  hibernate 有什么用 ? 11.  程序员和 hibernate 的整体工作流程   什么是 hibernate: 持久化的框架 , 属于设计方面的内容 , 类库 , 用来做对象持久化的 , 什么是对象持久化呢 ?   Hibernate 的知识内容 : 语法部分 ( 类库 ) 程序设计思想 , 也就是持久层的设计   什么是对象持久化 ? 对象持久化有什么用 ?( 解决的问题 ): 发现问题 : 程序设计的架构 : 表现层 业务层 持久层 数据库层 , 其中表现层和业务层是 JVM 来执行 , 应用程序会产生许多的对象 , 如果断电了 , 对象就消失了 , 也就是说在内存中的对象是不稳定的 , 状态不能持久 发现问题 : 将一个对象从 A 电脑复制到 B 电脑 , 如何做到呢 ?   那么有三种方法解决上面的问题 : 1.     序列化 : 通过网络传递 , 或者硬盘共享 2.       存储到数据库中 , 谁想用 , 从数据库中拿 3.       EJB Entity Bean( 实体 Bean)   序列化的方法比较死板 : 如果当一个对象的结构比较复杂的时候 , 我们这时只需要一部分内容 , 没有办法 , 只能整个写入到文件 , 整个读取 序列化的缺点 : 不能检索 , 不能分离一个对象 , 不方便共享 所以说第一种方法只能用于做临时的持久化 , 简单的传输 , 但不适合复杂的持久化工作   第二种方法 ( 数据库持久化 ): 检索方便 , 分布式共享 , 永久数据   总结 : 什么是对象持久化 : 对象持久化就是把内存中的对象永久的保存起来 , 保护对象的状态 , 方便使用 对象持久化有什么用 : 1. 解决掉电的问题 2. 共享方便 3. 保证对象安全 检索方便   如何对象持久化 : 1.     对象序列化 2.     数据库 (JDBC,EJB,Hibernate)   如何用数据库的方法做对象持久化 : 1.     JDBC 发现问题 : 需要做大量的工作 , 难度大 2.     EJB 使用的是其中的一个功能来做持久化 , 解决了使用 JDBC 方法的的大量工作的问题 发现问题 : EJB 是重量级的组件 , 要使用它 , 有两个问题 1. 成本 2. 性能   发现问题 : 以上两种方式还有个共同的问题 , 对象不是简单存储在数据库中的 , 比如多态的特点就不能处理  A b=new B(); B A 的子类   3.     Hibernate 解决了以上的所有问题 , 作用 :1. 不用做大量的工作 2. 移植性能好 3. 提高了代码的质量 , 简单 4. 检索 共享 重用 成本 调试   ORM( 对象关系映射 ) 是什么 ? 有什么作用 ? 发现问题 : java 中的对象的属性类型和数据库中的字段类型是不一样的 , 那么如何来存储 java 中的对象呢 ? 这就需要做对象关系的映射 , 也就是 ORM 什么是 ORM: 将内存中的对象和数据库做转化 , 这样就实现了 java 与数据库之间的访问等功能   ORM 从对象到表所要考虑的问题 : Orm 的复杂问题 : 1.     数据库如何保证对象的唯一性 : 在内存中 , 两个对象属性值都一样 , 但是内存地址不一样 , 可以做区分 , 但是在数据库中如何分辨呢 ? 2.     继承关系如何转化 3.     集合如何映射呢 ?   什么是 ORM 框架 ? 有什么用 ? 就是一个类库 , 通过这个类库完成持久化层的设计   使用 hibernate 的方法做对象持久化的工作 , 程序员应该怎么做 ? 1.     ORM 方案定下来 , 就是类到数据库的转化 2. 利用 hibernate 生成代码 hibernate 有什么用 ? 1.     完成 jdbc 的代码 2.     管理持久化对象的状态 3.     提供一个查询的 API   程序员和 hibernate 的整体工作流程 程序员 : 1.     设计 ORM 方案 2.     写配置文件 3.     调用 Hibernate API, Hibernate 发出命令 hibernate: 4.     读配置文件 5.     生成 jdbc 代码 6.     执行   Hibernate 简单实例 Hibernate 语法 : 作用 : 数据库的增删改查 HQL 面向对象的查询语句   大致步骤 : 1.     设置环境   类库 2.     定义映射 A 定义映射的实体 po B 建立数据库表 C XML 配置文件 ( , 数据库 ) 3.     调用 Hibernate API A 管理 po 的状态 ( 增删改 , 恢复 po 状态 ) B 检索 ( 查询 )   Hibernate 第一个简单的实例 : 引例 (frisHbn ) 1.     设置环境 hibernate 配置环境需要的资源 Hibernate jar : lib.zip dtd.zip: dtd.zip 可以不设置 2.     定义映射 建立项目 : bussiness : entity Biz 业务 client : 测试 util : 工具   先写持久化类 : 以花为实体 , 建立花类 , 并且建立数据库表 /**  * 建表语句 :  * CREATE TABLE T_FRUIT(    FID NUMBER(10) PRIMARY KEY,    NAME VARCHAR(20) NOT NULL,    COMMENTS VARCHAR(50),    PRICE NUMBER(5) NOT NULL );  */ package Yuchen.fristHbn.business.entity; // 持久化类 ( 花类 ), 注意因为采用的是 hilo 的方式获得 id, 所以需要有 setid 的方法 public class Fruit {             private Integer fid;//hibernate 中的 id 不能识别 int       private String name;       private String comments;       private int price;             public Fruit() {             super();       }             public Fruit(String name, String comments, int price) {             super();             this.name = name;             this.comments = comments;             this.price = price;       }         public String getComments() {             return comments;       }       public void setComments(String comments) {             this.comments = comments;       }             public Integer getFid() {             return fid;       }       public String getName() {             return name;       }       public void setName(String name) {             this.name = name;       }       public int getPrice() {             return price;       }       public void setPrice(int price) {             this.price = price;       }         public void setFid(Integer fid) {             this.fid = fid;       }       }   使用 hilo 的方式获得 id: 建表语句 : CREATE TABLE T_HILO(HILO_ID NUMBER(10)); INSERT INTO T_HILO VALUES(1);   hibernate 的连接数据库的配置文件 : <?xml version="1.0"?> <!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="show_sql">true</property>             <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>             <property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:name</property>             <property name="connection.username">scott</property>             <property name="connection.password">tiger</property>             <property name="connection.isolation">2</property>             <property name="dialect">org.hibernate.dialect.Oracle9Dialect</property>             <mapping resource="Yuchen/fristHbn/business/entity/Fruit.hbm.xml"/>       </session-factory> </hibernate-configuration>   写映射配置文件 : <?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="Yuchen.fristHbn.business.entity">       <class name="Fruit" table="T_FRUIT">            <id name="fid" column="fid">                  <generator class="hilo">                        <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>             </id>             <property name="name" column="name" />             <property name="comments" column="comments"></property>           <property name="price" column="price"></property>       </class> </hibernate-mapping> A.    类名 — 表名 B.    id—id  获得 id 的方式   详细信息 ( 如 : hilo 的表名和字段 ) C.    属性 — 字段   使用 hibernate API(FruitManager.java): package Yuchen.fristHbn.business.Biz; // 业务逻辑类 : 负责增删改查 通过使用 hibernate API 进行 import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration;   import Yuchen.fristHbn.business.entity.Fruit;   public class FruitManager {       public void insert(Fruit fruit){             Configuration config=new Configuration();             config.configure();// 读配置文件             SessionFactory sf=config.buildSessionFactory();// 得到工厂             Session session=sf.openSession();// 得到 session             Transaction tt=session.beginTransaction();// 检查事务开启             session.save(fruit);// 存储 insert             tt.commit();// 提交             session.close();// 关闭资源       } }       写测试类 : 插入一个对象到数据库中 /**  * 知识点 :  * hibernate 基础 : 练习语法部分 API 和简单的映射关系  * 程序目标 :  * 使用 hibernate 方法将对象进行持久化  * 实现数据库的增删改查  * API:  * 1.Configuration: 这个类负责读取 XML 文档 ( 映射配置文件 )  * configure(): 读 xml  * buildSessionFactory(): 创建一个生产 session 对象的工厂 , 其实是再次检查  * 因为 hibernate 和 jdbc 不一样 ,jdbc 是如果不手动设置开启事务 , 那它  * 就是马上执行 sql 的 ,hibernate 的不会马上执行 , 是事务提交后执行  * 默认情况下就是打开事务的状态 , 这里只是再检查以下  * 2.SessionFactory: 负责生产 session 对象  * openSession(): 创建一个 session  * 3.Session 类 : 这个是主要的类 , 负责增删改查 , 开启事务等  * beginTransaction(): 产生一个事务对象 (Transaction)  * save(): 增加相当于操作 sql 中的 insert 语句  * 4.Transaction 类 : 负责管理事务的  * commit(): 提交一个事务  *  */ package Yuchen.fristHbn.client;   import Yuchen.fristHbn.business.Biz.FruitManager; import Yuchen.fristHbn.business.entity.Fruit;   public class Test {             public static void test1(){            Fruit fruit=new Fruit("lisi","hello",100); //       fruit.setName("zhangsan"); //       fruit.setComments("hello"); //       fruit.setPrice(100);                        FruitManager fm=new FruitManager();             fm.insert(fruit);       }       public static void main(String[] args) {            // TODO 自动生成方法存根            Test t=new Test();             t.test1();       }   }   hibernate API( ): Configuration: 读取配置文件信息 用来初始化的 SessionFactory: 重量级对象 , 特点 : 消耗资源大 , 线程是安全 , 所以可以被共享 上面两个对象只实例化一个就行了 , 都是用于初始化的 Session: 线程是不安全的 , 所以要避免多个线程共享它 , 是轻量级的对象 , 使用后关闭   Session 对象的状态 : 顺态 : 还没有被持久化 , 也就是说数据库中没有该对象的记录 , 并且 Session 中的缓冲区里没有这个对象的引用 持久态 : 在数据库中有该对象的记录 , 并且在 session 中的缓冲区里有这个对象的引用 , 和顺态正好相反 游离态 : 在数据库中有记录 , 但是不在 session 的缓冲区里   对象状态的转换 : 做一个工具类 , 将 hibernate 中重复的代码包装起来 : package Yuchen.fristHbn.util; // 生产 session 对象的工具类 import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration;   public class HbnUtil {       private static SessionFactory sf;       static{             sf=new Configuration().configure().buildSessionFactory();       }             public static Session getSession(){             return sf.openSession();       } }   完善 FruitManager 类 : package Yuchen.fristHbn.business.Biz; // 业务逻辑类 : 负责增删改查 通过使用 hibernate API 进行 import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration;   import Yuchen.fristHbn.business.entity.Fruit; import Yuchen.fristHbn.util.HbnUtil;   public class FruitManager {       public Integer insert(Fruit fruit){             Session session=HbnUtil.getSession();// 通过工具更方便了             Integer id=null; //       Configuration config=new Configuration(); //       config.configure();// 读配置文件 //       SessionFactory sf=config.buildSessionFactory();// 得到工厂 //       Session session=sf.openSession();// 得到 session             Transaction tt=session.beginTransaction();// 检查事务开启             id=(Integer)session.save(fruit);// 存储 insert             tt.commit();// 提交             session.close();// 关闭资源             return id;       }             public Fruit selectId(Integer id){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();            Fruit fruit=(Fruit)session.get(Fruit.class, id);             t.commit();             session.close();             return fruit;       }             public void remove(Fruit fruit){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             session.delete(fruit);             t.commit();             session.close();       } }   测试对象状态的转换 : /**  * 知识点 :  * hibernate 基础 : 练习语法部分 API 和简单的映射关系  * 程序目标 :  * 使用 hibernate 方法将对象进行持久化  * 实现数据库的增删改查  * API:  * 1.Configuration: 这个类负责读取 XML 文档 ( 映射配置文件 )  * configure(): 读 xml  * buildSessionFactory(): 创建一个生产 session 对象的工厂 , 其实是再次检查  * 因为 hibernate 和 jdbc 不一样 ,jdbc 是如果不手动设置开启事务 , 那它  * 就是马上执行 sql 的 ,hibernate 的不会马上执行 , 是事务提交后执行  * 默认情况下就是打开事务的状态 , 这里只是再检查以下  * 2.SessionFactory: 负责生产 session 对象  * openSession(): 创建一个 session  * 3.Session 类 : 这个是主要的类 , 负责增删改查 , 开启事务等  * beginTransaction(): 产生一个事务对象 (Transaction)  * save(): 增加相当于操作 sql 中的 insert 语句  * 4.Transaction 类 : 负责管理事务的  * commit(): 提交一个事务  * test1(): 测试插入的功能  * test2(): 测试数据同步更新的功能  * test3(): 测试 saveOrUpdate()  * test4(): 测试 clear() 和 flush()  */ package Yuchen.fristHbn.client;   import org.hibernate.Session; import org.hibernate.Transaction;   import Yuchen.fristHbn.business.Biz.FruitManager; import Yuchen.fristHbn.business.entity.Fruit; import Yuchen.fristHbn.util.HbnUtil;   public class Test {             public void test1(){            Fruit fruit=new Fruit("lisi","hello",100); //       fruit.setName("zhangsan"); //       fruit.setComments("hello"); //       fruit.setPrice(100);                        FruitManager fm=new FruitManager();             fm.insert(fruit);       }             public void test2(){            // 测试同步更新的功能            Fruit fruit=new Fruit("meigui","hongse",70);// 顺态             FruitManager fm=new FruitManager();            Fruit fruit2=new Fruit();                        Integer id=fm.insert(fruit);             fruit2=fm.selectId(id);             System.out.println(fruit2.getFid());             System.out.println(fruit2.getName());                        fruit.setName("ziluolan");// 这里修改了对象             fruit2=fm.selectId(id);             System.out.println(fruit2.getFid());// 但是结果没有更新             System.out.println(fruit2.getName());            // 因为 fruit 在 Integer id=fm.insert(fruit); 后变成游离态了            // 也就是说只有持久态才能实现同步更新             System.out.println(fruit.getFid());             System.out.println(fruit.getName());       }             public void test3(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();            Fruit fruit=new Fruit("ziluolan","lanse",100);// 顺态            Fruit fruit2=new Fruit();             FruitManager fm=new FruitManager();             session.save(fruit);//fruit 在运行完此句后变为游离态             fruit2=(Fruit) session.get(Fruit.class, fruit.getFid());            // 从数据库读并打印出来             System.out.println(fruit2.getFid()+":"+fruit2.getName());                        session.saveOrUpdate(fruit);// 如果该对象为游历态就更新数据库 update            // 否则就是顺态 , 增加 insert             fruit2=(Fruit) session.get(Fruit.class, fruit.getFid());             //saveOrUpdate 后再从数据库读并打印出来             System.out.println(fruit2.getFid()+":"+fruit2.getName());            // 两个打印结果一样 ,saveOrUpdate 方法判断如果 id 为 null, 就            // 顺态 , 否则就是游离态             t.commit();             session.close();       }             public void test4(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();            Fruit fruit=new Fruit("guihua","fense",300);// 顺态            Fruit fruit2=new Fruit();             session.saveOrUpdate(fruit);// 执行 insert 因为对象为顺态 //       session.flush();             session.clear();//fruit 变成游离态了 , 并且不会执行 insert 语句            // 因为 hibernate 不是马上执行 sql, 而是等 t.commit() 提交事务            // 后才执行 ,clear 后 , 对象为游离态                        session.saveOrUpdate(fruit);// 这里验证上面的话 , 执行 update            // 做个 select 查看一下 , 可以证明 , 因为 clear 后 , 没有马上执行             //sql 语句 , 所以表里没有数据 , 这里 update 也没有用 , 所以表中            // 一个对象也没插入 , 但是如果加入 flush() 刷新就是马上执行 sql 了                        t.commit();             session.close();       }       public static void main(String[] args) {            // TODO 自动生成方法存根            Test t=new Test();       //      t.test1();       //      t.test2();       //      t.test3();            t.test4();            }   }   hibernate API( ): flush(): 从上面的例子可以看出 ,flush 是刷新 session 的缓冲区 , 并执行里面的命令 flush() 的事务管理模式 : flushMode() 里面有三个常量 , 可以用数字来表示 Load(): 另一种读取数据的方法 , 和 get 的区别是 : 1. 异常处理 : load 有异常处理 ,get 没有 , 它返回 null,2.get 从数据库读数据 ,load 可能去读缓冲区   事务的隔离级别 : 在 hibernate 的数据库配置文件中设置 数字 1 为可以脏读 , 数字 2 为不能 , 这个是最常用的   锁机制 : 避免并发冲突 , 在数据库中写数据是自动加锁的 , 读一般不加 , 有悲观锁和乐观锁 乐观锁是可以是 hibernate 程序自己加 实现乐观锁 : 引例 (hbn2 包 ) 步骤 : 1.     在表中加个 version 字段 2.     在持久类里加个 version 属性 3.     配置文件 <version name=”versopm”> 每存一次值加 1   引例 :hbn2 包   复杂的映射 : 1.     基数关系映射 2.     继承关系映射 3.     组件关系映射 4.     集合映射   基数关系的映射 —one to one: 基数关系的映射需要考虑的问题 : 1.     数量问题 2.     方向问题 在 one to one 的关系中 , 我们有两种方法可以体现类与类之间的关系 1.     共享主键 2.     外键唯一 引例 : Joto 包 - 此包引用了 fristHbn 包   建立与 Fruit 类有一对一关系的类 : 我们认为一个花有一个产地 , 一个产地生产一种花 , 所以要建立产地类 package Yuchen.Joto.business.entity; // 花的地址类 // 问题 : 为什么不能在构造函数中写 Fruit? 因为生成对象后要持久化 // 这个对象 , 但是数据库的表中不能插入另一个类的值 , 写上 null 又不 // 大合适 , 所以就去掉它 public class Address {       private Integer aid;       private String nation;       private String postcode;       private Fruit fruit;       public Address() {                  }       public Address(String nation, String postcode) {             super();             this.nation = nation;             this.postcode = postcode;       }       public Integer getAid() {             return aid;       }       public void setAid(Integer aid) {             this.aid = aid;       }       public Fruit getFruit() {             return fruit;       }       public void setFruit(Fruit fruit) {             this.fruit = fruit;       //      fruit.setAddress(this);       }       public String getNation() {             return nation;       }       public void setNation(String nation) {             this.nation = nation;       }       public String getPostcode() {             return postcode;       }       public void setPostcode(String postcode) {             this.postcode = postcode;       }       }   修改 Fruit 类 : package Yuchen.Joto.business.entity; // 持久化类 ( 花类 ), 注意因为采用的是 hilo 的方式获得 id, 所以需要有 setid 的方法 public class Fruit {             private Integer fid;//hibernate 中的 id 不能识别 int       private String name;       private String comments;       private int price;       private Address address;// 一朵花对应一个地址             public Fruit() {             super();       }             public Fruit(String name, String comments, int price) {             super();             this.name = name;             this.comments = comments;             this.price = price;       }         public Address getAddress() {             return address;       }         public void setAddress(Address address) {             this.address = address;             address.setFruit(this);// 因为当你给一个花设置产地的时候            // 该产地也有了花       }         public String getComments() {             return comments;       }       public void setComments(String comments) {             this.comments = comments;       }             public Integer getFid() {             return fid;       }       public String getName() {             return name;       }       public void setName(String name) {             this.name = name;       }       public int getPrice() {             return price;       }       public void setPrice(int price) {             this.price = price;       }         public void setFid(Integer fid) {             this.fid = fid;       }       }   为地址实体类建表 : //oto 共享主键方式 create table t_address(       aid number(10) primary key,       nation varchar2(30) not null,       postcode varchar2(10) not null,       constraint address_fruit foreign key(aid) references T_FRUIT(fid) ); 注意建表的方式不同 , 所对应的映射文件也有些区别   共享主键方式的映射文件 :<?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="Yuchen.Joto.business.entity">       <class name="Fruit" table="T_FRUIT">            <id name="fid" column="fid">                  <generator class="hilo">                        <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>             </id>             <property name="name" column="name" />             <property name="comments" column="comments"></property>             <property name="price" column="price"></property>             <one-to-one name="address" cascade="all" />       </class>       <class name="Address" table="t_address">            <id name="aid" column="aid">                  <generator class="foreign">                        <param name="property">fruit</param>                  </generator>             </id>             <property name="nation" column="nation"></property>             <property name="postcode" column="postcode"></property>             <one-to-one name="fruit" constrained="true"></one-to-one>       </class> </hibernate-mapping>   思路 : 写类 — 表 , 类中的属性 — 字段 , 类关系 ( 从数据库的角度出发 )   外键唯一的方式 :建表:  create table t_address(       aid number(10) primary key,       nation varchar2(30) not null,       postcode varchar2(10) not null,       fid number(10) not null unique,       constraint address_fruit foreign key(fid) references T_FRUIT(fid) ); 配置文件中修改 <one-to-one name="fruit" constrained="true"></one-to-one> 为 <many-to-one name="fruit" column="fid" unique="true" cascade="all" />   client 程序 :/**  * 知识点 :  * 基数关系映射 :one to one  * 程序目标 :  * 1. 写持久类 , 建立持久类之间的关系  * 2. 定义映射关系 , 为 po 建表 : 两种建表方式  * 第一种 : 共享主键  * 第二种 : 外键唯一  * 3. 写映射文件  * 共享主键情况下映射文件的写法 :  * A. 主键方 :<one-to-one name=" 引用类型变量名 " cascade="all">  * B. 外键方 :<one-to-one name=" 引用类型变量名 " constrained="true">  * 外键唯一情况下映射文件的写法 :  * A. 主键方 :<one-to-one name=" 引用类型变量名 " cascade="all">  * B. 外键方 :<many-to-one name=" 引用类型变量名 " column="fid" unique="true" cascade="all" />  */ package Yuchen.Joto.client;   import org.hibernate.Session; import org.hibernate.Transaction;   import Yuchen.Joto.business.entity.Address; import Yuchen.Joto.business.entity.Fruit; import Yuchen.Joto.util.HbnUtil;   public class Test {             public void test1(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();            Fruit fruit=new Fruit(" 掉蓝 "," 绿色 ",260);             Address arddess=new Address(" 中国 "," 崛起 ");             fruit.setAddress(arddess);             session.save(fruit);             t.commit();             session.close();       }             public static void main(String[] args) {            // TODO 自动生成方法存根            Test t=new Test();             t.test1();       }   }   基数关系的映射 (one to many): 引例 :Jotm 我们认为一种花有多个产地 : 建立花类 : package Yuchen.Jotm.business.entity; // 花类 import java.util.HashSet; import java.util.Set;   public class Fruit {       private Integer fid;       private String name;     private String comments;    private int price;     private Set addresses = new HashSet();// 一种花有多个产地       public Fruit() {             super();       }       public Fruit(String name, String comments, int price) {             super();             this.name = name;             this.comments = comments;             this.price = price;       }             public void setAddress(Address address) {             addresses.add(address);             address.setFruit(this);       }       public Set getAddresses() {             return addresses;       }       public void setAddresses(Set addresses) {             this.addresses = addresses;       }       public String getComments() {             return comments;       }       public void setComments(String comments) {             this.comments = comments;       }       public Integer getFid() {             return fid;       }       public void setFid(Integer fid) {             this.fid = fid;       }       public String getName() {             return name;       }       public void setName(String name) {             this.name = name;       }       public int getPrice() {             return price;       }       public void setPrice(int price) {             this.price = price;       }     }   建立产地类 : package Yuchen.Jotm.business.entity;   // 地址类 public class Address {          private Integer aid;          private String nation;          private String postcode;          private Fruit fruit;// 一个地址对应一种花       public Address() {             super();       }       public Address(String nation, String postcode) {             super();             this.nation = nation;             this.postcode = postcode;       }       public Integer getAid() {             return aid;       }       public void setAid(Integer aid) {             this.aid = aid;       }       public Fruit getFruit() {             return fruit;       }       public void setFruit(Fruit fruit) {             this.fruit = fruit;       }       public String getNation() {             return nation;       }       public void setNation(String nation) {             this.nation = nation;       }       public String getPostcode() {             return postcode;       }       public void setPostcode(String postcode) {             this.postcode = postcode;       }       }   建立数据库表 : Fruit : create table T_FRUIT_many2one(    FID number(10) PRIMARY KEY,    NAME VARCHAR2(20) NOT NULL,    COMMENTS VARCHAR2(50),    PRICE number(5) NOT NULL );   Address : 这个是多的一方 , 所以他的外键的值要引用 Fruit 类的主键值 CREATE TABLE T_ADDRESS_many2one(    AID number(10) PRIMARY KEY,    NATION VARCHAR2(30) NOT NULL,    POSTCODE VARCHAR2(10) NOT NULL,    AFID number(10) NOT NULL,    CONSTRAINT ADDRESS_FRUIT_many2one FOREIGN KEY(AFID)    REFERENCES T_FRUIT_many2one(FID) );   写映射配置文件 : <?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="Yuchen.Jotm.business.entity">       <class name="Fruit" table="T_FRUIT_many2one">            <id name="fid" column="fid">                  <generator class="hilo">                        <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>             </id>             <property name="name" column="name" />             <property name="comments" column="comments"></property>           <property name="price" column="price"></property>           <set name="addresses" inverse="true" cascade="all">                  <key column="afid"></key>                  <one-to-many class="Address"></one-to-many>             </set>       </class>       <class name="Address" table="t_address_many2one">            <id name="aid" column="aid">                  <generator class="hilo">                      <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>             </id>             <property name="nation" column="nation"></property>           <property name="postcode" column="postcode"></property>             <many-to-one name="fruit" column="afid" cascade="all"></many-to-one>       </class> </hibernate-mapping>   client : /**  * 知识点 :  * 基数关系映射 :one to many  * 程序目标 :  * 映射文件的写法 :  * 1. 主键方 :  * <set name=" 引用类型的变量 " inverse="true" cascade="all">  * <key column=" 外键名 ">  * <one-to-many class=" 外键的类名 "></one-to-many>  * 2. 外键方 :  * <many-to-one name=" 引用类型的变量 " column=" 外键名 " cascade="all">  */ package Yuchen.Jotm.client;   import Yuchen.Jotm.business.Biz.FruitManager; import Yuchen.Jotm.business.entity.Address; import Yuchen.Jotm.business.entity.Fruit;   public class Test {             public static void main(String[] args){             FruitManager fm=new FruitManager();             Address address1=new Address(" 北京 ","0000");             Address address2=new Address(" 上海 ","000340");            Fruit fruit=new Fruit(" 玫瑰 "," 红色 ",2000);             fruit.setAddress(address1);             fruit.setAddress(address2);             fm.insert(fruit);       } }   基数关系的映射 (many to many): 我们把花和产地看为多对多的关系 : 引例 :Jmtn 修改产地类 : package Yuchen.Jmtn.business.entity;   import java.util.HashSet; import java.util.Set;   // 产地类 public class Address {          private Integer aid;          private String nation;          private String postcode;          private Set fruits=new HashSet();// 一个地址对应一种花       public Address() {             super();       }       public Address(String nation, String postcode) {             super();             this.nation = nation;             this.postcode = postcode;       }             public Set getFruits() {             return fruits;       }       public void setFruits(Set fruits) {             this.fruits = fruits;       }       public Integer getAid() {             return aid;       }       public void setAid(Integer aid) {             this.aid = aid;       }       public void setFruit(Fruit fruit) {             fruits.add(fruit);       //      fruit.setAddress(this);       }       public String getNation() {             return nation;       }       public void setNation(String nation) {             this.nation = nation;       }       public String getPostcode() {             return postcode;       }       public void setPostcode(String postcode) {             this.postcode = postcode;       }       }       建表 : Fruit : create table T_FRUIT_many2many(    FID number(10) PRIMARY KEY,    NAME VARCHAR2(20) NOT NULL,    COMMENTS VARCHAR2(50),    PRICE number(5) NOT NULL );   Address : 这个是多的一方 , 所以他的外键的值要引用 Fruit 类的主键值 CREATE TABLE T_ADDRESS_many2many(    AID number(10) PRIMARY KEY,    NATION VARCHAR2(30) NOT NULL,    POSTCODE VARCHAR2(10) NOT NULL );   中间表 : CREATE TABLE FRUIT_ADDRESS(    FID number(10) NOT NULL REFERENCES T_FRUIT_MANY2MANY(FID),    AID number(10) NOT NULL REFERENCES T_ADDRESS_MANY2MANY(AID),    PRIMARY KEY(FID,AID) );   映射配置文件 : <?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="Yuchen.Jmtn.business.entity">       <class name="Fruit" table="T_FRUIT_many2many">            <id name="fid" column="fid">                  <generator class="hilo">                        <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>             </id>             <property name="name" column="name" />             <property name="comments" column="comments"></property>           <property name="price" column="price"></property>           <set name="addresses" table="fruit_address" inverse="true" cascade="save-update">                  <key column="fid"></key>                  <many-to-many class="Address" column="aid"></many-to-many>             </set>       </class>       <class name="Address" table="t_address_many2many">            <id name="aid" column="aid">                  <generator class="hilo">                      <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>             </id>             <property name="nation" column="nation"></property>           <property name="postcode" column="postcode"></property>            <set name="fruits" table="fruit_address" cascade="save-update">                  <key column="aid"></key>                  <many-to-many class="Fruit" column="fid"></many-to-many>             </set>       </class> </hibernate-mapping>   cline : /**  * 知识点 :  * 基数关系映射 :many to many  */ package Yuchen.Jmtn.client;   import Yuchen.Jmtn.business.Biz.FruitManager; import Yuchen.Jmtn.business.entity.Address; import Yuchen.Jmtn.business.entity.Fruit;   public class Test {             public static void main(String[] args){             FruitManager fm=new FruitManager();             Address address1=new Address(" 北京 ","0000");             Address address2=new Address(" 上海 ","000340");            Fruit fruit=new Fruit(" 玫瑰 "," 红色 ",2000);            Fruit fruit2=new Fruit(" 紫罗兰 "," 紫色 ",1000);             fruit.setAddress(address1);             fruit.setAddress(address2);             fruit2.setAddress(address1);             fm.insert(fruit);             fm.insert(fruit2);       } }   继承关系的映射 : 三个表 发现问题 : 如何体现继承关系呢 ? 两种方式 :1. 共享主键 2. 外键唯一 继承中子类有一个 supper, 也就是有一个父类 , 但是父类中没有子类 , 所以是单向的一对一的关系 , 因此在继承中不考虑数量的问题 优点 : 和面向对象的概念相似 , 支持多态 缺点 : 子类的数据会存放很多 , 效率也不高 , 表也多 , 但是数据没有冗余   引例 :Extends 1.     建立工具包类 ( 省略 ) 2.     建立实体类 付款方式 : 现金   银行 package Yuchen.Extends.business.entity; // 父类 : 付款方式 public abstract class Payment {       private Integer pid;       private String reason;// 付款原因       private Double amount;// 付款金额             public Payment() {             super();       }         public Payment(String reason, Double amount) {             super();             this.reason = reason;             this.amount = amount;       }         public Double getAmount() {             return amount;       }         public void setAmount(Double amount) {             this.amount = amount;       }         public Integer getPid() {             return pid;       }         public void setPid(Integer pid) {             this.pid = pid;       }         public String getReason() {             return reason;       }         public void setReason(String reason) {             this.reason = reason;       }       }   package Yuchen.Extends.business.entity; // 银行付款 public class CardPayment extends Payment{       private Integer pid;       private String bank;// 银行卡               public CardPayment() {             super();       }               public CardPayment(String reason, Double omount, String bank) {             super(reason,omount);             this.bank = bank;       }           public Integer getPid() {             return pid;       }           public void setPid(Integer pid) {             this.pid = pid;       }           public String getBank() {             return bank;       }         public void setBank(String bank) {             this.bank = bank;       }             }   package Yuchen.Extends.business.entity; // 现金 public class CashPayment extends Payment{       private Integer pid;       private String cash;// 货币类型       public CashPayment(){                  }       public CashPayment(String reason,double amount, String cash) {             super(reason,amount);             this.cash = cash;       }       public String getCash() {             return cash;       }       public void setCash(String cash) {             this.cash = cash;       }       public Integer getPid() {             return pid;       }       public void setPid(Integer pid) {             this.pid = pid;       }       }   建表 : 1.Payment create table t_payment (       pid number(10) primary key,       reason varchar2(30) not null,       amount number(30) not null );   2.CardPayment // 共享主键 create table t_cardpayment(       pid number(10) primary key references t_payment(pid),       bank varchar2(30) not null );   3.CashPayment // 共享主键 create table t_cashpayment(       pid number(10) primary key references t_payment(pid),       cash varchar2(30) not null );   写配置文件 :<?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="Yuchen.Extends.business.entity"> <class name="Payment" table="t_payment">       <id name="pid" column="pid">             <generator class="hilo">                  <param name="table">t_hilo</param>                  <param name="column">hilo_id</param>             </generator>       </id>       <property name="reason"></property>       <property name="amount"></property>       <joined-subclass name="CardPayment" table="t_cardpayment">            <key column="pid"></key>             <property name="bank"></property>       </joined-subclass>       <joined-subclass name="CashPayment" table="t_cashpayment">            <key column="pid"></key>             <property name="cash"></property>       </joined-subclass> </class> </hibernate-mapping> client: /**  * 知识点 :  * 继承关系映射  * test1(): 三个表  */ package Yuchen.Extends.client;   import org.hibernate.Session; import org.hibernate.Transaction;   import Yuchen.Extends.business.entity.CardPayment; import Yuchen.Extends.util.HbnUtil;   public class Test {             public static void test1(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             CardPayment card=new CardPayment(" 买杂志 ",100.0," 人民币 ");             session.save(card);             t.commit();             session.close();       }       public static void main(String[] args) {            // TODO 自动生成方法存根             Test.test1();       }   }   继承关系的映射 : 两个表 一个子类一个表 , 父类不建表 , 但是每个子类需要加入父类的属性 缺点 : 不支持多态的查询 , 特点不明显 , 用的很少   建表 : 两个表 : 1.CardPayment create table t_cardpayment_concrete(     pid integer(10) primary key,     reason varchar(30) not null,     amount double not null,     bank varchar(10) not null   );     2.CashPayment create table t_cashpayment_concrete(     pid integer(10) primary key,     reason varchar(30) not null,     amount double not null,     cash varchar(10) not null ); 修改配置文件 : <?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="Yuchen.Extends.business.entity">       <class name="Payment">            <id name="pid" column="pid">                  <generator class="hilo">                        <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>          </id>             <property name="reason"></property>             <property name="amount"></property>             <union-subclass name="CardPayment" table="t_cardpayment_concrete">             <property name="bank"></property>             </union-subclass>             <union-subclass name="CashPayment" table="t_cashpayment_concrete">             <property name="cash"></property>       </union-subclass>       </class> </hibernate-mapping>   继承关系的映射 : 一个表 优点 :1. 生成报表快 2. 易于实现 3. 支持多态 缺点 : 修改和维护比较麻烦 如果类中的属性太多用这个方法就不大合适了 建表 : 一个表 : create table t_payment_hierarchy(  pid number(10) primary key,  reason varchar2(30) not null,  amount number not null,  cash varchar2(10) not null,  bank varchar2(10) not null,  type varchar2(10) not null );   修改配置文件 : <?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="Yuchen.Extends.business.entity"> <class name="Payment" table="t_payment_hierarchy">       <id name="pid" column="pid">                  <generator class="hilo">                        <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>    </id>       <discriminator column="type"></discriminator>       <property name="reason"></property>       <property name="amount"></property>       <subclass name="CardPayment" discriminator-value="card">             <property name="bank"></property>       </subclass>       <subclass name="CashPayment" discriminator-value="cash">             <property name="cash"></property>       </subclass> </class> </hibernate-mapping>   组件映射 and Query: 什么是组件映射 ? 我们知道在类的关联关系中有一种关系叫组合关系 , 什么是组合关系呢 ? 就是不能独立存在的类 , 我们以前在映射这种关系的时候在一对一的情况下使用的是 one to one 的映射方法 , 这种方法比较复杂 , 那么我们可以使用组件映射的方法使得映射更简单 语法 : 1.     被包含的对象没有 oid, 组件类不能看做 po 2.     组件类不映射一个表 作用 : 只有一个表 , 没有 1to1 的关系 , 使得映射更简单 引例 : 银行帐户 , 有两个类 , 一个是帐户基本信息类 , 另一个是帐户人详细地址类 建立实体类 : 地址类属于值对象 , 帐户类属于实体对象 , 两者之间是组合关系 package Yuchen.component.business.entity; // 帐号信息类 public class Account{       private Integer aid;       private String name;       private Address address;// 地址       public Account() {             super();       }       public Account(String name, Address address) {             super();             this.name = name;             this.address = address;       }       public Address getAddress() {             return address;       }       public void setAddress(Address address) {             this.address = address;       }       public Integer getAid() {             return aid;       }       public void setAid(Integer aid) {             this.aid = aid;       }       public String getName() {             return name;       }       public void setName(String name) {             this.name = name;       }       }   package Yuchen.component.business.entity; // 详细地址类 : 注意不需要 id, 因为要和 Account 建一个表里 public class Address{       private String street;// 街道       private String city;// 城市       private String zipcode;// 邮编       public Address() {             super();       }       public Address(String street, String city, String zipcode) {             super();             this.street = street;             this.city = city;             this.zipcode = zipcode;       }       public String getCity() {             return city;       }       public void setCity(String city) {             this.city = city;       }       public String getStreet() {             return street;       }       public void setStreet(String street) {             this.street = street;       }       public String getZipcode() {             return zipcode;       }       public void setZipcode(String zipcode) {             this.zipcode = zipcode;       }       }   建表 : create table t_component(       aid number(10) primary key,       name varchar2(30) not null,       street varchar(30) not null,       city varchar(30) not null,       zipcode varchar(30) not null );   映射文件 : <?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="Yuchen.component.business.entity">       <class name="Account" table="t_component">            <id name="aid" column="aid">                  <generator class="hilo">                        <param name="table">t_hilo</param>                        <param name="column">hilo_id</param>                  </generator>             </id>             <property name="name" />             <component name="address">                  <property name="street" />                  <property name="city" />                  <property name="zipcode" />             </component>       </class> </hibernate-mapping>   client: /**  * 知识点 :  * 组件映射  */ package Yuchen.component.client;   import org.hibernate.Session; import org.hibernate.Transaction;   import Yuchen.component.business.entity.Account; import Yuchen.component.business.entity.Address; import Yuchen.component.util.HbnUtil;   public class Test{       public static void test(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             Address address=new Address(" 湖南路 "," 上海 ","010000");             Account account=new Account("lisi",address);             session.save(account);             t.commit();             session.close();       }       public static void main(String[] args){             Test.test();       } }   Query: /**  * 知识点 :  * 组件映射 ,Query 查询  * test1(): 组件映射  * test2():1. 条件查询 2.from Object 3.uniqueResult()  * test3(): 复杂的条件查询 ( 支持 like )  * test4(): 加参数的查询  * test5(): 使用 select:1. 查询一个类中引用类型的属性值  *                               2. 查询一个类中引用类型的对象  * test6(): 查看两个对象的属性 ( 对象数组太麻烦 )  * test7(): 使用中间对象查看两个对象的属性  *            1. 建一个中间对象类  *            2. select HQL 语句调用 API  * test8(): 命名查询  *            1. 修改配置文件  *            2. 执行 API  * API:  * uniqueResult(): 返回唯一的对象  * getNameQuery(): 得到变量名所指定的 sql 语句  */ package Yuchen.component.client;   import java.util.Iterator; import java.util.List;   import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction;   import Yuchen.component.business.entity.Account; import Yuchen.component.business.entity.AccountAddress; import Yuchen.component.business.entity.Address; import Yuchen.component.util.HbnUtil;   public class Test{       public static void test(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             Address address=new Address(" 湖南路 "," 上海 ","010000");             Account account=new Account("lisi",address);             session.save(account);             t.commit();             session.close();       }       public static void test2()       {             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction(); //       Query q=session.createQuery("from Account where name='lisi'");             Query q=session.createQuery("from java.lang.Object");            List list=q.list();             Account account=(Account) list.get(1); //       Account account=(Account) q.uniqueResult();             System.out.println(account.getName());             t.commit();             session.close();       }             public static void test3(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             Query q=session.createQuery("from Account a where a.name like '%si'");             Account account=(Account) q.uniqueResult();             System.out.println(account.getName());             t.commit();             session.close();       }       public static void test4(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             Query q=session.createQuery("from Account a where a.name like :x");             q.setString("x", "%si");             Account account=(Account) q.uniqueResult();             System.out.println(account.getName());             t.commit();             session.close();       }             public static void test5(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction(); //       Query q=session.createQuery("select a.address.city from Account a where a.name='lisi'");             Query q=session.createQuery("select a.address from Account a where a.name='lisi'");             Address address=(Address) q.uniqueResult();             System.out.println(address.getCity()); //       String city=(String) q.uniqueResult(); //       System.out.println(city);             t.commit();             session.close();       }             public static void test6(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             Query q=session.createQuery("select a.name,a.address from Account a");            List list=q.list();             Object[] obj=(Object[]) list.get(0);// 第一条 (name,address 组成的对象数组 ) //       Object[] obj2=(Object[]) list.get(1);// 第二条             System.out.println(obj[0]);             System.out.println(((Address)obj[1]).getCity());             t.commit();             session.close();       }       public static void test7(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             Query q=session.createQuery("select new Yuchen.component.business.entity.AccountAddress(a.name,a.address.zipcode) from Account a");            List list=q.list();             Iterator it=list.iterator();             while(it.hasNext()){                  AccountAddress aa=(AccountAddress) it.next();                  System.out.println(aa.getName());                  System.out.println(aa.getZipcode());            }             t.commit();             session.close();       }       public static void test8(){             Session session=HbnUtil.getSession();             Transaction t=session.beginTransaction();             Query query=session.getNamedQuery("mingming");             query.setString("name","%si");             Account aa=(Account) query.uniqueResult();             System.out.println(aa.getName());             t.commit();             session.close();       }       public static void main(String[] args){             Test.test8();       } }   修改配置文件 : class 后加入 : <query name="mingming"><![CDATA[from Account a where a.name like :name]]></query>    

    最新回复(0)