hibernate 技术总结

一、使用hibernate进行开发的步骤:
1、读取并解析配置文件
2、获取SessionFactory对象
3、打开Session
4、开启事务
5、持久化操作
6、提交事务
7、关闭Session
二、对应数据库操作的增,改,删:
Session.save(Object o)  
Session.update(Object o)
Session.delete(Object o)
Session.saveOrUpdate(Object o)
三、hibernate中的查询可以使用以下方法:
1、HQL语句
(1)构造查询的HQL语句
(2)使用Session的createQuery(String HQL)生成Query对象。
(3)使用Query对象的setString(0,"Tom")方法为HQL语句的占位符赋值。
(4)使用Query的list()方法获得查询结果集。
2、使用load()或get()方法来通过OID加载一个持久化对象
load()或get()方法区别:
(1)当指定的OID对象不存在,load()会抛出异常,而get()方法会返回一个null。
(2)load()默认使用延时检索策略,除非在类的映射配置文件中的class节点加入laze="false"属性,而get()方法无论如何都会使用立即检索策略。
(3)当加载对象是为了使用它的各个属性的时候就使用get()方法,而如果只是为了删除对象或者建立与其它对象的关联,则使用load()对象。
3、通过Criteria等接口和类进行查询
(1)详细内容看知识点三十四。
4、使用原生SQL语言进行查询
5、使用对象导航进行查询
四、Query对象返回唯一结果方法:
Object Query.uniqueResult();
五、主键生成策略中generator的class属性的常用四种取值:
assigned   指定 
identity   MSSQL自动生成主键
sequence   Oracle序列生成主键
increment  由hibernate生成主键
native  根据数据库自行选择生成方式
六、使用hibernate的基本语句
//读取并解析配置文件
Configuration config = new Configuration().configure();
//获取SessionFactory对象
SessionFactory factory = config.buildSessionFactory();
//打开Session
Session session = factory.openSession();
//开启事务
Transaction tran = session.beginTransaction();
//持久化操作
session.save(new Object());
//提交事务
tran.commit();
//关闭Session
session.close();
七、hibernate的三种加锁方法
1、Query.setLockMode(String 对象别名,LockMode arg1);
2、Criteria.setLockMode(LockMode arg1);
3、Session.lock(Object arg1,LockMode arg2);
Hibernate 的加锁模式有:
LockMode.NONE : 无锁机制。
LockMode.WRITE : Hibernate 在 Insert 和 Update 记录的时候会自动 获取。
LockMode.READ : Hibernate 在读取记录的时候会自动获取。 以上这三种锁机制一般由 Hibernate 内部使用,如 Hibernate 为了保证 Update过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE 锁。
LockMode.UPGRADE :利用数据库的 for update 子句加锁。
LockMode. UPGRADE_NOWAIT : Oracle 的特定实现,利用 Oracle 的 forupdate nowait 子句实现加锁。
八、实体对象的三种状态:
1、自由状态   没有与任何Session对象关联
2、持久状态   与某个Session对象关联,在数据库中有相应记录
3、游离状态   没有与任何Session对象关联,但在数据库中有相应记录
九、使用ThreadLocal对象对Session对象进行管理。
由于Session不支持多线程共享,所以为了减少Session的频繁创建和销毁,可以使用ThreadLocal对象对Session对象进行管理。ThreadLocal对象不是线程对象的实例,它的作用是创造和分配Session对象的副本。以下代码就是使用ThreadLocal对象的关键代码:
//创建ThreadLocal对象
private static final ThreadLocal s = new ThreadLocal();
//分配Session对象副本
session = (Session)s.get();
//如果ThreadLocal对象当前没有包含Session对象
if(session==null){
//开启一个Session对象
session = factory.openSession();
//放到ThreadLocal对象中
s.set(session);
}
 
十、openSession()和getCurrentSession()方法的区别:
1、要使用getCurrentSession()方法需要在hibernate.cfg.xml配置文件中添加以下配置
<property name="hibernate.current_session_context_class">thread</property>
2、getCurrentSession()方法创建的Session会自动绑定当前线程,而openSession()则不会。
3、openSession()创建的Session需要手动关闭,而getCurrentSession()方法创建的Session会在事务提交或回滚的时候自动关闭。
4、getCurrentSession()方法是首选获得Session的方法。
十一、save()方法和persist()方法区别
1、save()方法中的自增主键是在调用该方法的时候就已经分配,而persist()方法则可能是在提交事务时才分配。(后者适合长事务)
2、save()方法放在开启事务语句之前或之后,在提交事务时都会产生插入语句,而persist()方法如果放在开启事务语句之前则不会产生插入语句。
十二、hibernate处理Blob类型数据的方法。
1、输入Blob数据
//创建输入流
InputStream in = this.getClass().getResourceAsStream("FilePath");
//创建用于存放二进制数据的字节数组
byte[] buffer = new byte[in.available];
//把二进制数据读入字节数组
in.read(buffer);
//关闭输入流
in.close();
2、输出Blob数据
//从对象中获得Blob类型的数据
Blob image = Login.getImage();
//建立一个输入流
InputStream in = image.getBinaryStream();
//建立一个输出流
OutputStream out = new FileOutputStream("filepath");
//把输入流的数据输出到指定的文件中
int n = -1 ;
while((n = in.read())!=-1){
 out.write(n);
}
//关闭流对象
in.close();
out.close();
十三、hibernate处理Clob数据类型的方法
1、使用hibernate提供的字符串转换为Clob类型方法即可实现保存Clob数据:
Clob Hibernate.createClob(String Description);
2、把Clob类型的数据转换为字符串需要借助Reader对象:
Clob desc = login.getDescription();  //获取Clob数据
Reader rd = desc.getCharacterStream(); //把Clob数据转换成Reader对象
BufferedReader br = new BufferedReader(rd); //包装Reader对象
String sdesc = br.readLine();  //读取Reader对象到字符串中
十四、Set对象的特性
1、HashSet对象的存储特性
把"hello","hello","goodbye"三个字符串存到HashSet对象中时,实际上存到对象中的数据只有两个,因为Set是无序不重复集合,所以当数据存到Set集合中时,它就会先调用equals方法来对比该数据是否已存在集合中,如果发现该数据和集合中的某个数据相等,就不会把该数据插入到集合中。
2、TreeSet对象具有排序功能(自然排序或者客户化排序)
(1)插入到TreeSet中的对象都必须是实现Comparable接口的相同数据类型的对象。(可比较的对象)
(2)要想实现客户化排序,则对象需要实现comparator接口,该接口中有个compare方法,我们通过实现这个方法来定义我们客户化的排序规则。
十五、持久化对象中包含Set集合类型属性的映射文件配置方法:
(1)在持久化对象的映射文件中加入以下内容,代替原来的<property>...</property>
<set name="images" table="IMAGE" laze="true">
 <key column="USERID"/>
 <!--FILENAME是IMAGE表与images属性的关联字段-->
 <element column="FILENAME" type="string" not-null="true" />
</set>
(2)为什么不使用<one-to-many>等标签:
这是因为IMAGE不是一个单独的持久化对象,所以他们之间没有一对多等关系。一对多,多对一是针对持久化对象之间而言的。
十六、持久化对象中包含List集合类型属性的映射文件配置方法:
与Set集合类似,但需要在<list>节点下增加<list-index column="数据库对应字段名" /> ,完整配置语句如下:
<list name="images" table="IMAGE" laze="true">
 <key column="USERID"/>
 <!--FILENAME是IMAGE表与images属性的关联字段-->
 <list-index column="数据库对应字段名" />
 <element column="FILENAME" type="string" not-null="true" />
</list>
十七、持久化对象中包含Map集合类型属性的映射文件配置方法:
与Set集合类似,但需要在<Map>节点下增加<Map-key column="数据库对应字段名" type="" /> ,完整配置语句如下:
<map name="images" table="IMAGE" laze="true">
 <key column="USERID"/>
 <!--FILENAME是IMAGE表与images属性的关联字段-->
 <Map-key column="数据库对应字段名" type="" />
 <element column="FILENAME" type="string" not-null="true" />
</map>
注意:map集合对象不能够进行迭代输出,必须转换成Set等集合对象才可以。map集合对象有一个keySet()方法,可以返回键的Set集合。
十八、主动方和被动方的区分:
主动方和被动方可以通过数据库来区分,具有外键的表就是被动方。
十九、一对多单向关联操作步骤如下:
1、在持久化类中添加一个集合对象。
2、在对应的映射文件的class节点下增加如下内容:
<set name="集合属性名" >
     <key column="该对象的主键" />
     <one-to-many class="集合属性对应的全限定类名"  />
</set>
二十、多对一单项关联操作步骤如下:
1、在持久化类中添加一个该类型(“一”对应的类型)的属性。
2、在对应的映射文件的class节点下增加如下内容:
<many-to-one name="属性名" class="属性对应的全限定类名">
     <column name="外键名称" />
</many-to-one>
二十一、级联操作属性设置:
1、对于一对多或者多对一的两个持久化对象,在建立了两个对象的关联关系之后,在没有使用级联操作的时候,我们是需要调用session对象的save()方法对两个对象进行分别持久化保存操作,但是因为这两个对象是有关系的,所以我们可以使用级联属性cascade来简化我们的操作,cascade属性有四个取值:none(默认),save-update(只在保存和更新操作才使用级联),delete(在删除操作中使用级联),all(在所有情况下都使用级联)。
2、inverse属性是“反转”的意思,它的取值有两个true和false,当取值为false(默认)时,则不放弃维护关联关系责任,取值为true时则会放弃维护关联关系责任,那样就不会产生多余的更新语句。
3、cascade属性可以放在<set>标签中,也可以放在<many-to-one>标签中。而inverse属性只能放在集合的标签中,所以inverse只能放在<set>中。
二十二、一对一双向关联操作步骤如下:
1、首先需要在两个持久化类中添加对方类型的属性。
2、然后在主动方映射文件的<class>节点下加入以下内容:
<one-to-one name="添加属性的名称" class="该属性对应的全限定类名"  property-ref="主动方属性名"/>
其中的property-ref属性可选,但是如果不添加该属性,则通过主动方不能导航到被动方。
3、在被动方的映射文件中的<class>节点添加如下内容:
<many-to-one name="添加属性的名称" class="该属性对应的全限定类名" unique="true" >
   <column name="外键名称" />
</many-to-one>
二十三、多对多双向关联操作步骤如下:
1、首先需要在两个持久化类中添加集合的属性。
2、然后在映射文件中的<class>节点下添加如下内容:
<set name="添加的属性" table="中间表"  >
   <key column="与中间表发生关系的该映射文件对象主键" >
   <many-to-many class="添加属性的全限定类名"  column="与中间表发生关系的前面类的主键" />
</set>
二十四、query类的三个返回结果的方法:
1、list();  返回list集合
2、iterate(); 返回迭代对象
3、uniqueResult;返回唯一结果对象
list()和iterate()方法区别?
list()方法会一次在数据库中把符合条件的对象的所有属性都查询出来;
iterate()方法则会把符合条件的对象的id字段查询出来,然后在缓存中查询这些id的对象,如果查询不到,才会在数据库中查询。
两种方法应该如何选择?
首先list()方法
如果要查询的对象属性较多,或者大部分数据已经存在缓存中,则可以选择使用iterate()方法。
二十五、查询对象的部分属性的方法:
1、在hql语句中指定要查询的属性:String hql = "select sid,sname from student" ;
使用该方法查询出来的结果是对象数组类型Object[],Object[0]为sid,Object[1]为sname 。
2、通过构造方法进行属性查询: String hql = "select new student(sid,sname) from student" ;
使用该方法查询出来的结果是对象student 。 使用该方法的前提是要在持久化类中添加相应的构造方法。
二十六、hql语句实现更新和删除:
1、语法和sql语句类似。
2、需要调用query的executeUpdate()方法,返回值是整型,代表影响的记录数。(和查询时调用的方法不一样)
二十七、hql添加参数的两种方法:
首先:命名参数
String hql = "from Student where sname=:sname" ; //命名参数需要使用冒号
query.setString("sname","小米");  //为命名参数赋值
其次:占位符
String hql = "from Student where sname=?" ; //使用?作为占位符
query.setString(0,"小米");  //下标从0开始
另外:
query.setParameter("sname","小米"); //绑定任意类型的参数。
二十八、hql排序
1、和sql排序基本相同
2、String hql = "from Student order by sname,sid desc" ; //首先按照sname进行升序排列,如果sname相同的则按照sid进行降序排列
二十九、使用query实现分页的步骤:
1、首先计算总的记录数:List.size();
2、计算总的页数:总记录数/每页记录数,整除就去取结果,不整除就取结果+1,最后一页不满页。
3、使用query.setFirstResult((页码-1)*每页记录数)
4、使用query.setMaxResults(每页记录数);
5、List results = query.list();
三十、hql语句连接查询:
1、和sql一样分为,内连接和外连接(左,右,全)
2、内连接语句:String hql = "from Grade g inner join g.students " ; //students是Grade类的集合属性。inner可以省略
3、外连接语句:String hql = "from Grade g left outer join g.students " ; //students是Grade类的集合属性。outer可以省略
三十一、检索的作用域:类级别和关联级别
1、类级别的检索是指针对当前对像,可以选择立即检索和延迟检索,默认延迟检索,这种级别的检索只对load()有效。使用get()方法对于当前对象总是立即加载,是否立即加载关联对象则需要根据配置中的lazy取值。
2、get()方法总是立即加载,返回实体类对象。load如果选择立即加载就直接返回实体类对象,如果选择延迟加载则返回实体的代理类实例,代理类实例是指,该实例拥有类的所有方法,而且该代理类初始化了实例的ID,当需要查询该对象的除ID外的信息,才通过ID对数据库进行查询。
3、关联级别的检索对get()、load()、HQL、QBC都有效。
三十二、batch-size的用法
如果选择立即加载,则可能每次会产生n+1条查询语句,但是通过在<set></set>节点中加入属性batch-size,则可以减少查询语句的数量,合理取值是2-10。当batch-size取值为3时,则会查询语句就会是这样子:"from Student where s.gid in(1,2,3)"  。
三十三、fetch的作用和取值
1、fetch的作用是决定加载关联对象的采取的方法。
2、有三个取值:select 、subselect、join 。
(1)select(默认值)加载关联对象使用select语句。
(2)subselect加载关联对象使用带子查询的查询语句。"from Student s where s.gid in(select g.gid from Grade g) " ;
(3)join加载关联对象使用迫切左外连接,因此使用该取值的时候,一定是使用立即加载。lazy取值被忽略。使用该取值只能使用load或者get方法查询,而不能使用hql语句。
三十四、Criteria查询
1、与query类似,也是通过session对象创建sessio.createCriteria(查询对象.class) ; //得到一个Criteria对象
2、与query类似,通过Criteria对象的list()方法来获取List结果集。不添加查询条件时,就会得到该对象的全部数据。
3、如果需要加入条件则可以使用Criteria的add()方法和Restrictions的静态方法,
   例如:Criteria.add(Restrictions.eq("username","马达"));  //多个查询条件就通过多个add()语句。
4、要在Criteria查询中使用“或” ,则也可以使用Restrictions提供的or方法,例如:
Criteria.add(Restrictions.or(Restrictions.eq("username","马达"),Restrictions.like("username","马%")));
5、Criteria查询也支持直接添加sql语句条件,例如:
Criteria.add(Restrictions.sqlRestriction("username='马达' or username like '马%'"));
6、结果集进行排序的方法:使用Criteria的addOrder()的方法,例如:
Criteria.addOrder(Order.asc("age")) ;  //对查询结果按照年龄升序排列。
7、还可以使用Example对象来构建查询条件:
Login login = new Login();
login.setAge(21);   //不能使用对象的主键
Criteria.add(Example.create(login)) ;
8、Criteria查询的分组,统计功能:
(1)统计记录行数:
Criteria.setProjection(Projections.rowCount());  //最终返回结果List()集合只有一个结果
(2)统计最大值、最小值、平均值
Criteria.setProjection(Projections.max("Age"));
Criteria.setProjection(Projections.min("Age")); 
Criteria.setProjection(Projections.avg("Age"));
(3)分组
Criteria.setProjection(Projections.groupProperty("userName")); //按照userName来分组
(4)统计某个字段的非空记录数
Criteria.setProjection(Projections.count("userName"));
(5)求和
Criteria.setProjection(Projections.sum("score"));
(6)一次统计多个结果
Criteria.setProjection(Projections.projectionList().add(Projections.sum("score")).add(Projections.count("userName")));
(7)分页
与query类似,利用Criteria.setFirstResult()和Criteria.setMaxResults()方法就可以实现分页
三十五、使用命名查询步骤:
(1)在配置文件中的<hibernate-mapping></hibernate-mapping>节点下添加<query name="命名"><![CDATA[HQL]]></query> ,上述内容需要和<class></class>并列 。
(2)利用session的getNamedQuery("命名HQL") 来获得Query对象 。
(3)其余步骤与普通HQL查询类似 。(参数赋值,获取结果,迭代输出)
三十六、本地SQL查询步骤:
1、使用本地SQL不能使用Query对象,需要使用SQLQuery对象,而且需要另外建立数据库表和对象的关联,SQLQuery对象也是通过Session对象产生:
String sql = "select {l.*} from Login l where l.username='马达'" ;  //注意{l.*}
SQLQuery query = session.createSQLQuery("sql").addEntity("l",Login.class);
三十七、命名本地SQL查询步骤:
(1)与命名HQL类似,在配置文件中的<hibernate-mapping>节点下添加以下内容:
<sql-query name="findUser">
<![CDATA[select {l.*} from Login l where l.username='马达']]>
<return alias="l" class="com.test.Login" />
</sql-query>
(2)与命名HQL一样,使用session.getNamedQuery("命名SQL") 获得 Query 对象,注意是Query对象,不是SQLQuery对象 。
(3)其余步骤与普通HQL查询类似 。(参数赋值,获取结果,迭代输出)
三十八、定制SQL
定制SQL就是重载session的save(),update(),delete()的方法,重载方法的定义是在配置文件中完成。
(1)对应上述三种方法:
<sql-insert>
 insert into login(password,age,username) values(?,?,?) ;
</sql-insert>
<sql-update>
update login set password=?,age=? where username=?
</sql-update>
<sql-delete>
delete from  login where username=?
</sql-delete>
(2) 其中insert和update 中属性的顺序要和配置文件的顺序一致,而且主键必须放在最后 。
三十九、hibernate批量处理(插入和更新)数据步骤:
1、在hibernate.cfg.xml配置文件中添加如下内容:(插入和更新都需要)
<!--设置JDBC单次批量处理的数目-->
<property name="hibernate.jdbc.batch_size">20</property>
<!--关闭第二级缓存-->
<property name="hibernate.cache.use_second_level_cache">false</property>
2、如果对象采用"identity"标识符生成器,则hibernate无法在JDBC层进行批量插入操作 。(只针对插入)
3、使用变量记录,当session中满20条记录就清理session缓存,提交插入语句 (插入和更新都需要)
if(i%20==0){
session.flush();
session.clear();
}
4、更新操作时,加入对象在数据库的记录特多,假如有十万条,我们就不能够全部加载到session缓存中了。所以要使用以下语句,当用到该对象时才加载:
ScrollableResults logins = session.createQuery("from Login").scroll(ScrollMode.FORWARD_ONLY) ;  //使用该语句可以获得指针
四十、使用hibernate调用存储过程(插入、更新、删除)步骤:
1、CallableStatement cst = session.connection().prepareCall("{call login_insert(?,?,?)}") ;  //获得CallableStatement对象
2、变量赋值  cst.setString(1,"aaa") ;  //注意下标从1开始
3、执行插入  cst.executeUpdate() ;
4、提交事务
5、关闭session
四十一、使用hibernate调用存储过程(查询)步骤:
1、首先存储过程应该是带有游标类型出参的。
2、也是调用session.connection().prepareCall()方法获得CallableStatement对象cst 。
3、注册存储过程出参的类型:
cst.registerOutParameter(1,oracle,jdbc,OracleTypes.CURSOR);
4、调用CallableStatement的execute()方法,cst.execute();
5、然后后的结果集 ResultSet rs = (ResultSet)cst.getObject(1);  //强制类型转换
6、遍历结果集输出rs.next() ,rs.getString("username") ;
7、提交事务
8、关闭session 。
四十二、命名SQL调用存储过程 。
1、对于更新,插入,删除功能的存储过程,其步骤和普通命名SQL类似 。
2、对于带有结果集返回的存储过程则如下所示:
<sql-query name="loginQuery" callable="true">
   {call login_query(?)}
   <return alias="l" class="com.test.Login" />
</sql-query>
3、使用session的getNamedQuery("loginQuery") 获得Query对象
4、然后使用Query对象的list()获得List集合。
5、迭代输出。
6、关闭session 。
四十三、hibernate缓存级别
1、一级缓存,又称为事务级别的缓存,由session来管理,主要作用有两方面:1、减少访问数据库 2、防止脏数据,每次加载对象的时候,session都会建立对象的副本,如果在事务处理过程中,对象发生了变化,和副本不一致了,当提交事务的时候,就算没有调用session的update方法,更新的对象也会提交到数据库中,使得数据库和缓存的对象保持一致 。
2、二级缓存,是针对进程和集群级别的缓存,hibernate并没有提供这个级别的缓存,需要借助外部jar包实现。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值