多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] # 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操作 ![](https://box.kancloud.cn/2ccdd52768678700659d5b4799c502b1_622x149.png) ### 一级缓存优化 一级缓存也叫做session缓存,在一个hibernate session有效,这级缓存的可干预性不强,大多于hibernate自动管理,但它提供清除缓存的方法,这在大批量增加(更新)操作是有效果的,例如,同时增加十万条记录,按常规进行,很可能会出现异常,这时可能需要手动清除一级缓存,session.evict以及session.clear. ## 检索策略(抓取策略) ### 延迟加载 延迟加载 是hibernate为提高程序执行的效率而提供的一种机制,即只有真正使用该对象的数据时才会创建。 load方法采用的策略延迟加载. get方法采用的策略立即加载。 检索策略分为两种: 1. 1. 类级别检索 2. 2. 关联级别检索 ### 类级别检索 类级别检索是通过session直接检索某一类对应的数据,例如 Customer c=session.load(Customer.class,1) Session.createQuery(“from Order”) 类级别检索策略分为立即检索与延迟检索,默认是延迟检索,类级别的检索策略可以通过<class>元素的lazy属性来设置 ,默认值是true 在hbm配置文件中设置 ![](https://box.kancloud.cn/cec421db919307765a6ed2a60badb07b_769x365.png) ### 关联级别检索 查询到某个对象,获得其关联的对象或属性,这种称为关联级别检索,例如 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可以使用下面注解来描述 ![](https://box.kancloud.cn/b8f44c2f72d6d99c9ae1321da072d372_784x399.png) ## set上的fetch与lazy set上的fetch与lazy它主要是用于设置关联的集合信息的抓取策略。 Fetch可取值有: 1. SELECT 多条简单的sql (默认值) 2. JOIN 采用迫切左外连接 3. SUBSELECT 将生成子查询的SQL lazy可取值有: 1. TURE 延迟检索 (默认值) 2. FALSE 立即检索 3. EXTRA 加强延迟检索(及其懒惰) ![](https://box.kancloud.cn/413eef459a416dd2230b127ff5677f12_669x446.png) ### 第一种组合 ![](https://box.kancloud.cn/741b5add6353648510577a5315bfe4da_649x129.png) ### 第二种组合 ![](https://box.kancloud.cn/02463fefb17cf7d818a8ced374054728_694x146.png) ### 第三种组合 ![](https://box.kancloud.cn/b68481f990b125995e633dd2b798e834_656x104.png) 当查询客户信息时,不会查询订单信息,当需要订单的个数时,也不会查询订单信息, 只会通过count来统计订单个数。 当我们使用size(),contains()或isEmpty()方法时不会查询订单信息。 ### 第四种组合 如果fetch选择的是join方案,那么lazy它会失效。 生成SQl将采用的是迫切左外连接(left outer join fetch) 会立即查询。 ![](https://box.kancloud.cn/0e851f39fea9105511537111b142494a_646x91.png) ### 第5种组合 ![](https://box.kancloud.cn/2702dedd58e40fa26471c600e60915e9_647x96.png) 会生成子查询,但是我们在查询订单时采用的是延迟加载。 ### 第6种组合 ![](https://box.kancloud.cn/0896c30ad66ce082d012bd5b2b173ef7_659x90.png) 会生成子查询,在查询客户信息时,就会将订单信息也查询出来 ### 第七种组合 ![](https://box.kancloud.cn/02b9c631f96036f4ca942f21ebe7fe42_648x95.png) 在查询订单时,只会根据情况来确定是否要订单信息,如果不需要,例如我们 程序中size操作,那么就会发出`select count(*) from Order where c_customer_id=?` ### 结论 ![](https://box.kancloud.cn/0ca1929b06516a751566df0363b21239_481x226.png) ![](https://box.kancloud.cn/6f78ac5511273b246ebc0004f2d6dacd_570x50.png) no-session问题解决? 扩大session作用范围 ![](https://box.kancloud.cn/a92f261ac8ca1ff40a40581ed5251e2a_568x335.png) ## One的一言fetch与lazy `<set fetch lazy>`它主要是设置在获取到一的一方时,如果去查询多的一方。 在`<many-to-one>或<one-to-one>`如果去查询对方。 对于程序 就是在多的一方如何查询一的主方信息 例如:获取到一个订单对象,要查询客户信息。 Fetch可取值: select 默认值,代表发送一条或多条简单的select语句 join 发送一条迫切左外连接 lazy可取值 false 不采用延迟加载 proxy 默认值 是否采用延迟,需要另一方的类级别延迟策略来决定 no-proxy 不用研究 ![](https://box.kancloud.cn/1d42ed4829d0dc7876d79f87904c1872_667x399.png) ### 第一种组合 ![](https://box.kancloud.cn/6a3134439a29f0bfa4da3c6344a442f0_439x195.png) 当我们执行时,会首先发送一条sql只查询订单信息,客户信息会延迟,只有真正需要客户信息时,才会发送sql来查询客户信息. ### 第二种组合 ![](https://box.kancloud.cn/bd82d518110cc4eebff60ff46e6677b1_802x287.png) ### 第三种组合 ![](https://box.kancloud.cn/88ea439f4eecbe86fd4f1396610d5598_566x137.png) ### 第四种组合 ![](https://box.kancloud.cn/54c5ed43015293adb72eec86639a81ae_470x167.png) ## 批量抓取 我们在查询多个对象的关联对象时,可以采用批量抓取方式来对程序进行优化. 要想实现批量抓取: 可以在配置文件中 batch-size属性来设置 可以使用注解 @BatchSize(size=4) 可以采用批量抓取来解决N+1问题. 抓取客户的时候一次抓取几个联系人 查询客户,查询订单 ![](https://box.kancloud.cn/a0284718ef3f03a323261d94be5ff644_734x473.png) 查询订单,查询客户 ![](https://box.kancloud.cn/314c268f0d00612124b88eac92ab5428_769x578.png) ![](https://box.kancloud.cn/387acc86cd87c7a2a99a5d238e4d2944_815x370.png)