标签:
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
标签:
原文地址:http://blog.csdn.net/baidu_21578557/article/details/51643830