1. 读取配置文件Configuration类
2. 创建SessionFactory对象
3. 创建Session对象
4. 开启事务
5. 进行数据库操作
6. 提交事务
7. 关闭Session
8. 关闭SesstionFactory
Hibernate在查询数据的时候,并没有将数据加载到内存中。只有真正操作数据的时候对象才会存在于内存当中,这样实现了懒加载。节省了服务器的内存开销,从而提高了服务器的性能
在配置文件中使用 many-to-one one-to-many many-to-many
临时/瞬时状态 transient
当我们直接new出来的对象就是临时/瞬时状态的
该对象还没有被持久化【没有保存在数据库中】
不受Session的管理
持久态
当保存在数据库中的对象就是持久化状态了
当调用session的save/saveOrUpdate/get/load/list等方法的时候,对象就是持久化状态
在数据库有对应的数据
受Session的管理
当对对象属性进行更改的时候,会反映到数据库中
游离态
当Session关闭了以后,持久化的对象就变成了游离状态了 或者使用delete方法删除了这个数据
不处于session的管理
数据库中有对应的记录
三态
1.瞬态:通过Java关键字new的实体类对象,不和Session实例关联并且在数据库中没有和瞬态对象关联的记录,此时的对象还没有纳入Hibernate的缓存管理中。
2.持久态: 已经被保存进数据库的实体对象,还存于Hibernate的缓存管理之中。
3.游离态(脱管态):持久态对象脱离了Hibernate的缓存管理后就会变成游离态,游离态对象与瞬态对象的最大区别在于,游离态对象在数据库中可能存在一条与之对应的记录,而瞬态对象则不会在数据库中存在与之对应的记录,简而言之就是游离态对象比瞬态对象多了一个ID属性。
1立即检索;
优点: 对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便的从一个对象导航到与它关联的对象;
缺点: 1.select语句太多;2.可能会加载应用程序不需要访问的对象白白浪费许多内存空间;
2延迟检索:
优点: 由应用程序决定需要加载哪些对象,可以避免可执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并且能节省内存空间;
缺点: 应用程序如果希望访问游离状态代理类实例,必须保证他在持久化状态时已经被初始化;
3 迫切左外连接检索
优点: 1对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便地冲一个对象导航到与它关联的对象。2使用了外连接,select语句数目少;
缺点: 1 可能会加载应用程序不需要访问的对象,白白浪费许多内存空间;2复杂的数据库表连接也会影响检索性能;
1.放入二级缓存的对象,只读(Read-only);
2.非严格的读写(Nonstrict read/write)
3.读写; 放入二级缓存的对象可以读、写(Read/write);
4.基于事务的策略(Transactional)
sorted collection 是在内存中进行排序
ordered collection 是在数据库中通过order by进行排序
一级缓存
也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效
只要是持久化对象状态的,都受Session管理,也就是说,都会在Session缓存中!
Session的缓存由hibernate维护,用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit()/clear()方法操作。
二级缓存
二级缓存是基于应用程序的缓存,所有的Session都可以使用
Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。
如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。
Hibernate二级缓存:存储的是常用的类
一级缓存,session对象的生命周期与一个数据库事务或应用事务相对应。因此session对象的缓存是事务范围的缓存。在一级缓存中,持久化类的实例都有一个唯一的OID
二级缓存,SessionFactory缓存。
由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件。
1 很少被修改的数据
2 不是很重要的数据,允许出现偶尔并发的数据
3 不会被并发访问的数据
4 常量数据
不适合存放到第二级缓存的数据?
1.经常被修改的数据
2.绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
3.与其他应用共享的数据。
LinkMan linkMan = session.get(LinkMan.class,1l);
Customer customer = linkMan.getCustomer();
Customer customer = session.get(Customer.class,2l);
Set<LinkMan> linkMans = customer.getLinkMans();
? 数据库设计调整
? HQL优化
? API的正确使用(如根据不同的业务类型选用不同的集合及查询API)
? 主配置参数(日志,查询缓存,fetch_size, batch_size等)
? 映射文件优化(ID生成策略,二级缓存,延迟加载,关联优化)
? 一级缓存的管理
? 针对二级缓存,还有许多特有的策略
inverse属性默认是false,就是说关系的两端都来维护关系。
1. 比如Student和Teacher是多对多关系,用一个中间表TeacherStudent维护。Gp)
2. 如果Student这边inverse=”true”, 那么关系由另一端Teacher维护,就是说当插入Student时,不会操作TeacherStudent表(中间表)。只有Teacher插入或删除时才会触发对中间表的操作。所以两边都inverse=”true”是不对的,会导致任何操作都不触发对中间表的影响;当两边都inverse=”false”或默认时,会导致在中间表中插入两次关系。
如果表之间的关联关系是“一对多”的话,那么inverse只能在“一”的一方来配置!
JDBC
手写sql
delete、insert、update要将对象的值一个一个取出传到sql中,不能直接传入一个对象。
select:返回的是一个resultset,要从ResultSet中一行一行、一个字段一个字段的取出,然后封装到一个对象中,不直接返回一个对象。
hibernate 全自动
不写sql,自动封装
delete、insert、update可以传入对象
select直接返回对象
ibatis 半自动
手动sql
delete、insert、update可以传入对象
select直接返回对象
SessionFactory是Hibernate中的数据库存储的一个概念,他是线程安全的, 可以被多个线程并发访问。SessionFactory一般只会在启动的时候构建。
SessionFactory接口负责Hibernate的初始化和建立Session对象。
它在Hibernate中起到一个缓冲区作用. Hibernate可以将自动生成的SQL语句、映射数据以及某些可重复利用的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。
SessionFactory是一个线程安全的对象,所有由该工厂生产的Session都共享工厂中维护的数据 .
get() 立即加载
get()方法返回的是一个实例对象。如果不存在该数据,返回null
load() 延迟加载
load() 首先在一级缓存中查找, 如果没有查找到返回一个代理对象。 然后在二级缓存,数据库中查找。如果不存在这个数据。就会报错
merge的出现的原因
在一个session中存在两个不同的实体却有着相同的身份标签(主键)是会报错的,这时为了避免这种错误就可以使用Hibernate提供的merge()方法。
merge()方法的使用特性
1.new一个对象并设置ID时,这个对象会被当作游离态处理,在使用merge时,如果在数据库中不能能找到这条记录,则使用insert将数据插入;如果在数据库中找到这条记录,则使用update将数据更新。
2.new一个对象没有设置ID时,这个对象会被当作瞬态处理,在使用merge时会根据实体类的主键生成策略保存这条数据。
3.使用merge存储到数据库的对象,其本身不会转变为持久态对象。
1.persist不保证立即执行,要等到flush
2.save()立即执行,将瞬态转换为持久化
3.persist()没有返回值
4.save()返回持久化标识符(对象的主键)
1.identity自增长 (mysql db2)
2.sequence 自增长(序列) oracle 序列的方式实现自增长
3.native 自动选择
mysql 选择 identity oracle 选择 sequence
4.increment 自增长(会有并发访问的问题,一般在服务器集群环境使用会存在问题。)
指定主键生成策略为手动指定主键的值
assigned
指定主键生成策略为UUID生成的值
uuid
1.getCurrentSession()获得的session与当前的线程进行绑定。而openSessoin()是创建一个新的session
2.getCurrentSession()的事务是由spring控制的。 openSessoin()需要手动开启和关闭事务
3.getCurrentSession需要我们手动设置绑定事务的机制,有三种设置方式,jdbc本地的Thread、JTA、第三种是spring提供的事务管理机制org.springframework.orm.hibernate4.SpringSessionContext,而且srping默认使用该种事务管理机制
因为hibernate要通过反射来创建实体类,调用Class.newInstance()。 如果没有无参构造就会报错
是可以的,但是不推荐。 hibernate中的延迟加载使用的是cligb代理,这个代理是实体类的子类。所以实体类最好不要设置为final。
1.清理缓存调用的是 session.flush() 方法.
2.清空调用的是 session.clear() 方法.
3.Session清理缓存是指按照缓存中对象的状态的变化来同步更新数据库,但不清空缓存;
4.清空是把Session 的缓存置空, 但不同步更新数据库;
优点
1. 封装了JDBC,简化了数据访问层繁琐的重复性代码
2. 使用了一级缓存、二级缓存
3. 非侵入性、移植性会好
4. 灵活的映射关系,适应各种数据库。支持复杂的一对多 多对多的方式
缺点
1. 框架使用ORM使得配置复杂
2. 执行效率和原生的JDBC 相比偏差: 特别是在批量数据处理的时候
3. 不支持批量修改和删除
4. 无法对sql进行优化
直接通过 JDBC API 执行相关的 SQl 语句或调用相关的存储过程是最佳的方式
1.使用双向一对多关联,不使用单向一对多
2.灵活使用单向一对多关联
3.不用一对一,用多对一取代
4.配置对象缓存,不使用集合缓存
5.一对多集合使用Bag,多对多集合使用Set
6. 继承类使用显式多态
1.悲观锁
行级悲观锁:Hibernate总是使用数据库的锁定机制,从不在内存中锁定对象!只要为JDBC连接指定一下隔 离级别,然后让数据库去搞定一切就够了。
2.乐观锁
使用版本号或时间戳来检测更新丢失,在的映射中设置 optimistic-lock=”all”可以在没有版本或者时间戳属性映射的情况下实现 版本检查,此时Hibernate将比较一行记录的每个字段的状态
1.Read-only: 这种策略适用于那些频繁读取却不会更新的数据,这是目前为止最简单和最有效的缓存策略
2.Read/write:这种策略适用于需要被更新的数据,比read-only更耗费资源,在非JTA环境下,每个事务需要在session.close和session.disconnect()被调用
3.Nonstrict read/write: 这种策略不保障两个同时进行的事务会修改同一块数据,这种策略适用于那些经常读取但是极少更新的数据
4.Transactional: 这种策略是完全事务化得缓存策略,可以用在JTA环境下
参考blog
https://blog.csdn.net/wu1317581750/article/details/82530907
https://blog.csdn.net/weixin_30340353/article/details/95160437
https://www.cnblogs.com/yanggb/p/11268377.html
原文:https://www.cnblogs.com/jiahaodaicoder/p/14662179.html