- Hibernate总结
Hibernate详解
https://blog.csdn.net/lsh6688/column/info/lshhibernate
Hibernate入门这一篇就够了
https://www.cnblogs.com/mq0036/p/8522150.html
SSH之Hibernate总结篇
https://www.cnblogs.com/Java-web-wy/p/6533672.html
hibernate学习笔记(一)
https://www.cnblogs.com/zhengcheng/p/5014246.html - Hibernate的三种状态:瞬时态、持久态、托管(即游离态)态及互相转化
https://blog.csdn.net/HD243608836/article/details/77852842
个人笔记:持久化状态对象的任何变化都会自动同步到数据库中,session的get/save/update/delete方法本质上是转换对象状态,get/save/update都会得到持久化状态的对象,从而将对象数据同步到数据库 - 一级缓存及快照/二级缓存
hibernate的缓存和快照
https://blog.csdn.net/jing_44944/article/details/40348107
Hibernate的缓存技术详解
http://www.cnblogs.com/xiaoming0601/p/5882980.html
Hibernate的缓存机制
https://blog.csdn.net/weixin_42669555/article/details/81049420
Hibernate缓存简介和对比、一级缓存、二级缓存详解
https://blog.csdn.net/u012518860/article/details/78256874
hibernate 的缓存机制
https://www.cnblogs.com/wy2185/p/5124443.html
解析hibernate中的缓存
https://www.cnblogs.com/HDK2016/p/7351727.html
hibernate缓存机制详细分析
https://www.cnblogs.com/xiaoluo501395377/p/3377604.html
个人笔记:
调用session的get方法,会发送sql语句到数据库,hibernate将得到的ResultSet结果封装到对象中返回,生成两个对象,一个放入session一级缓存中,另一个放入快照.
此时再次调用get方法获取相同OID的数据时,会先在一级缓存中查找,若已存在,则直接返回此对象.否则再查询数据库.
事务提交时,hibernate会对比缓存和快照中的两个对象(OID相同),若有更改,则发送sql update语句到数据库,若一样,则不操作数据库.
持久化对象即存在于一级缓存的对象.
瞬时->持久化:调用save方法
游离->持久化:调用update方法
saveOrUpdate:自动识别对象状态,将其放入缓存转为持久化对象.
new一个对象并手动赋id值,此时该对象处于什么状态?
若该id在数据库中不存在,则为瞬时状态
若该id存在数据库中,则为游离状态
持久化状态(即存在于session一级缓存中)的对象,会在事务提交时自动同步到数据库中
hibernate中save,update,saveOrUpdate的用法和区别
https://blog.csdn.net/wufaliang003/article/details/73997636
注意:使用sessionFactory的getCurrentSession方法需要在主配置文件中进行配置
<property name="hibernate.current_session_context_class">thread</property>
通过getCurrentSession方法获得session对象,在事务提交时session会自动关闭,不要手动调用close关闭.
hibernate中的批量查询:
1.HQL(hibernate query language)查询:适合不复杂的多表查询
2.Criteria查询:适合单表条件查询
3.原生SQL查询:复杂的业务查询
一对多|多对一
配置文件表达
LinkMan.hbm.xml
<many-to-one name="customer" column="lkm_cust_id" class="Customer" >
</many-to-one>
Customer.hbm.xml
<set name="linkMens" inverse="true" cascade="save-update" >
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
级联操作cascade:
save-update 级联保存更新
delete:级联删除
all:save-update+delete
其本质上是简化操作,减少代码量(即不必对每个对象调用save或delete),可用save-update,不建议使用delete.
inverse:
在保存对象时,一对多关系的两方都会维护外键关系,一的一方在维护外键时,hibernate会发送不必要update语句提交外键id,降低性能.
其本质上是性能优化.
在一的一方配置文件中,配置inverse=“true”,反转,将维护外键关系交给另一方完成.
注意:外键字段在多的一方,多的一方不能放弃维护关系
原则:无论哪方反转,都必须要有一方负责维护关系
一对多关系中,一的一方放弃.因此代码中一的一方也不需要在set属性中add另一方的对象.
删除一的一方时,因为其放弃维护外键且被引用,所以无法直接调用delete删除,设置不反转可解决,会将多的一方的外键字段置为null.或设置cascade=“delete”,级联删除.
多对多(员工与角色)
表中表达
使用中间表,至少两列,都是外键列,分别引用两张表的主键
实体表达
两方都使用集合来表达拥有多个对方
员工对象中使用set集合存角色对象,角色对象中亦使用set集合存员工对象.
配置文件表达
set标签还需带上table属性,指中间表的表名
key的column属性填引用本对象的外建名
many-to-many
User.hbm.xml
<set name="roles" table="sys_user_role">
<key column="user_id"></key>
<many-to-many class="Role" column="role_id"></many-to-many>
</set>
Role.hbm.xml
<set name="users" table="sys_user_role" inverse="true" >
<key column="role_id" ></key>
<many-to-many class="User" column="user_id" ></many-to-many>
</set>
多对多中,维护外键会在中间表插入记录,若两方都维护,则会插入重复记录.
解决方法1:在代码中只在其中一方的set属性中赋值
或2.配置文件中使用inverse=“true”
在开发中遇到多对多关系,一定要选择一方放弃维护关系.
员工与角色中,角色一般已确定,后续录入员工时,对其设置set角色属性,即可完成外键维护,为中间表插入记录.因此选择角色放弃维护外键.
cascade属性同样可减少代码量,可用可不用.
查询总结:
1.oid查询-get
2.对象属性导航查询
3.HQL
4.Criteria
5.原生SQL
HQL
Query query = session.createQuery(String hql)
query.list();
query.uniqueResult();
面向对象,hql语句中不会出现表中字段名
“from Customer”
排序:
“from Customer order by id asc/desc”
条件查询:
“from Customer where id = ?”/ “from Customer where id = :id”
query.setParameter(0,2) / query.setParameter(“id”,2)
分页查询:
query.setFirstResult(0);
query.setMaxResults(2);
统计查询:
“select count(*) from Customer”
“select sum(id) from Customer”
“select avg(id) from Customer”
“select max(id) from Customer”
“select min(id) from Customer”
投影查询:
只查询部分字段
“select name from Customer”
“select id,name from Customer” 用List<Object[]>接收结果
“select new Customer(id,name) from Customer” 用List接收结果,相当于使用构造函数,因此需要创建对应的构造函数
多表查询(不常用)
内连接
内连接
“from Customer c inner join c.linkMens”
用List<Object[]>接收结果,数组中有Customer和LinkMan对象
迫切内连接
“from Customer c inner join fetch c.linkMens”
用List接收结果,linkMan会被封装到Customer的set中
外连接
左外
“from Customer c left join c.linkMens”
左外迫切
右外
“from Customer c right join c.linkMens”
右外迫切
Criteria
Criteria c = session.createCriteria(Customer.class);
List<Customer> list = c.list();
条件查询
c.add(Restrictions.idEq(2l));
c.add(Restrictions.eq(“id”,2l));
分页查询
c.setFirstResult(0);
c.setMaxResults(2);
排序查询
c.addOrder(Order.asc(“id”));
统计查询
c.setProjection(Projections.rowCount());
离线Criteria
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
拼装条件,与Criteria一致
dc.add(Restrictions.isEq(2l));
关联session
Criteria c = dc.getExecutableCriteria(session);
查询优化
类级别查询
懒加载
get方法:立即加载.执行方法时立即发送sql语句查询结果
load方法:默认为懒加载.执行方法时不发送sql语句,先返回一个代理对象,其具有查询数据库的功能,在使用该对象时才发送sql语句执行查询
可以在配置文件的class元素上配置lazy属性来控制是否对类进行懒加载,若lazy=“false”,则load与get无区别
为了提高效率,建议使用懒加载
关联级别查询
集合策略(从Customer获取LinkMan) Customer.hbm.xml
配置文件中set标签的lazy和fetch属性
lazy决定是否懒加载
true(默认值)延迟加载,在使用到集合属性时才查询数据库
false立即加载
extra极其懒惰,在懒加载相同,并且若只获得集合的size,只会用count语句查询
fetch决定加载策略,即使用什么类型的sql语句加载集合数据
select(默认值):单表查询
join:多表查询 left outer join,一条sql语句查出所有字段,此时lazy属性失效,相当于立即加载
subselect:子查询 “from Customer”
懒加载下,当使用list集合中的set属性时,会使用子查询语句获取全部set数据
立即加载下,获取customer集合时,即直接发送两条sql语句获取数据
极其懒惰,使用size时只会用count语句查询
关联属性策略(从LinkMan获取Customer) LinkMan.hbm.xml
many-to-one标签的lazy和fetch属性
lazy:
false:立即加载
proxy(默认值):由customer的类级别加载策略决定
fetch加载策略
select(默认值):单表查询
join:多表查询 left outer join,一条sql语句查出所有字段,此时lazy属性失效,相当于立即加载
结论:fetch选择默认select,lazy选择默认true
no-session问题:懒加载下,数据对象返回到页面上才会进行查询,此时session已经关闭
扩大session的作用范围,filter会在请求到达servlet前先执行,整个流程完成之后(包括页面显示)还会再经过一次filter
filter前处理中,打开session,开启事务.执行完servlet\service\dao\jsp.后处理中关闭session,提交事务
spring提供的OpenSessionInViewFilter可解决该问题
批量抓取:set标签的batch-size="3"属性,抓取集合数量为3