Hibernate阶段性总结(一)

本文是关于Hibernate ORM框架的阶段性总结,介绍了其作为持久层框架的角色,以及项目组件和开发流程。详细讲解了Hibernate的配置、Session工厂、事务处理、主键生成策略和HQL语句的使用。此外,还探讨了缓存机制、对象状态以及解决懒加载的方法,为读者提供了深入理解Hibernate的指导。
摘要由CSDN通过智能技术生成

hibernate它是一个实现对JDBC轻量级封装的ORM(对象关系映射)的框架。处于项目的持久层。主要学习它的hibernate api和hibernate.cfg.xml,对象关系映射文件


这边介绍下项目的组成部分:

WEB层  

业务逻辑层(调用HQL语句去操纵持久层,这样就不用去关心到底使用哪种数据库,持久层会自己去判断) 

DAO层 

持久层(对JDBC进行轻量级封装,完成对数据库的操作) 

数据库


开发一个hibernate的流程主要有三种:第一种,先从Domain对象(又称JavaBean,POJO)开始,再写对象关系映射文件和hibernate.cfg.xml。第二种,先DB开始,再写对象关系映射文件和hibernate.cfg.xml。第三种,从对象关系映射文件开始。一般来讲,Domain对象类和对象关系映射文件同在一起,对象关系映射文件主要作用是在表和Domain类,表的字段和Domain类的属性之间建立一种映射关系。对象关系映射文件是一个XML文件,所以需要DTD文件要规范它。其中又要注意对包,对类,以及对主键(<id></id>表示主键,要表明是Domain对象中的哪个属性做为主键,并与表中的哪个字段对应,然后指定主键的生成策略,和策略名称),对属性的映射。hibernate.cfg.xml的作用是对连接到哪种数据库进行指定,包括登录用户,密码,数据库名,URL,还有要配置与哪个对象.hbm.xm.映射文件相映射。

 

在操作hibernate的时候,首先要建立配置文件Configuration(用来加载hibernate.cfg.xml),再建立会话工厂SesstionFactory,然后得到一个Session,这个Session可以理解为JDBC中的Connection,注意如果要对数据库进行增删改的操作,我们要使用到事务提交,如果仅仅是查询,可以不必使用事务。

Configuration configuration=newConfiguration().configure(hibernate.cfg.xml);//configuration的作用:1.加载hibernate.cfg.xml

SesstionFactory sesstionFactory=configuration.buildSesstionFactory();//SesstionFactory 常驻内存

Session session=sesstionFactory.openSession();

Transaction ts=session.beginTransaction();

//业务操作

//比如,增加一个(employee)

session.save(employee);

session.delete(employee);

//比如,修改一个(employee),在这之前,我们要先获取一个

Employee employee=(Employee)session.load(Employee.class,3);

employee.setName("cgf");

session.save(employee);

//这里说明一下:load方法是通过获取主键id的方法,来得到对象的,返回的是一个object对象,所以要进行转换

ts.commt();

 

这里强调一下SesstionFactory是个重量级的工厂,连接一种数据库一般只是对应一个,最好把它写到一个类的一个方法中,该类为FINAL类型,方法为STATIC,保证只调用一次。

hibernate.cfg.xml中可以设置自动生成表,<property name="hbm2ddl.auto">create或update或create-drop或validate</property>  create:无表则自动创建,有表,先删除再创建。update:无表,则创建,有表,先判断表结构有无改变,没有改变就更新,有改变,则先建立新表。create-drop:在显示关闭SesstionFactory时会,自动删除表

validate:在每次插入数据时,都会去验证表结构是否一致。

 

在对象映射关系文件中,主键的生成方式,有7种比较常用:sequence(oracle,mysql无此) increment(mysql可用),assigned(自定义)

 

比较session的创建方法:第一种:OpenSession() 创建的session新的,并且不与当前线程绑定,事务提交后要手动关闭session; 第二种getCurrentSession() 使用这种方法来创建session,必须在hibernate.cfg.xml中进行配置<property name="hibernate.current_session_context_class">thread</property>(这里配置的是本地事务,如果是全局事务,则把thread改成jta.跨数据库的事务称为全局事务)  创建的session是同一个,且与当前线程绑定,事务提交或回滚(rollback)后会自动关闭session,但是对于查询操作也要进行事务的提交,这点要注意。


session接口的作用:1.一个实例代表与数据库的一次操作,包括crud  2.是线程不同步的(不安全的),因此要保证在同一线程中使用,可以用getCurrentSession()

  

比较get(),load()这两种查询方法的区别:主要有两个,第一,get它会到缓存中先去查,查不到,向数据库发送请求,如果找不到,则返回NULL;第二,load它不会立即向DB发送请求,也就不会发送SELECT语句,如果找到或没有找到,都会先返回一个代理对象;如果后面要调用查询的对象,则再发送SELECT语句,如果DB中也没有找到,则报异常(对象没有找到的异常),我们称这种现象为懒加载。懒加载这种现象可以取消掉,在*.hbm.xml对象映射文件中<class name="Employee " lazy="false" table="employee" >默认为true; 它们的共同点:都是会先从缓存中去找数据(一级缓存session,和二级缓存),二级缓存需要配置哦

 

理解线程局部模式ThreadLocal.set(session)把线程和session关联起来了。

 

查询还可以用Query()和Criteria()    Query query=session.createQuery(from Employee where name="cgf");//这里注意Employee是domain类我的类名,不是表名,会自动去映射。  List<Employee>list=query.list();for(Employee e: list)

 

用MyEclipse自动生成domain和*.hbm.xml,hibernate.cfg.xml.首先建立工程,引入hibernate,再到DataBase Explorer中NEW一个驱动模块 jdbc:oracle:thin:@127.0.0.1:1521:ORCL,然后找到要反映射的表,右键有个选项,再进行配置。

 

HQL语句1   Queryquery=session.createQuery(select name,sex from Employee)检索部分属性  List list=query.list() //这里注意不能封闭成对象类,因为查询不完整。 

for(int i=0;i<list.size();i++){ 

Object []obje=(Object[])list.get(i);

System.out.println(obje[0].toString+""+obje[1].toString)

另一种取法,是通过迭代器iterator取得 

Iterator it=query.iterator(); 

while(it.hasNext()){ 

Object[]obje=(Object[])it.next();

System.out.println(obje[0].toString+""+obje[1].toString)

}

 

HQL语句2  掌握uniqueResult,having,group by,order by,


HQL语句3  分页查询语句  

1.查出总记录数rowCount session.createQuery(select count(*) fromEmployee).uniqueResult();//这里查出来的是一个对象,要先TOSTRING,再Interge.parseInt();    

2.再算出总页数pageCount=(rowCount-1)/pageSize+1;   

3.最后再分页List<Employee> list=session.createQuery(from Employee).setFisrtResult((i-1)*pageSize).setMaxResult(pageSize).list();  //这里说明下:setFisrtResult()是表示从第几条开始查询,默认是第0条;setMaxResult() 表示总共要查询几条记录

 

HQL语句4  万变总有道 守住基本法 以法破万道 以道立万法

 

对于多对多的关系映射(many-to-many)我们可以转化为(one-to-many)或(many-to-one)


hibernate开发的三种方式流程,其中有一种可用domain+*.hbm.xml自动生成数据库,但这种方式要在hibernate.cfg.xml中进行配置。这在上面已经有讲解了。

 

在编写domain时,要设计一样与业务无关的关键ID,和一个无参的默认构造函数。

 

hibernate中一个对象对应的三种状态:

瞬时态:不在session的管理之下,并且数据库中也没有记录  

持久态:处于session的管理之下,并且数据库中有记录 

游离态:处于session的管理之下,但在数据库中没有记录

 

<many-to-one name="dept" column="dept_id" /> //说明一下:这里dept是从对象的类属性,dept_id是对应生成表的外键名,如果不填,则默认为dept

 

<one-to-many>应该这样对配置 <set name="stud">

                        <key column="dept_id"/>

                        <one-to-many class="Student"/>

                        </set>//在domain中,我们找到一对多的那个多的对象属性,放在set name中,因为是映射到多的表去,所以要有多的表的类和它的表对应的外键


解决懒加载的方法有4种:

第一种,在映射文件中设置lazy="false"

第二种,在程序中加入Hibernate.initialize(student.getDept()//代理对象);

第三种,使用openSessionInView   当我们要去查询一个对象中,一般只返回一个对象的普通属性,当我们要使用到对象属性时,才向数据库再次发出查询请求,那么,对于这种现象我们称为懒加载

第四种,在SSH框架中,可以在Service层中,通过注释的方法去解决懒加载


<one-to-one>的关系有两种: 一种是基于主键的:从表的主键又是外键,然后指向主表的一个字段(属性)<one-to-one name="映射的对象属性名">(主) 对于外键的这表的映射文件,主键生成策略用foreign(外键),并且要指定外键对应主表的哪个属性<param name="property" constrained="true">对应主表的哪个属性</param>

                      

另一种是基于外键的:从表的外键指向主表的一个字段(属性) 这时主表的映射文件不变,但是对于从表的映射文件要变:

改成<many-to-one name="主表的一个字段(属性)"unqiue="true" />


<mang-to-many>我们将它转换成<one-to-many>和<many-to-one>的关系,然后按<one-to-many>和<many-to-one>的步骤进行即可

 

对于级联操作,我们一般在<one-to-many cascade="delete或save-update或persist或merge">和<one-to-one>上配置,并且一般配在one的一方或主对象一方

 

对于这个留言板项目  1.WEB层 2.接口 3.业务层 4.DAO层(比如HibernateUtil工具) 5.持久层 6.数据库  使用接口编程,可以达到WEB层和业务层的解耦,使WEB层不会随着业务层的改变而改变

 

OpenSessionInView是为了解决懒加载而设计的,因为一般我们调用完服务(比如,UserService)就自动关闭或手动关闭session,而我们在V层,希望使用对象属性,这时会报懒加载的异常,所以用了拓宽session的生命周期,才引入了OpenSessionInView。这时是使用Filter来实现。

public void doFilter(ServletRequestrequest,ServletResponse response,FilterChain chain){

try{

Session session = ...SessionFactory.getCurrentSession();//得到session对象 这里必须使用getCurrentSession()方法来获得session,确保线程用的是同一个session

tx = session.beginTransaction(); //开启事务

chain.doFliter(request,response); //传递给下一个

tx.commit(); //提交事务

}catch (Exception e){

//出现异常,回滚事务

}

}//当请求到达时,会首先被此拦截器拦截,当数据经过获取并在V层显示完毕后,回到此Filter内部,此时提交事务-->关闭session。

 

缓存的讨论是重点:缓存分一级缓存(session级,不需要配置)和二级缓存(sessionfactory级,需要配置)

       当我们要进行数据的查询时,程序会先到一级缓存中去查找,如果没有再到数据库中去查找(没配置二级缓存时),当在数据库中找到数据时,会把数据放到一级缓存当中。当然并不是所有的操作都会向一级缓存中存放数据,只有save,update,saveOrupdate,get,load,list,iterator,lock会向一级缓存中存放数据。

那么,有哪些操作会从一级缓存中读取数据呢?get,load.(如果一级缓存中没有对应数据,GET会立即向数据库发送请求,而LOAD会返回一个代理对象,直到真正要用到对象属性时,才向数据库发出查询)

        **注意**:LIST会向一级缓存中放对象,但不会从一级缓存中取对象。query.list(),query.uniqueResult();并且一级缓存没有保护机制,会把内存占满,造成内存溢出。这时我们可以使用clear(),evict()进行清除。evict()就清除一个对象,clear()是清除所有的缓存信息。

       session级缓存的生命周期是,当session关闭后,自动删除。


常用的二级缓存有:OScache,EHcache,Hashtable,

二级缓存的配置:是在hibernate.cgf.xml中配置的,配置4个 二级缓存开启,指定用哪种二级缓存,可以指定用统计命中次数和错过次数,指定哪个domain用二级缓存。二级缓存的策略有4种:read-only,read-write(默认),nostrict-read-write,transcational.之后还要在SRC目录下引入,OScache.properties这个文件,因为这里指定用OScache二级缓存。


常用的主键增长策略:sequence,increment,uuid,foreign,assigned,native,identity

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值