`

hibernate框架学习笔记

阅读更多
第一天 1
Hibernate框架的作用,优点: 1
Hibernate设计原理: 2
Hibernate主要API: 2
Hibernate使用步骤: 3
插入一条数据的过程: 3
第二天 3
Hibernate映射类型: 3
2.Hibernate主键生成方式 4
3. Hibernate框架的基本特性(默认的情况下采用的是批处理) 5
1. 一级缓存: 5
2. 对象持久性: 6
3. 延迟加载: 7
如何使用同一个Session 8
第三天 9
1. 一对多关系映射 9
2. 多对一关系映射 9
2. Inverse属性 10
第四天 10
1.如何利用MyEclipse根据数据库生成实体类和映射描述文件 10
2.多对多关系映射 11
3.继承关系映射 11
第五天 11
---------总结--------- 11
1)继承关系映射 12
2)Hibernate查询 13
第六天- 14
1.Hibernate高级特性 14
1)二级缓存技术 14
2)查询缓存技术 14
*3)悲观锁和乐观锁 15

第一天
Hibernate框架的作用,优点:
主要是用于负责对数据库的操作(增删改查的操作),使用该框架可以简化数据操作代码量,要程序员将更多的精力放在业务的编写上。业务复杂的情况下对数据的操作就不单纯只是DAO的操作了。    本质上是对JDBC技术的封装。封装了很多智能的功能。原有的JDBC方式访问数据库的时候的不足之处有:   a. 需要编写大量复杂的SQL语句。
B . 需要做大量的对象和记录之间关系的转换。c. 数据库之间的转换使用的时候(也就是数据库的移植),要更换的SQL语句。需要变更的是分页语句,使用数据库函数的语句。
使用了Hibernate框架可以解决上面的三个问题。
Hibernate设计原理:
   Hibernate框架是一款ORM工具。基于ORM设计思想开发出来的。ORM(Object—Relation--Mapping)基于ORM思想设计出来的还有:Hibernate,IBATIS,JPA等。他们都是需要文件信息进行操作,文件信息是必不可少的。
对象:指的就是Java的entity对象,
关系:指的是关系数据库,
映射:就是对象和数据库的对应关系。
   思想是:将程序中对象和数据库中数据记录自动映射转换。利用ORM工具,在查询的时候,可以自动将记录封装成Java对象返回,在更新,插入操作时,可以将对象自动写入数据表。向中间的SQL+JDBC操作细节,完全封装在工具底层。    要做框架的话都要学JAVA反射技术:通过反射技术可以获取类的所有信息,包括类的结构和字段属性,方法等。
Hibernate框架的主要结构:a. java实体类(n个)用于封装数据表记录的java对象类型。b. hibernate.cfg.xml(1个) Hibernate的主配置文件,里面主要定义数据库的连接参数。还可以定义框架的参数。刚启动的时候就会加载进去的。c. 文件名.hbm.xml(),Hibernate映射描述文件,里面定义了实体类和数据库之间的对应关系,比如:哪类和哪个表,属性和表字段之间的对应关系。
Hibernate主要API:
使用的时候,需要使用Hibernate提供的API,他们将sql+jdbc操作细节封装起来了。a. Configuration:主要用于加载配置文件Hibernate.cfg.xmlb. SessionFactory:通过Configuratioin获取,主要用于创建hibernate中的session对象。和servelt里面的session是一点关系都没有的,servlet里面的是客户和服务器的会话。Hibernate中的是程序和数据中的会话。c. Session:代表java程序与数据库之间的一次连接。负责对数据库进行增删改查操作。提供的方法有:save(),update(),load(),get(),list(),      load()和get()是对主键进行触发。d. Transaction:负责事务管理。Hibernate是没有自动提交的。注意的是:每次做增删查改操作必须要显示提交事务,因为:Hibernate将默认提交功能关闭。e.Query:负责执行Hibernate查询语句。
     
Hibernate使用步骤:

a. 创建工程,引入hibernate和驱动开发包,b. 在src下追加hibernate.cfg.xml主配置   方言设置:diarect:用于封装指定数据库的SQL方言   加载映射描述文件:c. 根据数据表创建entity实体类。d. 编写实体类和数据表的映射文件hbm.xml   <calss>属性里面有name:类名,属性名,,,table:对应的表名。   Class里面有一个<id>是定义的主键映射,属性有name:属性名,column:对应表中的        字段名,type:属性类型,要全部小写,如果是写成java的话要写成包名点类名点属性类型这种形式的方式写。可以指定主键的生成方式,<genderatioin> class:生成方式,非主键的用<property>来写,属性也是一样的。e. 利用hibernate API实现增删改查操作
插入一条数据的过程:
1. 创建一个实体类对象,2. 调用hibernate的API用于装载配置文件,Configuration conf=new Configuration();如果是默认的配置文件hibernate.cfg.xml则直接调用,conf.configure();如果不是的话则conf.configure(new File(“abc.xml”));3. 创建SessionFactory:SessionFactory  factory=conf.buildSessionFactory();4. 创建Session :Session session=factory.openSession();5. 获得事务:Transaction tx=session.getTransaction();6. 开启事务:tx.begin();7. 插入数据:session.save(user);8. 提交事务:tx.commit();9. 关闭session:session.close();

             ----------------课后练习------------------
1.基于Cost表做增删改查练习
2.重构资费管理模块的添加、开启、删除功能
第二天
Hibernate映射类型:
  在hbm.xml中,描述属性和字段之间映射的时候,可以使用type属性指定映射类型。Type属性可以指定java类型和hibernate类型,主要作用是指定属性值和字段值之间转换的时候,采用的转换类型。这里建议使用hibernate映射类型。   hibernate映射类型主要有下面的几种:   a. 整数类型:byte,short,integer,long;   b.浮点数类型:float,double;   c. 字符串类型:string;   d. 日期类型:date:只取年月日,time时分秒把年月日忽略,timestamp:年月日时分秒。   e. boolean类型:       yes_no.将true/false转换成Y/N       true_false;将true/false转换成T/F       ;;有些数据库没有boolean类型。可以通过和字符类型的转换。
   f.其他:big_decimal:----Bigdecimal,big_integer—Biginteger,colb:比较大的字符信息。Blob:字节信息的存储
2. ---------------------------------------------------案例------------------------------------------------------
create table t_foo(
  t_id number primary key,
  t_name varchar2(50),
  t_salary number(8,2),
  t_marry char(1),
  t_hiredate date,
  t_last_login_time date
)
-------------mysql----------------
create table t_foo(
  t_id int auto_increment primary key,
  t_name varchar(50),
  t_salary double,
  t_marry char(1),
  t_hiredate date,
  t_last_login_time timestamp
) default charset=utf8;

2.Hibernate主键生成方式
  在hbm.xml中,可以为主键指定生成方式。
具体如下:
  *a. sequence :采用指定序列生成,适用于Oracle数据库。使用格式
<generator class="sequence">
    <param name="sequence">
       foo_seq
   </param>
</generator>
 
*b.identity : 采用数据库自增涨机制生成。适用于MySQL,SQLServer数据库。
   <generator class="identity">
   </generator>
  
*c.native : 根据方言自动选择identity,
sequence等生成方式。
   <generator class="native">
   </generator>
 
*d.increment : 首先获取最大主键值,然后加1,再执行插入操作。适用于各种数据库。
先执行select max(id) from t_foo;
再执行insert into...
    <generator class="increment">
   </generator>
 
e.assigned : Hibernate忽略主键生成,不负责管理。需要程序员在程序中指定主键值
   <generator class="assigned">
   </generator>

  f.其他
uuid:采用UUID算法生成一个字符串主键值
hilo:采用高地位算法生成一个数值主键值
3. Hibernate框架的基本特性(默认的情况下采用的是批处理)
  1. 一级缓存:
(session级别缓存,默认情况开启)持久态:每次创建一个Session对象,会为这个session对象提供一个缓存区,用于缓存该session查询出来的单个对象。Session关闭的时候它就会消失。一级缓存主要是针对单个对象的。不同的session访问同一个对象的时候,要访问数据库两次,每个session只能访问自己的缓存区的对象,同一个session不同的结果对象,会对数据库访问两次。
         (session要负责将持久态对像的变化更新到数据库,在flush()的时候更新,tx在提交的时候会自动调用session的flush()).
   一级缓存区的管理方法:游离态:session.evict(obj);将obj从一级缓存移除。         session.clear();
如果session被查询,session将先到缓存中查找是否有被查询的对象,找到则直接取出,找不到则访问数据库。
Session需要负责实时维护在缓存中的数据,保证缓存中的数据与数据库中的数据的一致性,一旦用户对缓存中的数据做了修改,当commit提交事务或者执行flush()时候session会立刻将数据更新到数据库中。Commit()方法默认调用flush,然后提交事务,而flush()是将缓存区的数据同步到数据库。
一级缓存的优点:
     当利用同一个session对象多次查询同一个数据对象时,仅第一次从数据库查询,后续几次从缓冲区中取。如果缓存的对象过多会造成溢出,通过下面的方法处理。
Session session =
      HibernateUtil.getSession();
Transaction tx =
      session.beginTransaction();
for(int i=1;i<100000;i++){
     User user = new User();
     //......
     session.save(user);
     //20条调用一次flush
     if(i%20==0){
        session.flush();//同步到数据库
        session.clear();//清空缓存
      }
}
tx.commit;
HibernateUtil.close();
  2. 对象持久性:
     Hibernate框架用于实现对数据库的操作,为应用程序构建一个持久层,(由持久对象构成)
     在hibernate使用中,实体对象有三种状态:
临时状态:new
采用session对象查询出来的,受session对象管理的对象。比如:load,get,save,update方法后的对象,处在持久性的对象的特点:数据状态可以更新到数据库;对象不能被垃圾回收器回收;对象会一直在一级缓存区存放,由session管理。
游离/脱管状态:脱离了session的管理,如:调用了session.evict(),session.clear();

  3. 延迟加载:
  Hibernate提供一些方法,利用这些方法返回的对象,并没有立刻加载数据库的数据,而是在调用对象的gertter方法时才触发数据库查询,加载数据记录。
  使用延迟加载的好处是;可以降低并发量,减少资源占用,如果同步查询的数量很多,session会溢出,如果是延迟加载,可以让程序支持更多的用户。
哪些方法具有延迟加载:session.load();query.iterator(),关联属性。这些方法返回的对象里面没有数据,数据在使用的时候(调用getXXX方法时)才取。他们返回的不是实体类,而是该实体类动态子类对象,该子类重写了getXXX方法。在这个方法中触发了对数据库的访问。当调用load(),iterator()方法时,具体hibernate调用了GBLIB的功能实现了动态生成子类。Get方法查询的时候没有记录返回Null,load()方法没有记录时会异常。
Query.iterator()这个方法是和query.list()这个方法是对应的一个是返回实体类,一个是延时机制返回动态子类对象。   get()和load()方法的区别: 相同点:按照主键ID当条件查询某个对象。不同点:load()采用了延迟加载机制,get()为立刻加载;load如果没有符合记录会抛出异常,get方法会返回null;load方法返回的是动态子类对象,get方法返回的是实体类。
使用延时加载方法的时候要注意避免出现no session的异常。
动态生成子类对象的原理:具体的说是动态代理技术。注意:在自定义的类的时候不要做成final类型的,因为在很多框架中会有类似的动态生成机制
   d)延迟加载实现原理(动态代理技术)--采用延迟加载方法后,Hibernate会在底层动态的创建一个新的实体类,动态编译成class.    public class Foo$$CGLIB... extends Foo{
        //重写foo中属性的getter方法
          public String getName(){
           //判断是否有name值,没有查询DB
           return name;
       }
   }
   --Hibernate采用了cglib.jar和asm.jar两个开发包。实现了动态生成新类和编译操作
课堂补充注解:如果不是主键查询的时候用hql:from 类名 where 属性名。Query.setstring(0,);?号是从0开始,不是从1开始。
分页查询的时候:设置分页查询的参数:query.setFisrtResult(begin);设置抓取记录起点;query.setMaxResult(pageSize);设置最大抓取记录。结束点它会自己计算。
如果是在响应jsp之后要关闭session的话可以通过拦截器或者过滤器来在最后进行关闭
=========案例练习==========
1.重构资费列表显示示例
为了支持延迟加载方法,需要在项目中采用OpenSessionInView思想。可以利用Filter和Interceptor技术实现。
*.action-->拦截器前期(无)
-->Action-->DAO-->Result
-->JSP(通过标签和EL获取对象数据)
-->拦截器后期(关闭Session)
-->将HTML结果响应
如何使用同一个Session
处理的情况下:拦截器中使用的session一定要是同一个session这样对于事务的处理才是同一个事务。要使用线程池技术来获取同一个session。
方案一:利用ThreadLocal机制,实现Session与当前线程绑定      ThreadLocal<Session> sessionLocal = new ThreadLocal<Session>();
       获取session的时候要先判断session是不是存在,然后再创建新的session。
方案二:利用Hibernate框架封装的机制,实现Session与当前线程绑定
      返回当前线程绑定的session,需要在hibernate.cfg.xml增加配置
//如果没有的新建一个,然后和线程绑定
//该Session对象在事务结束自动关闭
//该Session对象必须在一个事务中使用
return sf.getCurrentSession();
//创建一个新的Session对象,
//必须手动关闭

第三天
Hibernate关系映射的作用:利用关联映射,Hibernate可以帮着查询加载对象相关的数据,可以简化查询代码,此外还可以基于关系进行增删查改操作。
一对多关系映射:
由一条字段找到多条记录。要设成set<>的属性a. 确定1的一方和多的一方,1的一般是主键,多的一般是外键,b. 由1的一方对象查询出多的一方的记录。c. 首先在1的那方实体类中添加集合属性setd. 然后在1的那方的hbm.xml中定义一对多关系映射的描述    <set name="关系属性">
       <key column="关联条件的外键字段"/>
        <one-to-many class="关联的另一方类型,即n方类型"/>
   </set>e.使用的时候,通过1的那方对象.关系属性获取多的那方的数据
多对一关系映射:
a. 需要由多方对象查询1放对象信息。b. 在多方实体类中添加属性,属性类为1方类型c. 在多方hbm.xml文件中,添加属性的映射描述信息。d. 清楚多方的实体类中外键字段描述信息和属性。就是重复出现的字段描述e. 使用时,通过多方对象.关联属性获取相关信息。
关联操作注意事项:要避免频繁使用,默认情况下,
A.  在hbm.xml中为属性添加lazy=”false”(关联属性数据在主对象加载的时候加载)   在为这个属性追加fetch=”join”(指定关联属性加载方式,可以指定为  select,join,subselect)默认的是select表示的是需要的时候加载,jion表示的是同时加载使用的是表连接的语句加载。
写一个HQL,采用join fetch关键字加载关联属性,需要自己写一个sql语句,这样可以自己来决定是什么加载注意:a方案会影响所有service对象操作,不推荐使用,如果需要关联属性随着主对象加载而加载推荐使用b方案实现。
5.  级联查询:
6.  级联添加:先插入数据在添加级联关系。
7.  级联删除:
  删除的时候不能用new出来的的对象,要使用缓存的形式进行查询了再session.ldelete();
  对主对象做删除操作的时候,关联属性电视剧也做相应的删除操作。先解除关联关系然后再删除。   a. 需要在hbm.xml中的关联属性开启级联删除操作。   b. 在执行session.delete(obj)操作时,删除的obj对象时龙session先查询出来。不要使用new出来的对象,因为不具有关联的数据,hibernate找不到相关数据。
   缺点:级联删除采用n+1个delete删除数据,因此关联数据对象n过多的时候,不推荐使用,而是采用hql语句进行批量删除。
Inverse属性:可以控制关系字段值维护的操作是由哪一方负责的,也就是两个表的关联条件字段。默认情况下由具有关系的对象双方负责,也就是不管是哪个做了操作都要对字段进行维护,让哪一方负责维护就在哪一方添加这个属性就额可以。一般是在1方关联属性中使用inverse=true,意思是要1方放弃关系维护操作,不会出现update维护关系的这种语句。只要是一对多的情况下建议使用inverse=true这个属性,
第四天
1.如何利用MyEclipse根据数据库生成实体类和映射描述文件
1)在DB Browser中建立一个与数据库的连接
2)新建一个Web Project工程
3)为工程添加Hibernate开发框架
   (导入包,添加主配置及其参数设置)
     选中工程-->右键-->MyEclipse-->Add Hibernate Capabilities...
  4)按MyEclipse向导添加Hibernate框架开发包,添加主配置文件,设置连接参数,创建一个HibernateUtil工具类  .   
  ----------生成实体类和hbm.xml-------------
  5)进入DB Browser,选中要操作的数据表,右键-->Hibernate Reverse Engineering.按向导生成实体类和hbm.xml.
  6)向导界面1:选择存放实体类和hbm文件的工程和package。
     选择要生成文件:hbm.xml,pojo,dao
  7)向导界面2: 将Type Mapping选中为Hibernate Types
 向导界面3:点击Finish完成

2.多对多关系映射
   多对多关系在数据库中需要3张表表示。
  例如AdminInfo-->Admin_Role<--Role
  如果需要根据Admin查找Role,可以建立Admin到Role的多对多关系映射。具体过程如下:
   a.在Admin实体类中追加一个集合属性,用于存储相关联的Role对象信息
   b.在Admin的hbm.xml中描述集合属性映射
<set name="关系属性" table="关系表">
   <key column="与当前类型联的关系表字段">
   </key>
   <many-to-many  class="关联的另一方类型" 
        column="与另一方类型关联的关系表字段">
    </many-to-many>
</set>


3.继承关系映射


第五天
---------总结---------
1.第一天
   理论:Hibernate作用和原理
   应用:Hibernate对单表的基本操作
2.第二天
   理论:了解什么是一级缓存,对象持久性,延迟加载
   应用:掌握OpenSessionInView模式控制Session关闭。将Session与请求处理线程绑定。使用ThreadLocal自己封装,也可以使用Hibernate3封装的getCurrentSession();
3.第三天
   理论:关联映射的作用
   应用:掌握一对多,多对一基本映射
              基于关系*查询,添加,*删除等操作
4.第四天
   理论:利用Myeclipse生成实体类和映射描述
   应用:掌握多对多基本映射和操作
              掌握继承基本映射和操作
5.第五天
   理论:了解其他的查询方式,高级特性
   应用:Hibernate的HQL查询
==============================
1)继承关系映射
   a.父类一张表,每个子类一个表,主键对等
   b.可以采用<joined-subclass>进行继承关系映射,具体如下
    --在子类追加extends 父类
    --在子类hbm.xml中定义
<joined-subclass name="子类类型"
       extends="父类类型" table="子类表">
   <key column="子类哪个字段与父类关联">
   </key>
   //子类中属性的property映射
</joined-subclass>
       
######示例表Oracle######
CREATE TABLE PRODUCT
(
ID NUMBER(5) CONSTRAINT PRODUCT_ID_PK PRIMARY KEY,
NAME VARCHAR2(20),
PRICE NUMBER(15,2),
PRODUCT_PIC VARCHAR2(100)
);

CREATE SEQUENCE product_seq;

CREATE TABLE BOOK
(
ID NUMBER(5) CONSTRAINT BOOK_ID_PK PRIMARY KEY,
AUTHOR VARCHAR2(20),
PUBLISHING VARCHAR2(50),
WORD_NUMBER VARCHAR2(20),
TOTAL_PAGE VARCHAR2(20)
);

CREATE TABLE CAR
(
ID NUMBER(5) CONSTRAINT CAR_ID_PK PRIMARY KEY,
BRAND VARCHAR2(20),
TYPE VARCHAR2(1),
COLOR VARCHAR2(50),
DISPLACEMENT VARCHAR2(20)
);
##############################

2)Hibernate查询
  *a.HQL查询
    Hibernate Query Language
    HQL与SQL语句结构相似,SQL语句是面向数据表和字段进行查询,而HQL语句是面向Hibernate映射过来的对象和属性进行查询,因此HQL被称为是一种面向对象查询语言
    HQL和SQL共同点:
      --都支持select,from,where,order by,
having,group by等子句。
      --都支持运算符表达式,例如+,-,*,/,>,<等
      --都支持in,not in,between and,like等过滤条件关键字
      --都支持分组函max,min,sum,avg,count
    HQL和SQL不同点:
      --HQL是大小写敏感的,类名和属性名严格区分大小写
      --HQL不支持select * 写法
      --HQL不支持join...on...中的on子句
      --HQL不支持表名和字段名

HQL案例:
--查询所有:from Account
--参数查询:from Account where status=?
             from Account where status=:stat
--查询部分字段:
    select id,osUsername from Service
   返回ist<Object[]>
    select new Service(id,osUsername) from Service
   返回List<Service>
--在hbm.xml中定义hql:
   Query query =  session.getNamedQuery("标识符")
--分页查询用法:
   query.setFirstResult(抓取起点从0开始计算)
    query.setMaxResult(抓取最大数量);
    List list = query.list();

  b.Criteria查询(QBC)
   了解,参考示例和Hibernate帮助文档
  c.Native SQL查询
   了解,参考示例和Hibernate帮助文档
第六天-
1.Hibernate高级特性
1)二级缓存技术
    SessionFactory级别的缓存,受SessionFactory管理,可以被不同Session访问和操作。默认是关闭。一般在使用时需要利用SessionFactory.evict()等方法显式的管理该缓存
a.什么情况可以考虑使用二级缓存
     --该对象被多个不同用户频繁使用
     --该对象更新操作不频繁
b.如何使用二级缓存
     --添加ehcache.jar开发包和src/ehcache.xml配置
     --在hibernate.cfg.xml中开启二级缓存,指定采用哪种二级缓存组件
     --需要缓存哪个对象,就在hbm.xml中添加<cache>元素配置
      <cache usage="read-only或read-write"
   region="采用ehcache.xml哪组参数缓存该对象"/>
  c.二级缓存管理
         sessionFactory.evict方法

2)查询缓存技术
    一级和二级缓存只能缓存单个对象,查询缓存可以缓存一个select查询结果。
    a.查询缓存的使用
       --要对查询的目标对象开启二级缓存
       --在hibernate.cfg.xml中开启查询缓存设置
       --在执行query.list()查询之前,
         调用query.setCacheable(true);
    b.适合使用查询缓存的情况
       --不同用户都执行相同的SQL查询和相同结果
       --查询结果集不发生改变
   
   注意:在使用关联映射时,关系属性数据默认不参与缓存,即使访问对象在缓存中存在,当访问该对象的关联属性数据时,还得去数据库查询。如果需要缓存关联属性数据,需要对关联属性和hbm.xml都设置<cache>元素

*3)悲观锁和乐观锁
    当出现多个用户同时执行更新等操作时,会出现事务交叉更新操作的冲突,会破坏业务和数据的完整性。可以使用悲观锁和乐观锁解决这类问题。
a.悲观锁机制:在进行数据查询时追加一个锁机制,进行业务操作,此时其他用户不能进行增删改操作,在事务结束时会自动将锁释放,其他用户可以继续执行此类操作。
     悲观锁特点:将用户操作一个一个处理,可以解决更新并发问题,缺点是处理效率比较低。
   Hibernate悲观锁机制一般是借助于数据库锁机制。
   session.load(Train.class,1,);
   session.get(Train.class,1);
   
b.乐观锁机制:多个不同用户都可以同时对数据库记录进行查看和更新操作,但是最先commit提交的用户会执行成功,后续用户会以异常形式提示失败。
乐观锁是借助于一个版本字段进行控制,当并发操作中一个用户成功提交了,版本字段值会自动加1,后续提交的对象版本信息小于数据库版本字段值会被hibernate阻止掉。
乐观锁特点:允许多个用户同时操作,处理效率相对较高。
乐观所使用步骤:
        --将原有数据表追加一列版本字段,初始值0
        --在实体类中添加版本属性
        --在映射描述文件中采用<version>元素定义版本属性和版本字段的映射
        --当发生多个事务并行交叉执行时,第一个提交的成功,后续提交的会抛出异常。可以异常捕获给用户一个友善的提示。
  
==============示例表=================
create table train(
t_id number primary key,
t_value number,
t_version number);

insert into train values (1,100,0);
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics