码迷,mamicode.com
首页 > Web开发 > 详细

Hibernate要点总结

时间:2016-06-12 02:59:45      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:

1、什么是Hibernate

    1)Hibernate是数据访问层的框架,对JDBC进行了封装,是针对数据访问层的面向对象的解决方案。
    2)Hibernate允许我们直接访问对象,然后将访问自动转化为SQL去执行,从而达到间接访问数据库的目的,简化代码开发,提升开发效率。

2、为什么使用Hibernate

    1)使用JDBC开发出现的问题
        --需要在代码中写大量的SQL
        --需要给大量的?赋值
        --需要将结果集转换为实体对象
        --在SQL中可能会写不同数据库特定的函数,移植性差。例如分页查询、主键生成方法、数据库函数等。
    2)使用Hibernate可以解决上面的问题
        --基本上不需要写SQL,因为Hibernate可以自动生成SQL并执行
        --可以自动给?赋值
        --可以自动将结果集转换为实体对象
        --Hibernate提供通用的API来访问不同的数据库,移植性好。
    3)补充JDBC与Hibernate的优缺点
        a、JDBC优点:效率高
        b、Hibernate缺点:效率相对于JDBC要低

*3、Hibernate的设计原理(思想)

    1)Hibernate是采用了ORM的思想,对JDBC进行的封装。
    2)ORM:Object Relation Mapping,即对象关系映射,指的是Java对象和关系数据库的映射。
        Hibernate框架是ORM的一种实现,解决了对象和数据库数据映射问题。在数据库添加或更新时,可以将一个对象自动写入或更新数据表;查询时,可以将记录自动封装成对象返回。这些操作在中间执行时所涉及的细节开发者不用参与和关注。
        --之前使用JDBC开发时,需要知道数据库表和实体对象的关系,以及字段和对象属性的关系,比如需要知道COST表和Cost对象的关系。那么这种关系我们之前是手动维护的,比如:
            cost.setName(rs.getString("name"));
            ps.setString(2,cost.getName());
        --ORM思想是希望将这种关系的维护提炼出来,用一个公共的组件描述,那么在我们访问数据库时,需要使用这种关系时,可以复用基于ORM思想提炼出来的关系
        --正是由于存在这样通用关系的描述,Hibernate才可以让我们直接访问Java对象,从而通过关系转换成SQL自动执行。
        --Hibernate中将这种关系定义在XML配置文件中。
            

4、Hibernate体系结构

    1)hibernate.cfg.xml(1个)
        是Hibernate的主配置文件,用于配置数据库连接参数,以及Hibernate框架参数。
    2)POJO实体类(n个)
        是Java类型,用于封装表中的数据
    3)xxx.hbm.xml(n个)
        是关系映射文件,用于配置表与实体类的关系,以及表中字段与类中属性的关系。
    4)Hibernate底层API
        主要是用于解析主配置文件,以及关系映射文件,然后根据关系自动生成SQL并执行。
    

5、Hibernate常用API

    1)Configuration
        用于解析主配置文件的,同时也可以加载hbm.xml信息
    2)SessionFactory
        用于创建Session对象,对JDBC的connection对象的封装。
    3)Session
        是数据库连接会话,相当于是数据库连接。负责执行增删改操作,提供了save,update,delete等方法。
        注意:此Session和HttpSession没有任何关系。
    4)Transaction
        用于控制事务。默认情况下,Hibernate不会自动提交,因此需要事务控制才能对数据库更新。
    5)Query
        用于做特殊查询(HQL)

*6、Hibernate使用步骤

    1)导包(Hibernate开发包、数据库驱动包)
    2)引入主配置文件hibernate.cfg.xml
    3)创建实体类Emp
    4)*创建关系映射文件Emp.hbm.xml
        --该配置文件必须和实体类同名
        --该配置文件必须和实体类位于同一个包下
        --在主配置文件中引入该关系映射文件
    5)使用Hibernate的API,来进行增、删、改、查

*7、Hibernate映射类型

    1)Hibernate中支持2种映射类型
        --Java类型
        --Hibernate定义的类型
    2)使用Java类型不能自动处理布尔值,如果想使用Java类型来处理,需要自己定义一个类型,该类型需要实现一个接口UserType
        举例:创建类
        com.*.type.MyBoolean implements UserType
        在hbm.xml中,type="com.*.type.MyBoolean"
    3)Hibernate定义的映射类型(推荐使用)
        --整数:byte,short,integer,long
        --小数:float,double
        --字符:string
        --日期(年月日):date
            可以将数据库日期类型转换为java.sql.Date
        --时间(时分秒):time
            可以将数据库日期类型转换为java.sql.Time
        --时间戳(年月日时分秒):timestamp
            可以将数据库日期类型转换为java.sql.Timestamp
        --布尔:
            yes_no:数据库中存y/n,对应属性true/false
            true_false:数据库中存t/f,对应属性true/false
        使用:
            type="timestamp"
        注意:

            Hibernate定义的映射类型都是小写的


8、Hibernate主键生成方式

    Hibernate框架提供了多种主键生成方式,使用时,通过hbm.xml文件<id>元素部分,利用<generator class="主键生成类型">指定。
    1)sequence
        --是采用sequence来生成ID,针对的是Oracle数据库
        --<generator class="sequence">
                <param name="sequence">序列名</param>
            </generator>
    2)identity
        --采用数据库主键自增长的机制来生成ID,针对初Oracle外的数据库,如MySql,SqlServer
        --<generator class="identity"></generator>
        注意:创建表时,指定主键可以自增长
    3)native
        --Hibernate会根据你设置的方言,判断出是哪种数据库,如果是Oracle就使用sequence方式生成主键,如果不是就使用identity方式生成主键。
        --<generator class="native">
                <param name="sequence">序列名</param>
            </generator>
    4)increment
        --也是采用自增长的方式生成主键,但是这种方式不是用数据库的机制,而是Hibernate自己的机制,并且适用于所有的数据库。
        --Hibernate提供一个组件,在需要主键时,它会从表中查询出最大的ID值,然后+1,以此结果作为新的主键。
        --<generator class="increment"></generator>
        --注意:通常不用,原因时在并发量大时可能会出现并发问题。
    5)assigned
        --Hibernate放弃生成主键,由程序员自行维护主键字段的值。
        --<generator class="assigned"></generator>
    6)uuid、hilo(高低位算法)
        --采用uuid/hilo算法来生成一个主键,该主键是一个没有规律的,不重复的,长的字符串
        --<generator class="uuid"></generator>

*9、Hibernate一级缓存(默认开启)

    1)什么是一级缓存?
        --Hibernate在创建Session时,会自动的给Session分配一块内存空间,用于存储该Session取到的对象值,那么这个内存空间就是一级缓存,或称为Session级缓存。
    2)一级缓存的维护
        --在使用Session进行查询时,Hibernate会优先上一级缓存中查找对应的数据,如果缓存中已经存在则直接返回,不用查库。如果缓存中不存在,再去执行查询数据库的行为。减少了对数据库的访问。
        --Session在执行完查询数据库后,会将新查到的数据自动放入一级缓存中。
    3)一级缓存的管理
        --session.evict(Object);
            把传入的对象从一级缓存中移除。
        --session.clear();
            移除一级缓存中所有的对象。
        --session.close();
            关闭session,释放缓存空间。
    4)*重点关注
        --Session级缓存是独享的,即每创建一个Session
            对象,就给这个对象分配一个独立的缓存区,
            其他的Session不能访问当前Session的缓存区。
        --Session仅仅是把查询到的数据放入缓存区,
            没有查询过的,是不会放入缓存区。
    注意:
        --一级缓存缓存的目标只能是实体对象

10、Hibernate对象持久性

    1)Hibernate中实体对象具有3种状态,围绕着这三种状态的转换过程,我们称之为对象持久性。
    2)3种状态
        a、临时态
            --通过new创建的对象是临时态的
            --临时态的对象可以被垃圾回收
            --持久态的对象通过delete方法可以转化为临时态
        *b、持久态
            --通过session的save,update方法可以将临时态/游离态的对象转化为持久态
            --通过session的get,load方法将查询到的对象默认置为持久态
            特点:
                --持久态的对象不能被垃圾回收
                --持久态的对象存在于一级缓存中,由Session负责管理
                --持久态的对象可以自动的与数据库同步更新
                --持久态的对象同步的时机是事务提交时即ts.commit,实际上是调用session.flush()时触发同步的,commit方法中调用了session.flush()
                注意:session.flush();//将缓存中改变的对象数据更新到数据库记录仅仅是触发同步,但并没有提交事务
                    即:ts.commit()=session.flush()+原有事务提交功能
        c、游离态
            --通过session的evict,clear,close方法可以将持久态的对象
                转化为游离态(从一级缓存中移除)
            --游离态的对象可以被垃圾回收

11、flush()和commit()扩展:

        session.flash()和缓存相关。执行时会清除session缓存并向数据库发送SQL语句并执行,但此时如果数据库当前存在一个事务,数据库会先将这些SQL语句缓存起来,那么此时在数据库中是无法看到SQL语句执行结果的。除非执行commit提交了事务。只要没有执行commit()方法,就能通过rollback()方法进行回滚。
    1)session在什么情况下清理缓存:
        --默认情况下,当应用程序提交事务,如:Transaction.commit;
        --当我们显示调用flush的时候
        --在执行某些查询的时候,如:iterate
    2)session.flush()主要完成两件事情:
        --清理缓存
        --执行sql
    3)flush执行的顺序:hibernate按照save,update,delete顺序提交相关操作commit()和事务相关。执行时会先隐式调用flush()方法,再提交事务。执行之后无法rollback()进行回滚。

*12、Hibernate延迟加载

    1)什么是延迟加载?
        Hibernate中有一些方法,在查询时并不是立刻查询数据库返回结果,而是给返回一个空(属性值)对象,当我们真正去使用这个对象getter时,才触发查询。这种将查询时机推迟到使用时间的机制,称之为延迟加载。
    2)哪些方法具有延迟加载机制
        a、session.load(Emp.class, id);//查询单个对象
            --当调用该方法时,Hibernate并没有立刻查询数据库,而是new Emp(),然后setId(id),即我们得到的对象是一个只有id有值,其他属性为空的对象。
            --当我们调用该对象时,比如e.getName()时,此时会触发查询。我们使用这个对象任何一个属性都可以触发查询,但使用id却不触发。
            --不管是调用哪个属性触发的查询,那么本次查询都会将当前的记录完整的返回,此时对象中属性都可以有值。
        b、query.iterate();//查询多个对象集合
            --当调用该方法时,Hibernate会返回一个迭代器,迭代器中存的是一个空(属性空)的对象,该对象中仅仅是id有值,其他属性为空。
            --此时,Hibernate执行了一次查询,但是为了效率,仅仅是查询出了ID的值select id from emp;
            --当我们从迭代器中读取出对象,并且使用该对象时会触发真正的查询,将其他属性都查询出来,此时是根据当前对象的ID查询当前ID对应的一条记录,并非是查询所有的记录。
        c、关联属性查询
    3)延迟加载的好处
        --可以提升内存资源的使用率
        --可以降低对数据的并发访问(使用时机错开)
    4)在使用延迟加载时要注意,不能在使用对象前关闭Session否则会报错:
        LazeInitializationException:No Session
        两种解决办法:
        --不使用延迟加载的方法session.load()、query.iterate(),可使用session.get()、query.list()等
        --在使用对象后关闭Session
    5)在项目中,采用OpenSessionInView的机制来保证session关闭的时机。
        a、OpenSessionInView指的是在视图层加载阶段保证Session处于非close状态,而视图层加载完成后,再关闭Session。
        b、如何实现
            --Servlet:监听器

public class MyFilter implents Filter{
    public void doFilter(request,response,chain){
        //添加逻辑--前期处理
        //通过过滤器,调用后续资源
        chain.doFilter(request,response);
        //添加逻辑--后期处理(关闭session)
    }
}
            --Struts2:拦截器
                创建拦截器OpenSessionInViewInterceptor,在拦截方法中,先调用ai.invoke(),该方法实际上会调用Action的业务方法,并根据返回值找Result,且加载JSP页面,因此在此方法后调用HibernateUtil.closeSession()方法就相当于是在页面加载完成后关闭Session,从而达到了推迟关闭Session的目的。
public class MyInterceptor implements Interceptor{
    public  String intercept(ActionInvocation in){
        //前期处理
        in.invoke();//执行Action--Result
        //后期处理(关闭session)
    }
}
            --Spring:AOP
    6)延迟加载实现原理
        a、Hibernate是采用CGLIB的动态代理技术,在我们调用load,iterate方法时,返回的是指定类型的子类对象,这种在程序运行过程中创建子类对象的方式称为动态代理技术。

        b、代码解读

public class Emp$.$.EnhancerByCGLIB$.$.88def978 extends Emp {//.是分割示意用,避免排版紊乱
                    //覆写get方法
                    public String getName() {
                        if(没有查询过) {
                            1.查询并给当前对象所有属性赋值
                            2.设置当前对象为查询后的状态
                        }
                        return this.name;
                    }
                    ...
            }

13、扩展1(大批量数据的分批同步处理方法—避免缓存溢出)

Session session = HibernateUtil.getSession();
Transaction ts = session.beginTransaction();
for(int i=0;i<10000;i++){//不做处理,容易使一级缓存溢出
    Foo foo = new Foo();//foo处于临时态
    //TODO 设置不同属性
    session.save(foo);//foo处于持久状态,会放入缓存
    if(i%20==0){
        session.flush();//将缓存foo对象同步
        session.clear();//清除缓存foo对象
    }
}
tv.commit();//不能分批提交,即不可破坏事务的完整性
session.close();

14、扩展2(大批量数据对象的单独处理方法—避免缓存溢出)

for(String id : ids){//如果数据量大,所有取出的对象放进一级缓存而不作处理,容易溢出
    Foo foo = (Foo)session.load(Foo.class,id)
    //处理foo
    session.evict(foo);//手动移除对象,提升健壮性
}





Hibernate要点总结

标签:

原文地址:http://blog.csdn.net/daijin888888/article/details/51605071

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!