hibernate基础知识

12年前

Hibernate框架知识

1、理论hibernate overview
2、映射
 mapping entity
 mapping entity associations-1
 mapping entiity associations-2
3、状态管理
 working with persistent Objects
4、其他问题
 事务
 HQL

 
Hibernate是什么东西?功能是什么?起什么作用?其结构和工作原理是什么?
 
Hibernate的结构和工作原理

O-----〉R
   转换
   对象持久化的工具------这也是最核心的部分;
   怎么把对象转到数据库里


为什么要用hibernate做对象持久化

一、什么叫对象持久化?
简单的说,对象持久化就是将内存中的对象状态存在的数据转存到外部持久设备。
在适当的时候可以将持久设备中的数据恢复到内存对象状态下的数据
O------------存----------->R
  <-------------恢复---------
内存          持久设备

    (是可逆的过程)
oracle---甲骨文---龟文-----持久化


二、为什么要持久化

 1、物理上的原因
   内存不能持久化
   内存容量有限
   
   内存主要是为了运算而用的,够算就行,而不是为了存储数据而用的!!!!
   
   总线 32位-64位-128位
 2、业务上的原因
   信息流动----带动人流动-----带动 物流=====〉信息先导性
   所有的软件都是以数据为中心的,数据-----信息00
   信息高速公路-----带动经济发展
   
   数据最关键不是加工而是流动起来,搜集、存取、分析、统计
    
  共享(流动)=====+++++
  管理(安全、有效、备份)
  大规模检索

结论:对于一个企业的数据来说,对象持久化是必须要做的

三、怎么样进行对象持久化(java平台)
 
 1、对象序列化  x-------把对象搞到硬盘上去
   只是个别对象序列化------序列化之后变成一个二进制文件------
   对于对象序列化之后的文件来说是无法检索的,必须全部再恢复到内存中之后再进行检索
   不适合存储海量的数据 
   
    对象有空间结构,对象序列化就是把其空间结构变成二进制数值
   
 2、DB   必须用DB-------真正的对象持久化
 

 

四、怎么样使用DB进行对象持久化(java平台)
 1、jdbc是基础,利用jdbc可以存储
  
  优点:功能完备、理论上效率最高、接口密度细;主要是干些细活
  缺点:代码量大(可以增加人手)、开发难度大
      很少直接拿jdbc来进行对象持久化
     
    
 2、EJB  entity Bean  有点过时了,但现在大量的程序还在运转
  
  优点:封装了jdbc
  缺点:采取了一个重量级的解决方案
    成本高
    维护工作量大
    EJB功能太多,其中持久化为其最弱的一块
    更复杂的api
    不能在服务器之外进行测试
    组件。必须得实现指定的接口,EJB服务器才能管理使用它
    技术上的:是以服务器为核心
    商业上的:捆绑销售

3、轻量级的ORM框架Hibernate
 优点:轻量级-----把EJB中持久化这部分单独拿出来,和EJB中一样都是封装JDBC,但是设计思路不一样
    做一个单一的类库
   专业
   持久对象是一个pojo--〉纯oo
   功能是可裁减的可扩充的开源的
   成本低
   封装了jdbc,提供了一个更简单的api
 缺点:
  功能完备性差(不如JDBC强,但比EJB强),主要是批量更新

也就是说一般情况下选择hibernate来做,部分采用JDBC来选择。(Hibernate大部分功能都可实现,只有部分需要JDBC来完成)


五、Hibernate的工作原理和结构
 
 工作原理:封装jdbc来完成对象持久化;就是替代JDBC来完成持久化
 
 hibernate的结构与jdbc的结构
 内存中     数据库中
 O   <------------JDBC--------------->R
          |       \
          |     \------------------|映射(要考虑业务的那个对象与数据库的字段有关系)
              APPLICATION   <-------- PROGRAMMER

 为什么呢?因为JDBC这种结构,让程序员太累,需要考虑业务的哪个对象与数据库哪个表的哪个字段有关系(映射)
      
内存中     _hibernate  数据库中
O   <--------|--JDBC--|------------->R
        ------ \
   |        \      --------------映射文件XML
   |           \------------------|映射(要考虑业务的那个对象与数据库的字段有关系)
              APPLICATION   <-------- PROGRAMMER
主要的任务:
1、首要映射说清楚-------映射文件
2、下指令----API

 

O---------|  JDBC   |-----------------R
             |    ------- |生成jdbc
       HIBERNATE参考-----|
       |   |映射文件|XML
       |命令   |
      app------ PROGRAMMER

持久化-----类比成搬家
  复杂的地方在映射文件
  
po讲解----po持久类;pojo;编码规范
1、oid(对象的唯一标识)--中性的。对象有一个唯一的属性,表里需要一个主键。
 为什么要用一个oid?
 持久对象有一个唯一标识符,对应表里有一个主键。
 
 hibernate对jdbc的管理,主要是靠这个主键
 
 为什么必须是中性的?唯一标识符;增删改查都要这个主键
  主键的产生不统一;
  业务一发生变化,号码的结构可能也会发生变化
  Hibernate不了解业务结构,而oid由hibernate负责产生和管理
  我们选择的oid和业务无关。

2、要有一个空的构造方法(重点)
 因为有参数的构造方法,hibernate不能用
 类x有m int,n int属性-----〉自然而然肯定有一个构造方法x(int,int);
 hibernate从数据库表中读出
 num    num
 100     200
 (100,200),那么hibernate肯定不能识别出m,n呢
那么hibernate怎么来识别呢?
hibernate不能使用有参数的构造方法,通过反射机制必须使用无参构造方法
 new x();
 x.setM();---->x.setM(100);
 x.setN();---->x.setN(200);
 
3、setter/getter  (由于属性都是私有的,所以必须有setter和getter方法)

 

比如说有一个账户对象Acct()
Acct acct=new Acct();
JDBC访问的主要代码

Con=  //连接到数据库
con.setAutoConnction();
sql="insert into"value(???)
ps=---------;
ps.setXXX(1,--);
ps.setXXX(2,--);
ps.executeUpdate();
con.commit();

hibernate访问主要代码
Session =
session.begin();
session.save(acct);
session.commit();

 

session{--------hibernate
   save
   delete
   update
   create}

 
 
HIBERNATE的api简单

映射怎么写?-----


步骤:
0环境
1po
2映射文件
3schema
4test(hibernate api)类

环境:
1、把hibernate类库导入到开发环境中---〉eclipse工程中
 选中工程
  java Build Path
   add Library
    user library--new
     add JARs
     import导入

2、两个xml文件需要写
  映射文件(类,表之间的映射关系)
  配置(可以有多个,db连接信息)---提供数据库的连接信息以及hibernate自身的一些信息
 import导入映射文件和配置文件
 准备2个模板,避免写错了

  注意:尽量不要混合使用不同版本的jar包,所以一定要考察好使用的版本的功能


lib.zip---类库 hibernate3.jar核心库,其他都是辅助库,
dtd.zip
template.zip
ojdbc.jar
mysql.jar

 

接下来我们要写程序了:


第一步:构建一个po持久类
package com.newxyz.hbn1.biz.entity;

public class Account {
 //持久类
 private Long oid; //由hibernate自动生成oid,表里面必须有这个字段,类必须有这个属性 ,
 //切记oid属性为Long
 private String acctNo; //帐户
 private double bal;  //余额
 public Account() {  //空的构造器;为什么必须用空的构造器呢?
     //有参数的构造器,hibernate不能用
  
 }
 public Account(String acctNo, double bal) {
  super();    
  //必须再增加一个有参数的构造器,为什么呢?
  //类本身初始化要使用
  //但是不能包含oid----,是由hibernate来提供。
  this.acctNo = acctNo;   
  this.bal = bal;
 }
 public void deposite(double amount){ //存款
  bal=bal+amount;
 }
 public void withdraw(double amount){  //取款
  bal=bal-amount;
 }
 //公开访问方法getXxxx,setXxxx
 public Long getOid() {
  return oid;
 }

 public void setOid(Long oid) {
  this.oid = oid;
 }
 public String getAcctNo() {
  return acctNo;
 }
 public void setAcctNo(String acctNo) {
  this.acctNo = acctNo;
 }
 public double getBal() {
  return bal;
 }
 public void setBal(double bal) {
  this.bal = bal;
 }

}

第二步:编写映射文件

映射文件的编码要求
1、1个映射文件映射一个持久类;是一种习惯;
2、映射文件名称与持久类名称保持一致,如
 Account.java   Account.hbm.xml
    hbm====hibernate mapping
3、映射文件要与其映射的持久类放在同一个包路径下

 

 

映射文件特定的模板:

<?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.newxyz.hbn1.biz.entity"> //package类似于java中的import
   <class name="" table="">
      <id name="" column="">
         <generator class="" />
      </id>
      <property name="" column=""></property>
   </class>
</hibernate-mapping>

单表映射   (类映射表;类属性映射字段)
类.属性映射表的字段------>因为两者都是由同一实体得来


Account.hbm.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.newxyz.hbn1.biz.entity">
<!--//package类似于java中的import,根元素;在根标记里面有一个package可以用;-->

   <class name="Account" table="t_acct">
      <id name="oid" column="OID">
         <generator class="hilo">
          <param name="talbe">t_hilo</param>
          <param name="column">hi</param>
          <!--
          表名
          表里面字段的名字
          意思是当hibernate读取该映射文件时,一旦看见generator class=“hilo”,从表t_hilo中查找字段为hi中取一个值。
          
          -->
         </generator>
      </id>
      <property name="acctNo" column="ACCTNO"/>
      <property name="bal" column="BAL"/>

   </class>
</hibernate-mapping>

 


      <id name="" column="">
         <generator class="hilo" >
  <!-- 需要指定表名和字段名-->
 
  <param name="table">t_hilo</param>
  <param name="column">hi</param>
 
  </generator>
      </id>
      OID是由hibernate自动生成,不是随便声称,要有唯一性
      生成值的算法有好多种《查询百度》
怎么样每次产生的id是不一样的呢?
 
 一般用计数器
比如有一个程序自己维护这个计数器,计数器的数字必须放在数据库中才行。
必须要考虑到程序关闭,计数器清0的情况。计数器持久化

hilo算法   高低位算法

从公有计数器取一个高位值,私有计数器自动生成一个低位值。

如全球电话号码  010-87654321
         020-87654321

 

3、接下来从数据库里面建表

create table t_acct(
 OID number(18) primary key,
 ACCTNO varchar(30) not null,
 BAL number(12,2) not null);
 
create table t_hilo(hi number(18) primary key);
insert into t_hilo values(1);//必须有一行,要不hibernate取不到值就会报错。
commit;


4、修改hibernate.cfg.xml配置文件


<?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><!--这些配置信息主要是通过session工厂来识别的-->
  <property name="show_sql">true</property><!--让hibernate运行期间,将其运行的SQL语句显示到console上-->
  <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
  <property name="connection.url">jdbc:oracle:thin:@192.168.0.23:1521:tarena</property>
  <property name="connection.username">openlab</property>
  <property name="connection.password">open123</property>
  <property name="connection.isolation">2</property><!--隔离级别,防止脏读-->

  <property name="dialect">org.hibernate.dialect.Oracle9Dialect</property><!--dialet方言,地方话:假设是mysql的话应该是org.hibernate.dialect.MySQLDialect-->
  <mapping resource="com/newxyz/ebank/biz/entity/Account.hbm.xml"/>
  
 </session-factory>
</hibernate-configuration>

 

5、写一个测试类test1.java

package com.newxyz.hbn1.test;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.newxyz.hbn1.biz.entity.Account;

public class test1 {
 public static void main(String[] args) {
  Account acct=new Account("a001",6000.0);
  //创建一个帐户对象,存起来

  Configuration cfg=new Configuration();
  cfg.configure();
  //加载配置文件
  //Configuration cfg=new Configuration().configure();

  SessionFactory sf=cfg.buildSessionFactory();
  Session s=sf.openSession();
  //加载SessionFactory,通过SessionFactory来创建Session

  try {
   s.beginTransaction();
   s.save(acct);
   s.getTransaction().commit();//事务跟数据库没关系,只跟交易有关系
  } catch (HibernateException e) {
  
   e.printStackTrace();
   s.getTransaction().rollback();
   
  }finally{
   s.close();
  }
  
 }

}