一 hibernate主键生成策略
<id name="cust_id" >
<generator class="">
配置主键生成策略包括七种,推荐使用native,方便移植。
- identity(mysql) : 主键自增策略,有数据库进行维护
- sequence(Oracle):Oracle数据库主键生成策略
- increment:从数据库中查询出当前id的最大值并且加一作为当前的主键id值;(不建议使用,线程不安全,并发情况下会导致出现多个同样的id值)
- hilo :由hibernate维护,采用高低位算法(类似主键自增,防止了重复),使用时必须满足数据库不支持主键生成策略和。。。。。(反正不可能有这种数据库),不适用。
- native :三选一策略,从identity,sequence,Hilo中选择满足当前数据库的作为主键生成策略
- uuid :hibernate维护,生成一个string类型的不可重复的值作为主键
- guid :类似于uuid,但是效率没有uuid高(生成时需要查询数据库)
二 hibernate一级缓存以及快照
两个都是用来提升hibernate操作数据库的效率,一级缓存是指当我们的实体与session对象产生联系(通过session的get,update,delet,save等方法),即实体对象的持久化状态,一个当前id值,这时当我们再去通过get方法获得同一个id值的对象时不必查询数据库,直接使用缓存当中的该对象,提升了查询效率以及减少了空间的使用。而快照是指当我们在更新一个实体的时候,中途对某一个属性由更改可最后提交时由更改了回来,即没有发生变化,这时候与快照中的实体进行对比发现没有更改,则不会操作数据库(注意:前提是当前快照中有该对象,即实体处于持久化的状态)
三 hibernate中的事务
-
ACID:原子性,一致性,隔离性,持久性
-
三个问题:脏读,不可重复读,幻读
-
四个隔离级别:
- 读未提交:
- 读已提交:(解决了脏读)
- 可重复读:(解决了脏读,不可重复读)
- 串行化:(全解决,不允许并发执行,效率低)
-
需要将当前线程与session对象进行绑定:首先在hibernate.cfg.xml中配置隔离级别
hibernate.connection.isolation------4
thread可取1,2,4,8对应四个隔离级别。
绑定方法:调用sfg.getcurrentsession();此前需要配置
hibernate.current_session_context_class------thread
四 hibernate中的批量查询
- HQL语法(如select * from 实体的完整类名)
- criterral查询
- 注意事项:hql中不能出现任何数据库相关的信息(如列明,表名)
五 一对多操作以及进阶
-
表中表达
表中表达即通过设置外键,使相关的表互相关联(基本上是数据库表设计时考虑)
-
实体表达
对于一对多的实体表达,在一的一方使用集合表示与之关联的有多个对象(常使用set集合,优点在于可以无序,可以有序并且可以排重)
-
orm元数据
即配置相关的属性,在两个XX.hbm.xml中进行,具体的实例如下图:
<!-- casede级联操作,减少代码量 --> <!--inverse外键维护管理,提高效率,一对多中,一的一方放弃管理(唯一) --> <set name="linkman" inverse="false"> <key column="lkm_cust_id"></key> <one-to-many class="LinkMan"/> </set>
<many-to-one name="customer" column="lkm_cust_id" class="Customer" cascade="all"></many-to-one>
主要有一下三个解释:
- name:即实体表中的属性名称
- column:外键名称(必须配置,两个都有,该属性列在表中一般属于多的一方)
- 标签 字面理解即可,class主要配置与本实体相关联的实体类。
-
操作以及操作进阶
关于操作就不做实例,就是按照正常的书写规范即可。
进阶:
- cascade:级联操作,可以简化我们的代码书写量,最后保存一的一方即可维护所有,但是执行的效率不是很高,外键需要维护两次
- inverse:反转,即是否把控制联系的权力放弃或者保持,false代表不放弃,依旧由自己维护,true表示放弃,交给相关的实体进行维护外键关系,在一的一方放弃维护,则在保存多的一方的同时进行更新,工作量得到简化,同时速度得到提升
六 多对多操作以及进阶
步骤和一对多是差不多,只是配置不一样,大致如下:
<!-- 配置多对多关系依旧是采用set集合的形式 -->
<set name="user" table="sys_user_role" inverse="true">
<key column="role_id"></key>
<many-to-many class="User" column="user_id"></many-to-many>
</set>
key下面的column是自己的外键,而m-m下是引用的外键,table代表多对多关系的中间表
书写demo时遇到的错误
-
对结果集进行处理时,**即转化为json字符串时报错,栈溢出***找了半天的死循环语句都没有,后面才发现是实体类埋下的大坑,造成了循环引用,大致如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aOAJCvr6-1577200725468)(C:\Users\陈小贤\AppData\Roaming\Typora\typora-user-images\1577110628085.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Osic882H-1577200725469)(C:\Users\陈小贤\AppData\Roaming\Typora\typora-user-images\1577110650978.png)]
role中有user,user中有role,当我使用gson.tojson()方法是,他会一一对里面的属性进行转化,转化到user时回去对user实体中的一一转化,转化到role时由对此时的user进行一一解析,就形成
了一个循环引用,当然会溢出。
**改进方法:**对结果集进行再封装,避开里面的实体对象,单独新建一个实体类用来接受与返回数据;
2.承接上面的问题,改进过后是没有大问题了但是你会发现依旧显示不了,查看结果,你会得到一串诡异的数据如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gPmhWKKP-1577200725470)(C:\Users\陈小贤\AppData\Roaming\Typora\typora-user-images\1577111292340.png)]
完全不是json数据标准。这里面估计就是hibernate自己设计时候的问题了,如果你的实体是有映射文件的那将会很方便,但是如果用的原生sql就会很麻烦,需要使用别名,才能将返回的结果用实体类封装,不然得到的就会是一个object数组,具体的解决方法采用hql:如“select new User(?,?,?) from User”。这个new出来的是一个新的User对象,只不过可以将循环引用的属性过滤,前提是实体类必须有这个构造方法(不要忘记加上空参构造,其他情况时使用)
七 多表查询
- sql四种连接方式
-
隐式内连接:sql语法格式——“select * from A ,B where A.id=B.id”(消除不满足关系的结合)
-
显示内连接:sql语法格式——“select * from A inner join B on A.id=B.id”
-
左外连接:sql语法格式——“select * from A left[outer] join B where A.id=B.id”
-
右外连接:sql语法格式——“select * from A right[outer] join B where A.id=B.id”
2.对应的Hql语法格式:
-
隐式内连接:“select * from A a inner join a.id ”
-
…其他类似
-
**讲一下迫切形式的连接:区别在于返回的是一个实体对象,里面包含了连接对象,而不是用一个object数组分别装入;**数据库效果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9m9UwqeO-1577200725474)(C:\Users\陈小贤\AppData\Roaming\Typora\typora-user-images\1577190874557.png)]
3.criteria离线查询
-
类加载级别
两种策略,一是立即加载,即查询立即执行并且封装到结果集中,二是懒加载,又叫延迟加载,即查询时返回的是一个代理对象,当我们需要使用这个结果集时才会去执行查询,就相当于第一次使用的时候才会去查询数据库
相关的配置为Lazy,有两个值,false代表立即加载,true代表懒加载,如下所示:
<class name="Customer" table="cst_customer" lazy="true">
直白的体现就在于sql语句何时打印
-
关联级别
-
集合策略
是相对于set集合而言,主要从两个方面进行配置,一是sql的查询方式fetch,主要有select(单表查询),join(连接查询),subselect(子查询),二是lazy的配置,有三个值
true,false,extra(及其懒惰)第三个的体现主要在于还没有使用结果集时而你想要其中的某个特性或者单个值,他只会执行响应的sql条件语句,而不是查询所有
配置示例:
<set name="linkman" inverse="false" fetch="select" lazy="true">
两两配合效果说明:
- select+true(默认):另外两没什么区别,主要就是何时sql,但是extra与 true的区别不大
- join+???:只要使用了join,不管加载策略是什莫都会失效,这种情况下会立即执行连接查询语句,将所有关联的都准备好
- subselect+???:该情况最主要的体现就是sql子查询语句,比如当我们去查询该类集合时就会打印出select‘------in 【】。
-
关联属性策略
该策略主要用于包含对象的一方,同样是从两个方向,不过取值不同,lazy有两个取值,false,懒加载,proxy:根据类加载级别而定,fetch有两个值,join,select
配置示例:
<many-to-one name="customer" column="lkm_cust_id" class="Customer" fetch="join" lazy="proxy"></many-to-one>
-
结论:使用默认值即可,效率最高
注意事项:no-session问题的解决
默认情况下,如果要想获得结果集,session必须是开启状态并且还是相关联的,但是一般使用是在页面使用,这时session的作用域只是service和dao层,如果想使用
">
```
结论:使用默认值即可,效率最高
注意事项:no-session问题的解决
默认情况下,如果要想获得结果集,session必须是开启状态并且还是相关联的,但是一般使用是在页面使用,这时session的作用域只是service和dao层,如果想使用
需要将三层都包裹在内,解决的方案就是采用filter,在放行前打开,放行后关闭session。