hibernate的一级缓存
1.什么是缓存
数据存到数据库里面,数据库本身是文件系统,使用流的方式操作文件效率不是很高
-把数据存到内存中,不需要使用流方式,可以直接读取内存中数据
2.hibernate缓存
hibernate框架中提供了很多优化的方式
-hibernate的缓存就是一个优化方式
hibernate缓存的特点
-hibernate的一级缓存
hibernate的一级缓存默认是打开的
hibernate的一级缓存使用范围,是session的范围,创建到关闭之间
hibernate的一级缓存中,存储数据必须是持久态数据
-hibernate的二级缓存
目前不使用,而是用替代技术 redis
默认关闭
使用范围是整个项目(sessionFactory)的范围
验证一级缓存
1.验证方式
- 首先根据id=1查询,返回对象
- 再根据id=1查询,再返回一个对象
第一次查询是从数据库里面查询,会发送SQL语句。第二次是从缓存里面查询,不会发送SQL语句
2.一级缓存的特性
持久态会自动更新数据库,不需要写update
hibernate事务代码规范写法
代码结构
Try{
开启事务
提交事务
}catch{
回滚事务
}finally{
关闭事务
}
hibernate绑定session(绑定本地线程来保证单线程,保证两次不是同一个对象)
1.session类似于jdbc的connection,web里学过threadLocal本地线程
2.hibernate底层帮助实现了本地线程绑定session,我们只需配置
3.获取与本地线程绑定session
- 在hibernate核心配置文件中配置
<property name="hibernate.current_session_context_class">thread</property> |
- 调用sessionFactory里面的方法得到
//提供返回与本地线程绑定的session方法
public static Session getSessionObject(){ return sessionFactory.getCurrentSession(); } |
4.获取与本地线程绑定session的时候,关闭session会报错,那是因为本地线程一结束,session
就会跟着关闭,所有就不需要我们自动关闭,session.close()不需要写
hibernate的API使用(查询)
* Query对象
- 使用query对象,不需要写SQL语句,但要写hql语句
->hql:hibernate query language,hibernate提供的查询语言,和普通SQL语句很相似
->hql和SQL语句区别:
使用SQL操作表和表字段
使用hql操作实体类和属性
- hql语句查询所有
(1) from 实体类名称
- Query对象使用
(1) 创建Query对象
(2) 调用query对象里面方法得到结果
代码: //1 创建Query对象 //方法里面写hql语句 Query query = session.createQuery("from User"); //2 调用query对象里面方法得到结果 List<User> list = query.list(); //遍历集合 for(User user:list){ System.out.println(user); } |
* Criteria对象
- 使用这个对象查询操作不需要写语句,直接调用方法,它已经给我们封装了
- 实现过程
(1) 创建Criteria对象
(2) 调用Criteria对象里面方法得到结果
代码: //1 创建Criteria对象 //方法里面参数是实体类class Criteria criteria = session.createCriteria(User.class); //2 调用query对象里面方法得到结果 List<User> list = criteria.list(); //遍历集合 for(User user:list){ System.out.println(user); } |
* SQLQuery对象
- 在使用hibernate的时候,也可以调用底层SQL语句来实现
- 实现过程:
(1) 创建SQLQuery对象
(2) 调用SQLQuery对象里面方法得到结果
- 返回的list集合中每部分都是数组
代码: //1 创建Criteria对象 //方法里面参数是实体类class SQLQuery sqlQuery = session.createSQLQuery("select * from student"); //2 调用query对象里面方法得到结果 //返回list集合,默认里面每部分都是数组结构 List<Object[]> list = sqlQuery.list(); //遍历集合 for(Object[] objects:list){ System.out.println(Arrays.toString(objects)); } |
//返回list中每部分是对象形式
代码: sqlQuery.addEntity(User.class); List<User> list = sqlQuery.list(); for(User user : list){ System.out.println(user); } |
表与表之间的关系
1 一对多(分类和商品)
2 多对多(订单和商品)
3 一对一(一夫一妻制)
Hibernate一对多操作
一对多映射配置
以客户和联系人做演示
1 创建两个实体类,客户和联系人
2 让这两个实体类之间先互相表示
-- 在客户实体类里面表示多个联系人
* 一个客户里面有多个联系人
代码: private Set<LinkMan> setLinkMan = new HashSet<LinkMan>(); public Set<LinkMan> getSetLinkMan() { return setLinkMan; } public void setSetLinkMan(Set<LinkMan> setLinkMan) { this.setLinkMan = setLinkMan; } |
--在联系人实体类里面表示所属客户
* 一个联系人只能属于一个客户
代码: private Customer customer; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } |
3 配置映射关系
* 一般一个实体类对应一个映射文件
* 把映射最基本配置完成
* 在映射文件中配置一对多的关系
在客户映射文件中,表示所有联系人
代码 <!-- 在客户映射文件中,表示所有联系人 使用set标签表示所有联系人 set标签里面有name属性: 属性里面写在客户实体类里面表示联系人的set集合名字 --> <set name="setLinkMan" cascade = "save-update"> <!-- hibernate机制:双向维护外键,在一和多的那一方都要配置外键 column 外键名称 --> <key column="clid"></key> <!-- 客户所有联系人,class里面写联系人实体类全路径--> <one-to-many class="com.hibernate.entity.LinkMan"/> </set> |
在联系人映射文件中,表示所有客户
代码 <!-- 表示联系人所属客户 name属性:因为联系人实体类使用customer对象表示,写customer名称 class属性:customer全路径 column属性:外键名称 --> <many-to-one name="customer" class="com.hibernate.entity.Customer" column="clid"></many-to-one> |
4 创建核心配置文件,把映射文件引入到核心配置文件中
代码 <!-- 第三部分,把映射文件放到核心配置文件中-必须的--> <mapping resource="com/hibernate/entity/Customer.hbm.xml"/> <mapping resource="com/hibernate/entity/LinkMan.hbm.xml"/> |
一对多级联操作
1 级联保存
添加一个客户,为这个客户添加多个联系人的过程就叫级联保存
级联保存配置:
<set name="setLinkMan" cascade = "save-update"> |
2 级联删除
删除一个客户,这个客户里面所有的联系人也要跟着删除
级联删除配置:
<set name="setLinkMan" cascade = "save-update,delete"> |
一对多修改操作
1 让一个联系人从原先所属客户换到另一个客户名下
根据id查询到联系人与客户,把联系人放到客户里面去,把客户放到联系人里面去。
2 inverse属性
(1) 因为Hibernate是双向维护外键机制,在客户和联系人都需要维护外键,修改客户时会修改一次外键,修改联系人时又会修改一次外键,这样就重复修改,会导致效率变低
(2) 解决方式,让其中一方放弃维护外键
- 一对多中,让一的这一方放弃维护
(3) 具体实现
在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性
在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性 inverse属性默认值为 FALSE false:表示不放弃维护 true:表示放弃维护 --> <set name="setLinkMan" cascade = "save-update,delete" inverse="true"> |