cy伊始吧 关注:11贴子:581
  • 9回复贴,共1

hibernate课堂笔记系列

只看楼主收藏回复

1、什么是Hibernate?
Hibernate是数据访问层的框架,对JDBC进行了封装,
是针对数据访问层提出的一套面向对象的解决方案。
Hibernate允许我们直接访问实体对象,它会将这种
访问自动转换为SQL并执行,从而达到间接访问数据
库的目的,可以提高我们数据访问层的开发效率。
2、为什么用Hibernate?
1)使用JDBC开发,有如下问题:
--需要在代码中写大量的SQL
--在SQL中包含大量的?,要给他们赋值
--要把ResultSet转换成实体对象
--使用了数据库特有的关键字或函数,如果更换
数据库的话,这些代码不可复用,即移植性差
2)使用Hibernate开发,可以解决:
--自动生成SQL
--能够自动的给?赋值
--能够根据实体对象和数据库的关系,自动将
结果集转换为实体对象
--采用统一的API访问数据库,这样可移植性好
3、Hibernate设计原理
--Hibernate采用ORM设计思想,对JDBC进行的封装
--ORM:Object Relation Mapping,即对象关系映射。
是Java对象和关系数据库之间的映射。
--Hibernate是实现了ORM思想,也就是解决了
实体对象和关系数据库之间映射的问题。
维护了实体类和数据库的关系,以及类中属性
和数据库字段的关系。
--有了这样的映射关系,Hibernate就可以让我们
直接访问实体对象,然后根据对象与数据库的关系,
自动的转换SQL并执行,达到访问数据库的目的。
对象->关系配置文件xml->表/字段
->生成SQL->结果集->实例化对象->赋值


1楼2014-03-10 22:10回复
    4、Hibernate体系结构
    1)hibernate.cfg.xml
    是Hibernate的主配置文件,可以用来设置数据库
    连接参数以及Hibernate框架参数等。
    2)实体类
    用来封装数据库结果的。
    3)hbm.xml
    是映射关系文件,用来配置实体类和数据库表的关系,
    以及类中属性和表中字段的关系。
    4)Hibernate底层的API
    主要是用来解析映射关系文件的,能够得到类与库
    的关系,从而自动的帮我们生成SQL并执行。
    5、Hibernate常用API
    1)Configuration
    用于加载主配置文件的,同时也加载映射关系文件
    2)SessionFactory
    用于创建Session对象的
    3)Session
    跟HttpSession没任何关系。
    是Hibernate中数据库连接会话,可以理解为
    Connection,用于进行增删改查操作。
    4)Transaction
    用来控制事务
    5)Query
    用来做特殊查询
    *6、Hibernate使用步骤
    1)导包
    2)引入主配置文件hibernate.cfg.xml
    3)创建实体类Cost
    4)引入映射关系文件Cost.hbm.xml,
    --该文件与实体类处于相同路径下
    --该文件与实体类同名
    --将该文件追加到主配置文件中
    5)调用Hibernate的API,执行增删改查。
    *7、Hibernate映射类型
    1)映射关系文件中,需要设置实体类中属性和表中
    字段的关系,并且要设置转换时所需的类型,即
    type="java.lang.String"。
    2)此种映射类型的设置方式有2类
    a、Java类型
    --如果某些类型Java自带类型无法满足时,
    可以自己创建一个类,实现UserType接口,
    以此实现类来充当映射类型。
    b、Hibernate提供的类型
    --整数:byte,short,integer,long
    java.lang.Integer <-> number(4)
    --小数:float,double
    java.lang.Double <-> number(9,2)
    --字符:string
    java.lang.String <-> varchar2(20)
    --日期(年月日):date
    java.sql.Date <-> date
    --时间(时分秒):time
    java.sql.Time <-> date
    --时间戳(年月日时分秒):timestamp
    java.sql.Timestamp <-> date
    --布尔:yes_no,true_false
    yes_no:java.lang.Boolean <-> char(1) y/n
    true_false:java.lang.Boolean <-> char(1) t/f
    注意:这些类型都要小写


    2楼2014-03-10 22:10
    回复
      2025-08-03 15:19:23
      广告
      不感兴趣
      开通SVIP免广告
      1、Hibernate主键生成方式
      1)sequence,采用序列的方式生成主键,
      只是针对ORACLE数据库的。
      <generator class="sequence">
      <param name="sequence">序列名</param>
      </generator>
      2)identity,采用数据库自增长的方式生成主键,
      针对MySql、SQlServer等数据库的。
      <generator class="identity"></generator>
      3)native,根据方言来自动的选择主键生成方式,
      若方言是Oracle则使用sequence,若方言是其它
      数据库则使用identity。
      <generator class="native">
      <!-- 如果不是Oracle,
      这里的param配置将忽略 -->
      <param name="sequence">序列名</param>
      </generator>
      4)increment,是Hibernate提供的自增长机制,
      不是数据库自带的自增长,有别于identity。
      Hibernate提供一个组件,在需要生成ID时,该
      组件会查询这张表主键的最大值,然后+1,以此
      作为新的主键。
      <generator class="increment"></generator>
      注意:此种方式不推荐使用,原因是在并发量大
      的时候,会存在重复性问题,不安全。
      5)assigned,采用忽略的方式来处理,即Hibernate
      不负责主键的生成,需要程序员手动来维护主键。
      <generator class="assigned"></generator>
      6)uuid/hilo,采用uuid/hilo算法来生成一个主键,
      生成的主键是一个长字符串,可以保证不重复,
      但是没有规则。
      <generator class="uuid"></generator>


      3楼2014-03-10 22:10
      回复
        *2、Hibernate一级缓存(默认开启)
        1)什么是一级缓存?
        Hibernate在创建Session对象时,会自动的给创建的
        对象分配一块缓存区,该区域是给Session来缓存
        数据的,是由Session来负责管理的,我们称该缓存
        区域为一级缓存,又称Session级缓存。
        2)一级缓存的特点
        --每一个Session对象都有自己的缓存区,即一级
        缓存是单个Session独享的
        --一个Session不能访问其它Session的缓存区,即
        一级缓存不能交叉访问
        --在访问数据库时,Hibernate会优先向缓存查找
        要访问的数据,如果缓存区存在数据,则直接
        返回。如果缓存区不存在,再向数据库查找并
        返回,同时将刚查询出的数据放到缓存区。
        --一级缓存只能缓存实体对象,不能缓存集合。
        3)一级缓存的优点
        --减少数据库访问次数,从而提高效率
        4)验证缓存
        --使用同一个Session,查询同一条数据多次,
        发现只输出一个查询SQL,说明只查询了
        一次数据库,验证了缓存的存在。
        --使用不同的Session,查询同一条数据多次,
        发现输出了多个SQL,说明了每个Session不能
        访问其他Session的缓存区,即Session级缓存
        是独享的,不能交叉访问。
        --使用同一个Session,查询不同的数据多次,
        发现输出了多个SQL,说明每次查询的结果
        会被缓存,而没有查询出的结果与缓存无关。
        5)一级缓存的管理
        --session.evict(obj):将obj从缓存中移除
        --session.clear():移除缓存中全部的对象
        --session.close():释放缓存区


        4楼2014-03-10 22:11
        回复
          3、Hibernate对象持久性
          1)解释
          使用Hibernate的API操作的实体对象,我们称之为
          Hibernate对象。该对象的持久性可以理解为它的
          生命周期中对象状态的变化。
          2)Hibernate对象存在3种状态
          a、临时态
          --new出来的对象,即为临时态
          --对持久态的对象执行delete,可以将其转变
          为临时态
          --临时态的数据能够被垃圾回收
          b、持久态
          --对临时态的对象执行save,update,可以将其
          转变为持久态
          --对游离态的对象执行save,update,可以将其
          转变为持久态
          --执行get,load,list,iterate方法查询出来的对象,
          其状态就是持久态
          *持久态对象具有的特征
          --持久态对象不能被垃圾回收
          --*持久态对象存在于一级缓存中
          --*持久态对象可以自动与数据库同步更新
          --*更新的时机为事务提交,或者是
          session.flush(),实际上事务提交时就会
          调用session.flush()。
          c、游离态
          --对持久态的对象执行evict,clear,close,可以
          将其转变为游离态
          --游离态的数据能够被垃圾回收
          注意:
          --当调用query.list()方法查询全部数据时,查询到
          的结果会拆开成一个一个的实体对象,单独的存
          到一级缓存区。
          --那么我们如果再调用get方法查询某一个数据时,
          该数据由于存在于一级缓存区,因此不会重新
          执行查询。
          --如果我们再调用query.list()方法查询全部数据时,
          由于此方法的目的是得到所有的数据,即要求
          返回一个List类型的对象,而一级缓存区中的对
          象都是实体类型,没有集合类型,因此无法从
          缓存中得到这个值,需要重新查询。


          5楼2014-03-10 22:11
          回复
            *4、Hibernate延迟加载(默认开启)
            1)什么是延迟加载
            Hibernate中有一些查询方法执行后,并没有立刻
            查询数据库,而是返回一个实体对象,该对象中
            只有ID有值,其它属性均为空。当我们访问这个
            对象时,Hibernate再去查询数据库,我们把这种
            推迟查询的行为称之为延迟加载。
            注意:
            --返回的对象并不是null,只是其内部的属性为空
            --如果你仅仅访问的是ID,Hibernate也不去
            查询数据库。
            2)什么方法采用延迟加载?
            --session.load(Class,id)
            --query.iterate()
            执行了一次查询,但是仅仅是查询ID字段,然后
            返回一组实体对象,这些对象中仅仅是ID字段
            有值的。
            --关联查询
            注意:load和get的区别
            --load延迟加载,而get直接查询
            --load查不到结果将报错,
            而get方法查不到结果会返回null。
            3)延迟加载有什么好处?
            --可能会减少数据库访问次数
            --可以提高内存使用率
            4)示例演示延迟加载
            5)使用延迟加载方法时,需要注意的问题
            --避免session提前关闭,即在使用对象前关闭,
            否则报错如下:
            org.hibernate.LazyInitializationException:
            could not initialize proxy - no Session
            解决方式:
            --不使用延迟加载的方法load,iterate
            --*想办法,在使用对象之后关闭session
            6)Open Session In View
            --Servlet中考虑用filter
            --Struts2中考虑用拦截器
            追加处理session关闭的拦截器,在执行完ai.invoke
            方法之后,调用HibernateUtil.closeSession,来
            关闭session。由于invoke方法实际上是执行了
            Action->Result->Jsp,并且我们是在Jsp上调用
            的对象,因此在invoke之后关闭session,就相当于
            在Jsp加载完(对象使用完)之后关闭session,达到
            了使用对象之后关闭session的目的。
            --Spring中考虑用AOP


            6楼2014-03-10 22:11
            回复
              7)延迟加载的原理
              Hibernate中采用动态代理CGLIB的技术,来实现
              延迟加载。即在运行时,当查询某对象时,它返回
              的不是这个对象的类型,而是动态的生成一个对象
              的子类型,子类型中做了特殊的处理,才实现了
              延迟加载。
              public class Emp$$EnhancerByCGLIB$$e580f75e
              extends Emp {
              public String getName() {
              if(没有查询过) {
              做查询:查库,给属性赋值
              }
              return name;
              }
              }
              5、一级缓存、对象持久性、延迟加载
              1)当对象处于持久态时,位于一级缓存中
              2)使用load,iterate查询时,由于采用了延迟加载,
              直接返回的是一个空对象,在未使用该对象前,
              它是临时态的,不存在于一级缓存中。
              3)这三者我们将重点放在持久态的观察上,
              如果对象转变为持久态,则存在于一级缓存中。
              答疑:
              1、资费修改时,丢失值或报错的问题
              1)在修改页面上追加隐藏文本框将不需要修改的值
              存一下,然后提交时这些值会带给cost,从而保存
              时能存上,否则这些值为空,导致Hibernate的更新
              使这些字段为空。
              2)在hbm.xml中,字段property设置上,追加属性
              update="false",这样在Hibernate做更新时,
              不会将这个字段拼到update语句中。
              3)在hbm.xml中,class设置上,追加属性
              dynamic-update="true",这样在Hibernate做更新
              时,会将实体对象中非空的属性拼到update语句中。
              问题
              1、在批量插入数据时,数据量很大,在Hibernate中
              应该如何处理?
              //假设当前传入的emps有的size为10000
              public void add(List<Emp> emps) {
              Session session = HibernateUtil.getSession();
              Transaction ts = session.beginTransaction();
              for(int i=0;i<emps.size();i++) {
              Emp emp = emps.get(i);
              session.save(emp);
              if(i%20==0) {
              //将emp同步至数据库,但没有commit
              session.flush();
              //由于emp已经同步,可以转变为游离态
              session.clear();
              }
              }
              ts.commit();
              session.close();
              需要利用该字段
              --使用Hibernate关联映射时,service方实体类
              中已经有了account方的实体对象,通过该对象
              可以知道他们的关联关系,也可以知道外键的值
              getAccount().get(),因此外键字段可去掉。
              --归根到底,我们原先要accountId无非就是为了
              查找对应的Account,现在Account已经存在于
              Service中,就不需要accountId了。


              7楼2014-03-10 22:12
              回复
                *4、关联操作
                1)关联查询
                a、延迟加载
                --lazy="true"时,是延迟加载,默认的情况
                --lazy="false"时,不延迟加载
                b、连接查询
                --fetch="select",不连接查询,默认情况
                --fetch="join",采用连接查询的方式
                --一旦fetch="join",采用了连接查询,那么
                延迟加载就失效了。
                c、写HQL,通过join fetch来连接查询
                --from Account a join fetch a.services
                where a.id=?
                --from Service s join fetch s.account
                where s.account.id=?
                注意:HQL中参数赋值,从0开始
                需要利用该字段
                --使用Hibernate关联映射时,service方实体类
                中已经有了account方的实体对象,通过该对象
                可以知道他们的关联关系,也可以知道外键的值
                getAccount().get(),因此外键字段可去掉。
                --归根到底,我们原先要accountId无非就是为了
                查找对应的Account,现在Account已经存在于
                Service中,就不需要accountId了。
                *4、关联操作
                1)关联查询
                a、延迟加载
                --lazy="true"时,是延迟加载,默认的情况
                --lazy="false"时,不延迟加载
                b、连接查询
                --fetch="select",不连接查询,默认情况
                --fetch="join",采用连接查询的方式
                --一旦fetch="join",采用了连接查询,那么
                延迟加载就失效了。
                c、写HQL,通过join fetch来连接查询
                --from Account a join fetch a.services
                where a.id=?
                --from Service s join fetch s.account
                where s.account.id=?
                注意:HQL中参数赋值,从0开始
                1、多对多关联
                例:角色和管理员具有多对多的关系,当我们维护
                管理员数据时,要同时维护它与角色的关系。
                希望在新增管理员时,可以选择角色,同时保存。
                管理员数据存在管理员表,角色数据是体现在
                关系上,存在关系表中。
                1)分析关联关系,明确关联字段
                --关联关系:多对多
                --admin_info.id=admin_role.admin_id
                admin_role.role_id=role_info.id
                2)实体类
                --在Admin中追加属性roles,类型为Set<Role>
                --一定是实体对象的关系,中间表只是为了解决
                问题而设计的手段,并不体现在实体对象中
                3)Admin.hbm.xml
                --在此配置文件中追加与Role的多对多关系设置
                --<set name="关联属性" table="中间表名">
                <key column="Admin相关的关联字段名"/>
                <many-to-many class="关联属性类型"
                column="Role相关的关联字段名"/>
                </set>
                注意:
                --不要设置inverse="true",即不要放弃关联字段
                维护的控制权,因为关联字段在中间表中,并
                不是在另一方表中,另一方的表由于没有变更
                也没有触发关联字段的维护,因此不要这样做。
                --不必写cascade直接就可以自动维护中间表的
                数据,如果写了cascade="all",就可以自动
                维护另一方(role_info)的数据。


                8楼2014-03-10 22:12
                回复
                  2025-08-03 15:13:23
                  广告
                  不感兴趣
                  开通SVIP免广告
                  2、继承关联
                  例:去淘宝买东西,搜iphone后,出现的结果中
                  包含iphone手机、iphone手机壳、贴膜、挂饰、
                  iphone刷机指南等。
                  场景:有book表,phone表以及其他很多个商品表,这些
                  商品都有公共属性,希望他们能被复用,并且方便
                  搜索时可以搜索到全范围(包含book,phone...)的
                  商品。针对这种情况,我们建表时,可以将公共
                  字段提取到一个公共表中,然后通过1对1的关系
                  与之关联,从而可以复用其数据,和继承关系
                  相似,因此可以看成是对继承的模拟。
                  1)分析表之间关系,明确关系字段
                  --创建公共属性表product(id,name,price,desc)
                  --创建书籍商品表book(id,publisher,author,words)
                  --一对一的关系
                  --produce.id=book.id
                  2)处理实体类
                  --创建Product
                  --创建Book extends Product
                  3)写hbm.xml配置文件
                  --Product.hbm.xml,正常写,普通的写。
                  关于id设置sequence,自动生成。
                  --Book.hbm.xml,特殊的写法
                  <joined-subclass name="子类型" table="表名"
                  extends="父类型">
                  <key column="关系字段名"/>
                  <property/>
                  </joined-subclass>
                  注意:
                  --子类的配置文件中,不需要设置inverse,cascade,
                  并且也没有这2个属性。
                  3、HQL的使用
                  1)不以ID为条件来做HQL查询
                  参考test1,test2
                  2)查询一部分字段
                  参考test3,test4
                  --如果在select后面new了对象,那么要保证这个
                  对象具有相应的构造器
                  --new com.tarena.entity.ServiceVO,
                  如果new的对象没有相应的hbm.xml配置文件,
                  那么要写完整路径。
                  3)将HQL定义在hbm.xml中
                  参考test5
                  <query name="hql名">
                  <![CDATA[
                  HQL
                  ]]>
                  </query>
                  --最好将HQL用<![CDATA[]]>包含,避免有特殊
                  字符解析出现问题
                  --需要调用session.getNamedQuery方法来执行
                  此HQL,方法中的参数为HQL的名称
                  1、Hibernate访问数据库的其它方式
                  1)Criteria(了解)
                  --可以理解为HQL的替代品,是以API的方式
                  来动态的拼一个HQL。
                  --Criteria,Restrictions
                  2)Native SQL
                  --Hibernate出于兼容性考虑,当自身提供的访问
                  数据库的方法不能满足需求时,它允许我们写
                  一个SQL,来帮助我们使用JDBC的方式执行。
                  --在Hibernate框架下,尽量使用它提供的手段。
                  在很特殊的情况下,Hibernate满足不了需求,
                  才考虑使用SQL.


                  9楼2014-03-10 22:12
                  回复
                    *2、Hibernate高级特性
                    1)二级缓存(默认关闭)
                    a、什么是二级缓存
                    --是SessionFactory级别的缓存,
                    由SessionFactory负责管理。
                    --二级缓存默认关闭。
                    --二级缓存也是用来缓存实体对象,
                    SessionFactory下所有的Session都可以访问
                    该二级缓存区域。
                    b、二级缓存的使用步骤
                    --导包ehcache.jar
                    --导入缓存配置文件ehcache.xml
                    --在主配置文件hibernate.cfg.xml中设置开启
                    二级缓存,并且设置缓存驱动。
                    --想缓存哪个实体对象,就修改其hbm.xml
                    配置文件,追加<cache>元素。
                    2)查询缓存
                    1、什么是查询缓存?
                    --可以理解为一个特殊的二级缓存
                    --查询缓存可以缓存除对象之外的东西,
                    比如:集合、数组等
                    --基于二级缓存
                    --默认关闭的
                    2、使用步骤
                    --开启二级缓存
                    --在主配置文件hibernate.cfg.xml中,设置
                    开启查询缓存
                    --在代码中,查询之前设置其可以缓存的标志,
                    setCacheable(true)
                    3、Hibernate中并发处理
                    1)悲观锁
                    --不管发生什么情况,即使不会出现问题,也悲观
                    的假设其会出现问题,那么这种处理问题的方式
                    为悲观的方式。
                    --我们处理一条数据,多个线程同时访问的并发
                    场景时,往往采用加锁的机制,即当某线程访问
                    该数据时,对该数据加锁,不允许其他线程访问。
                    --不管结果是否有问题,都统一采用加锁方式来
                    处理,称之为悲观锁。
                    --在某线程中加悲观锁后,就只允许当前线程更新
                    其数据,其它线程更新不了,需要排队。直到
                    当前线程更新完毕,并且提交事务之后,其它
                    线程才能去更新。
                    优缺点
                    --很严谨、安全,不会让数据出现问题
                    --由于采用统一的方式去严格处理,那么当不会
                    出现错误的情况发生时,这个处理是多余的,
                    消耗了资源、降低了效率。
                    2)乐观锁


                    10楼2014-03-10 22:13
                    回复