A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始


【郑州校区】三大框架课堂笔记之Hibernate-day07(下)

【郑州校区】三大框架课堂笔记之Hibernate-day07(上)

多表操作
SQL多表操作
1.交叉连接  CROSS JOIN  会产生迪卡尔积
SELECT * FROM t_customer CROSS JOIN t_order;
2.内连接  INNER JOIN  ON
SELECT * FROM t_customer AS c INNER JOIN t_order AS o ON c.id=o.c_customer_id;
使用内连接它只能将有关联的数据得到。
隐式内连接  使用 "逗号"将表分开,使用WHERE来消除迪卡尔积
SELECT * FROM t_customer AS c ,t_order o WHERE c.id=o.c_customer_id;
3.外连接  左外LEFT OUTER JOIN    右外RIGHT OUTER JOIN
OUTER可以省略
SELECT * FROM t_customer c LEFT OUTER JOIN t_order o ON c.id=o.c_customer_id;
HQL多表操作
        Hql多表操作分类:
1. 交叉连接
2. 内连接
a) 显示内连接
b) 隐式内连接
c) 迫切内连接
3. 外连接
左外连接
迫切左外连接
右外连接
注意:在hibernate中有迫切连接的概念,而sql中没有。
内连接显示内连接
显示内连接使用的是inner join with
隐式内连接
隐式内连接也我们在sql中操作不一样,它是通过”.”运算符来关联
迫切内连接
迫切内连接得到的结果是直接封装到PO类中,而内连接得到的是Object[]数组,数组中封装的是PO类对象。
外连接
Hibernate事务管理事务介绍
问题:什么是事务?
        事务就是逻辑上的一组操作,组成这组操作的各个单元要么全部成功,要么全都失败。
问题:事务四个特性?
        原子性:不可分割
        一致性:事务在执行前后,要保证数据的一致。
        隔离性:一个事务在执行的过程中,不应该受到其它事务的干扰。
        持久性:事务一旦结束,数据持久化到数据库。
问题:不考虑事务的隔离性,会产生什么问题?
        脏读:一个事务读取到另一个事务的未提交数据
不可重复读:一个事务读取到另一个事务提交的数据(主要是指update),会导致两次读取的结果不一致。
虚读(幻读): 一个事务读取到另一个事务提交的数据(主要是指insert),会导致两次读取结果不一致.
问题:对于上述问题如何解决?
        我们可以通过设置隔离级别来解决.
        READ_UNCOMMITED 读取未提交,它引发所有的隔离问题
        READ_COMMITTED  读已提交,阻止脏读,可能发生不可重复读与虚读.
        REPEATABLE_READ 重复读  阻止脏读,不可重复读 可能发生虚读
SERIALIZABLE 串行化 解决所有问题 不允许两个事务,同时操作一个目标数据。(效率低下)
ORACLE  默认的是事务隔离级别  READ_COMMITTED
MYSQL 默认的事务隔离级别  REPEATABLE_READ
Hibernate中设置事务隔离级别
hibernate.connection.isolation
它可取的值有 1 2 4 8
1代表的事务隔离级别为READ UNCOMMITTED
2代表的事务隔离级别为READ COMMITTED
4.代表的事务隔离级别为 REPEATABLE READ
8代表的事务隔离级别为 SERIALIZABLE
在hibernate.cfg.xml文件中配置
Hibernate中session管理
Hibernate提供了三种管理session的方式:
1. Session对象的生命周期与本地线程绑定(ThreadLocal)
2. Session对象的生命周期与JTA事务绑定(分布式事务管理)
3. Hibernate委托程序来管理Session的生命周期
我们之前所使用的是第三种 ,通过程序获取一个Session对象,使用它,最后session.close();
在实际开发中我们一般使用的是前两种:
        主要介绍关于本地线程绑定Session。
        步骤:
1. 需要在hibernate.cfg.xml文件配置
2. 在获取session时不要在使用openSession而是使用getCurrentSession()方法。
关于getCurrentSession使用时的注意事项:
上述代码执行后,会产生问题
原因:使用getCurrentSession获取的与线程绑定的session对象,在事务关闭时,session对象也会close,简单说,就不需要我们在手动close;
Hibernate优化方案HQL优化1.使用参数绑定
        1.使用绑定参数的原因是让数据库一次解析SQL,对后续的重复请求可以使用用生成好的执行计划,这样做节省CPU时间和内存。
        2.避免SQL注入
2.尽量少使用NOT
        如果where子句中包含not关键字,那么执行时该字段的索引失效。
3.尽量使用where来替换having
Having在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录的数目,能减少这方面的开销
4.减少对表的查询
        在含有子查询的HQL中,尽量减少对表的查询,降低开销
5.使用表的别名
当在HQL语句中连接多个表时,使用别名,提高程序阅读性,并把别名前缀与每个列上,这样一来,可以减少解析时间并减少列歧义引起的语法错误。
6.实体的更新与删除
        在hibernate3以后支持hql的update与delete操作
一级缓存优化
一级缓存也叫做session缓存,在一个hibernate session有效,这级缓存的可干预性不强,大多于hibernate自动管理,但它提供清除缓存的方法,这在大批量增加(更新)操作是有效果的,例如,同时增加十万条记录,按常规进行,很可能会出现异常,这时可能需要手动清除一级缓存,session.evict以及session.clear.
检索策略(抓取策略)延迟加载
延迟加载 是hibernate为提高程序执行的效率而提供的一种机制,即只有真正使用该对象的数据时才会创建。
load方法采用的策略延迟加载.
get方法采用的策略立即加载。
检索策略分为两种:
1. 类级别检索
2. 关联级别检索
类级别检索
类级别检索是通过session直接检索某一类对应的数据,例如
Customer c=session.load(Customer.class,1)
Session.createQuery(“from Order”)
类级别检索策略分为立即检索与延迟检索,默认是延迟检索,类级别的检索策略可以通过<class>元素的lazy属性来设置 ,默认值是true
在hbm配置文件中设置
在类中使用注解
如果将lazy设置为false,代表类级别检索也使用立即检索。这时load与get就一样,都是立即检索。
如果对一个延迟代理对象进行初始化?
关联级别检索
        查询到某个对象,获得其关联的对象或属性,这种称为关联级别检索,例如
        c.getOrders().size()
        c.getName()
        对于关联级别检索我们就要研究其检索策略(抓取策略)
检索策略(抓取策略)抓取策略介绍
指的是查找到某个对象后,通过这个对象去查询关联对象的信息时的一种策略。
一对一 <one-to-one>
一对多(多对一) <set>下有<one-to-many>  <many-to-one>
多对多 <set>下有<many-to- many>
我们主要是在<set>与<many-to-one>或<one-to-one>上设置fetch  lazy
例如:查询一个客户,要关联查询它的订单
客户是一的一方,在客户中有set集合来描述其订单,在配置中我们是使用
<set>
        <one-to-many>
</set>..
可以在set标签上设置两个属性  fetch   lazy
Fetch主要描述的是SQL语句的格式(例如是多条,子查询,多表联查
Lazy 控制SQL语句何时发送
例如:在查询一个订单时,要查询客户信息
<many-to-one> 或<one-to-one>
也可以设置fetch  lazy
Fetch主要描述的是SQL语句的格式(例如是多条,子查询,多表联查
Lazy 控制SQL语句何时发送
总结:
讲解抓取策略
在两方面设置
<set fetch=”” lazy=””>
<many-to-one fetch=”” lazy=””>
<one-to-one>
注解配置抓取策略
问题:如何使用注解来设置
在<setse>设置的fetch与lazy可以使用下面注解来描述
在<many-to-one>或<one-to-one>上如何设置 fetch与lazy
set上的fetch与lazy
set上的fetch与lazy它主要是用于设置关联的集合信息的抓取策略。
Fetch可取值有:
1. SELECT 多条简单的sql   (默认值)
2. JOIN 采用迫切左外连接
3. SUBSELECT 将生成子查询的SQL
lazy可取值有:
1. TURE 延迟检索   (默认值)
2. FALSE 立即检索
3. EXTRA 加强延迟检索(及其懒惰)
第一种组合
会首先查询客户信息,当需要订单信息时,才会关联查询订单信息。
第二种组合
s
当查询客户信息时,就会将订单信息也查询,也就是说订单信息没有进行延迟。
第三种组合
当查询客户信息时,不会查询订单信息,当需要订单的个数时,也不会查询订单信息,
只会通过count来统计订单个数。
当我们使用size(),contains()或isEmpty()方法时不会查询订单信息。
第四种组合
如果fetch选择的是join方案,那么lazy它会失效。
生成SQl将采用的是迫切左外连接(left outer join fetch)
会立即查询。
第五种组合
会生成子查询,但是我们在查询订单时采用的是延迟加载。
第六种组合
会生成子查询,在查询客户信息时,就会将订单信息也查询出来
第七种组合
在查询订单时,只会根据情况来确定是否要订单信息,如果不需要,例如我们
程序中size操作,那么就会发出select count(*) from Order where c_customer_id=?
One的一言fetch与lazy
<set fetch lazy>它主要是设置在获取到一的一方时,如果去查询多的一方。
在<many-to-one>或<one-to-one>如果去查询对方。
对于程序 就是在多的一方如何查询一的主方信息
例如:获取到一个订单对象,要查询客户信息。
Fetch可取值:
        select 默认值,代表发送一条或多条简单的select语句
        join  发送一条迫切左外连接
lazy可取值
        false 不采用延迟加载
        proxy 默认值 是否采用延迟,需要另一方的类级别延迟策略来决定
        no-proxy 不用研究
第一种组合
注意:Customer的类级别延迟策略
当我们执行时,会首先发送一条sql只查询订单信息,客户信息会延迟,只有真正需要客户信息时,才会发送sql来查询客户信息.
第二种组合
注意:Customer的类级别延迟策略
当查询订单时,就会将客户信息也查询到,原因是Customer它的类级别延迟为false,也就是立即查询。
第三种组合
当查询订单时,不会对客户信息进行延迟,立即查询客户信息
第四种组合
如果fetch值为join,那么lazy失效。
会发送一条迫切左外连接来查询,也就立即查询。
批量抓取
我们在查询多个对象的关联对象时,可以采用批量抓取方式来对程序进行优化.
要想实现批量抓取:
可以在配置文件中 batch-size属性来设置
可以使用注解 @BatchSize(size=4)
可以采用批量抓取来解决N+1问题.
查询客户,查询订单
可以在客户配置文件中配置batch-size,是在<set>标签上
查询订单,查询客户
订单与客户,客户它是一个主表,订单是一个从表。
在设置批量抓取时都是在主表中设置
在配置文件中在主表的<calss>标签上设置batch-size
在注解使用中
注意:无论是根据哪一方来查询别一方,在进行批量抓取时,都是在父方来设置 ,
        如果是要查询子信息,那么我们是在<set>上来设置batch-size,如果是从子方来查询父方,
        也是在父方设置在<class>设置batch-size.
        
父与子区分:
        有外键的表是子(从关联方就是父(主)表


传智播客·黑马程序员郑州校区地址
河南省郑州市 高新区长椿路11号大学科技园(西区)东门8号楼三层
联系电话 0371-56061160/61/62
来校路线  地铁一号线梧桐街站A口出

3 个回复

倒序浏览
全部已收藏
回复 使用道具 举报
好人一生平安
回复 使用道具 举报
{:8_507:}
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马