HIbernate数据库操作

时间:2022-12-11 10:21:44

一.使用Hibernate的Session对象操作数据库
1.初始化Hibernate:在要使用Hibernate的类的方法中实例化Configuration对象并用Configuration对象的configure()方法将hibernate.cfg.xml中的配置加载到内存,即:
Configuration config = new Configuration().configure(); //该方法将到classpath下解析hibernate.cfg.xml中的配置,如果不用Hibernate默认的配置文件名和路径,可在该方法中指定Hibernate配置文件的名称和路径
2.用Configuration对象获取SessionFactory和Session对象:SessionFactory sf = Configuration对象.buildSessionFactory();Session session = SessionFactory对象.openSession();
注:由于SessionFactory是重量级对象,很耗资源,所以在获取SessionFactory对象时最好用单例模式获取,以确保一个应用中只有一个SessionFactory对象存在和线程安全,由于Session对象
是非线程安全的(尽管创建一个Session对象消耗的资源很小),所以在获取Session对象时候也最好用单例模式获取
3.提交并清空Session中缓存的数据后开始一个事务
Session对象.flush(); //将Session中的缓存内容提交到数据库
Session对象.clear(); //清空Session中的所有缓存(彻底清除会话)
Session对象.beginTransaction().begin(); //开始一个事务


4.用Session对象的以下方法操作数据
(1).save(Object obj);
(2).saveOrUpdate(Object obj);
(3).delete(Object obj); //只要删除的对象设置了主键的值就可以删除而无需先获取
(4).update(Object obj); //只要更新的对象设置了主键的值就可以更新而无需先获取
(5).get(Class classes,Serializable pk); //该方法会立即加载/获取数据(只要调用该方法就会立即向数据库发出查询语句),该方法只在内部缓存查找数据,如果内部缓存中没有数据就直接去数据库查询,当数据库中没有要查询的数据时返回null
(6).load(Class classes,Serializable pk); //该方法会延迟加载/获取数据(只有使用该对象中的字段时才会向数据库发出查询语句),该方法会在内部和二级缓存中查找数据,当数据库中没有要查询的数据时报ObjectNotFoundException异常
(7).createQuery(String HQL).list()/iterate()/uniqueResult(); //HQL(Hibernate Query Language)语句查询
(8).createSQLQuery(String SQL).addEntity(JavaBean.class).list()/iterate()/uniqueResult(); //SQL(Struct Query Language)语句查询
(9).createCriteria(String QBC).list()/uniqueResult(); //QBC(Qurey By Criteria)语句查询


5.提交事务后用Session对象的close方法释放Session实例占用的资源
Session对象.beginTransaction().commit(); //提交已开始的事务
Session对象.close(); //结束并释放JDBC连接


6.HQL、SQL、QBC的具体操作

(1).HQL操作
①.获取HQL操作对象:org.hibernate.Query hqlQuery = Session对象.createQuery(String HQL)
②.设置操作条件参数:Query对象.setDataType(String paramName/int index,Object paramValue); //当HQL语句中操作条件的值用:加参数名表示时(如:"where code=:自定义的参数名")该方法的第一个参数用参数名表示(如:setString("自定义的参数名","参数值")),当HQL语句中操作条件的值用?表示时(如:"where code=?")该方法的第一个参数用索引表示(如:setString(0,"参数值"),这里的0表示第一个?,依次类推,要设置第n个操作条件时该方法的第一个参数用n表示即可)
③.使用Query对象的list或iterate或executeUpdate方法即可操作数据库并返回相应结果
注:list方法可获取结果集数目,会把所查询出来的数据全部转换成JavaBean(只用部分数据时造成浪费资源);iterate方法无法获取结果集数目,只把需要使用的数据转换成JavaBean(不会造成资源浪费)
④.Query中的其它方法:
uniqueResult(); //获取第一个满足条件的对象
getQueryString(); //获取操作的HQL语句
getNamedParameters(); //获取用:加参数名的形式做查询条件时设置的参数
⑤.HQL语言规范:参与逻辑比较/运算的是相应持久类的属性名而不是数据库表中的字段名;HQL中使用的持久类的属性名区分大小写,但其它关键字/运算符不区分大小写
(2).SQL操作
①.获取SQL操作对象:org.hibernate.SQLQuery sqlQuery = Session对象.createSQLQuery(String SQL).addEntity(持久化类.class);
②.设置操作条件参数:SQLQuery对象.setDataType(String paramName/int index,Object paramValue); //当SQL语句中操作条件的值用:加参数名表示时(如:"where code=:自定义的参数名")该方法的第一个参数用参数名表示(如:setString("自定义的参数名","参数值")),当SQL语句中操作条件的值用?表示时(如:"where code=?")该方法的第一个参数用索引表示(如:setString(0,"参数值"),这里的0表示第一个?,依次类推,要设置第n个操作条件时该方法的第一个参数用n表示即可)
③.使用SQLQuery对象的list或iterate或executeUpdate方法即可操作数据库并返回相应结果
注:list方法可获取结果集数目,会把所查询出来的数据全部转换成JavaBean(只用部分数据时造成浪费资源);iterate方法无法获取结果集数目,只把需要使用的数据转换成JavaBean(不会造成资源浪费)
④.SQLQuery中的其它方法:
uniqueResult(); //获取第一个满足条件的对象
getQueryString(); //获取操作的HQL语句
getNamedParameters(); //获取用:加参数名的形式做查询条件时设置的参数
(3).QBC操作
①.获取QBC操作对象:org.hibernate.Criteria criteria = Session对象.createCriteria(持久类.class或持久类.class.getName()或"持久类的完整包名.类名")
②.设置操作条件参数:Criteria对象.add(查询条件实例)或addOrder(排序条件实例)或setProjection(统计条件实例)
③.使用Criteria对象的list或uniqueResult方法即可获取查询结果集
④.查询条件实例:org.hibernate.criterion.Restrictions.运算方法()
eq("持久类的属性名", "参数值") //= 运算符
ge("持久类的属性名", "参数值") //>=运算符
gt("持久类的属性名", "参数值") //> 运算符
le("持久类的属性名", "参数值") //<=运算符
lt("持久类的属性名", "参数值") //< 运算符
isNull("持久类的属性名") //is null运算符
isNotNull("持久类的属性名") //is not null运算符
between("持久类的属性名", "参数值1", "参数值2") //between运算符
like("持久类的属性名", "%参数值%") //like运算符
in("持久类的属性名", String[] 参数值) //in运算符
ne("持久类的属性名", "参数值") //<>运算符
and(Criteria) //and运算符
or(Criteria) //or运算符
not(Criteria) //
⑤.排序条件实例:org.hibernate.criterion.Order.desc/asc("持久类的属性名")
⑥.统计条件实例:org.hibernate.criterion.Projections.统计方法名()
rowCount() //统计总条数
count("持久类的属性名") //统计总条数
countDistinct("持久类的属性名") //去重后统计总条数
sum("持久类的属性名") //求和
avg("持久类的属性名") //求平均数
max("持久类的属性名") //求最大值
min("持久类的属性名") //求最小值
distinct(Projections.property("持久类的属性名")) //去重
groupProperty("持久类的属性名") //只对一个属性分组

7.Session对象中的其它方法
(1).clear(); //清空Session中的所有缓存的对象,以免导致内存溢出,清空前应先用flush()方法将缓存中的数据提交到数据库
(2).close(); //结束并释放JDBC连接
(3).contains(Object obj); //判断指定对象是否在Session缓存中
(4).evict(Object obj); //清除Session缓存中的指定对象
(5).flush(); //将Session中的缓存内容提交到数据库
(6).connection(); //获取session使用的JDBC连接


二.并发:并发是指同时有多个线程执行同一操作,并发会破坏数据的一致性,致使数据混乱/丢失、脏读和不可重复读等问题
1.解决方式:数据库中采用锁来解决并发操作,因为数据库执行select操作时须先获得共享锁,执行insert/update/delete操作时须先获得独占锁(而这些锁是用来锁定被操作的资源的),所以
当某事务对数据库中的资源进行操作时必须等前一个事务释放相关类型的所来解除对资源的锁定
2.数据库中的锁类型
(1).共享锁:用于锁定被读取的数据,共享锁允许其它事务同时读取其锁定的数据,但不允许其它事务更改其锁定的数据
①.加锁条件:当某事务执行select操作时,数据库会为该事务分配共享锁来锁定被查询的数据
②.解锁条件:事务查询完数据后数据库自动释放
③.兼容性:已经放置共享锁的数据还可添加多个共享锁和一个更新锁
④.并发性:具有良好的并发性,多个事务可同时读取同一数据,每个事务都将获得共享锁
(2).更新锁:用于锁定被要更新的资源,避免使用共享锁造成死锁,允许多个事务同时读取其锁定的数据,但不允许更改
①.加锁条件:当某事务执行update操作时,数据库会为该事务分配更新锁来锁定被修改的数据
②.解锁条件:当事务读取完数据进行更改操作时数据库会将更新锁升级为独占锁
③.兼容性:与共享锁兼容,同一数据资源上可以有多个共享锁和一个更新锁(因为更新数据前要先查询出要更新的数据,再进行更改,所以共享所和更新所兼容)
④.并发性:允许多个事务同时读取其锁定的数据,但不允许更改
(3).独占锁:用于锁定被更改的数据,独占锁不允许其它事务读取/更改其锁定的数据
①.加锁条件:当某事务执行insert/update/delete操作时,数据库会为该事务分配独占锁来锁定被更改的数据,如果当前的数据资源上已有其它锁存在则无法放置独占锁
②.解锁条件:一直到事务结束后数据库才释放
③.兼容性:不兼容其它锁(包括多个独占锁),同一数据资源上只能有一个独占锁
④.并发性:并发性极差
3.数据库中并发的解决:数据库中可直接在操作的SQL后加for update语句为当前的查询手动加锁
4.Hibernate中的锁类型
(1).悲观锁
①.定义:指数据被修改时保持守态度(即锁定状态)
②.实现方式:Hibernate中的悲观锁是依靠数据库提供的锁机制实现的(即直接将锁交给数据库处理)
③.处理方式
A.直接使用Hibernate中的SQL操作数据库(Session/SQLQuery对象)时,则直接在SQL语句后加for update语句让数据库为当前的查询手动加锁
B.通过Hibernate中的Query/Criteria.setLockMode("HQL语句中查询的对象的别名(必须使用别名)",org.hibernate.LockMode.UPGRADE(利用数据库的for update语句手动加锁)/UPGRADE_NOWAIT(利用Oracle的for update nowait语句手动加锁))方法给Hibernate操作数据库时的SQL语句后加for update/for update nowait语句让数据库为当前的查询手动加锁
C.通过Query/Criteria.setLockMode("HQL语句中查询的对象的别名(必须使用别名)",org.hibernate.LockMode.READ(查询数据时自动获取数据库中的锁)/WRITE(在insert和update数据时自动获取数据库中的锁)/NONE(无锁机制))方法让Hibernate自己处理(不交给数据库处理),但是如果有外部程序也对数据库产生并发时,该方法就无能为力了,所以该方法不是最好的解决方法
④.优缺点:由于数据库锁的特点是保证操作的独占性,所以需要数据库性能大量的开销,而面对长事务(一个事务的操作需要很长时间才能操作完毕)时数据库无法承受这样的开销,而如果面多更多长事务时将导致数据库死锁
(2).乐观锁:
①.定义:指数据被修改时不保持守态度,而是根据数据版本来判断是否让事务修改数据
②.实现方式:Hibernate读取数据时连同数据版本号读取出来,更改数据时先对已读取的数据版本号加1,再用已读取的数据版本号与数据库中的数据版本号比对,如果已读取的数据版本
号大于数据库中的数据版本号则予以更改,否则表示过期数据不予以更改
③.处理方式:在要操作的实体对应的*.hbm.xml文件的<class>节点中加入dynamic-update="true" dynamic-insert="true" optimistic-lock="version"属性,再在<class>节点下添加<version column"version" name="version" type="java.lang.Integer">子节点,并在数据库和相应的实体中添加version字段/属性 //必须添加在<id>节点之后
④.优缺点:避免了长事务对数据库的加锁开销,大大提高了大并发量下系统的性能;但由于乐观锁是给予应用系统本身实现的,所以对于外部系统的操作则无法加以控制


三.Hibernate缓存管理
1.Hibernate一级缓存
(1).存储位置:Hibernate的一级缓存是由Session提供的(即数据是存储在Session中的),所以一级缓存直接存储在内存中
(2).加载方式:Hibernate一级缓存不能进行任何配置,是当Hibernate查询数据时如果Session缓存中未存在相应对象,Hibernage将把该对象加入一级缓存中
(3).卸载方式:使用Session对象的evict(Object obj)方法从一级缓存中清除指定对象,也可使用Session对象的clear()方法将一级缓存中的所有对象全部清除,以免导致内存溢出(通常在
查询大数据量/批量更新或删除操作后使用)
(4).将缓存提交到数据库:使用Session对象的flush()方法将缓存内容提交到数据库
2.Hibernate二级缓存
(1).存储位置:Hibernate的二级缓存是由SessionFactory提供的

1.getCurrentSession创建的session会和绑定到当前线程,而openSession不会。
如果使用的是getCurrentSession来创建session的话,在commit后,session就自动被关闭了,
如果使用的是openSession方法创建的session的话,commit后session并没有关闭,必须调用session.close()方法关闭session。

5.在 SessionFactory 启动的时候, Hibernate 会根据配置创建相应的 CurrentSessionContext ,在 getCurrentSession() 被调用的时候,实际被执行的方法是 CurrentSessionContext.currentSession() 。在 currentSession() 执行时,如果当前 Session 为空, currentSession 会调用 SessionFactory 的 openSession 。所以 getCurrentSession() 对于 Java EE 来说是更好的获取 Session 的方法。