Hibernate持久化类
1. Hibernate持久化类编写规则
- 持久化类需要提供无参数的构造方法
- 持久化类的属性需要私有,对私有的属性提供共有的get和set方法
- 持久化类的属性要尽量使用包装类的类型
- 持久化类要有一个唯一标识OID与表的主键对应
- 持久化类尽量不要用final进行修饰
2.Hibernate的主键生成策略
- increment 数据库自己生成主键. 先从数据库中查询最大的ID值,将ID值加1作为新的主键
- identity 依赖于数据的主键自增功能
- sequence 序列,依赖于数据中的序列功能(Oracle).适用于代理主键
- hilo Hibernate自己实现序列的算法,自己生成主键. (hilo算法 )
- native 自动根据数据库判断,三选一. identity|sequence|hilo
- uuid 生成32位的不重复随机字符串当做主键
- assigned 自己指定主键值. 表的主键是自然主键时使用.
3.Hibernate的持久化对象的三种状态
1.瞬时态(临时态|自由态 transient)
瞬时态的实例是由new命令创建、开辟内存空间的对象,不存在持久化标识OID(相当于主键值),尚未与Hibernate Session关联。
2.持久态(persistent)
持久态的对象存在持久化标识OID,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录。
3.脱管态(离线态|游离态 detached)
脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管态对象发生改变时HIbernate不能检测到。
当某个持久化状态的实例与Session的关联被关闭时就变成了脱管态。
4.三种状态转换
5.持久态对象能够自动更新数据库
//1.根据id查询
User user=session.get(User.class,6);
//2.设置返回对象
user.setUsername("hanmeimei");
//调用方法实现
session.update(user);
执行过程
Hibernate的缓存
Hibernate的缓存分为一级缓存和二级缓存,Hibernate的这两级缓存都位于持久化层,存储的都是数据库数据的备份。其中第一级缓存为Hibernate的内置缓存,不能被卸载。
HIbernate的一级缓存
Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的Java对象。在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库,如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。
Hibernate一级缓存特点
- 当应用程序调用Session接口的save()、update()、saveOrUpdate时,如果Session缓存中没有相应的对象,Hibernate就会自动把从数据库中查询到的相应对象信息加入到一级缓存中去。
- 当调用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果没有再去数据库中查询对应对象,并添加到一级缓存中。
- 当调用Session的close()方法时,Session缓存会被清空。
验证一级缓存存在
1.验证方式
(1)首先根据uid=1查询,返回对象
(2)其次再根据uid=1查询,返回对象
//1.根据uid=6查询
//执行第一个get方法是否查询数据库,是否发送sql语句
User user1=session.get(User.class,6);
System.out.println(user1);
//2.根据uid=6查询
//执行第二个get方法是否查询数据库,是否发送sql语句
User user2=session.get(User.class,6);
System.out.println(user2);
第一次执行get方法之后,发送sql语句查询数据库
第二次执行get方法之后,没有发送sql语句,查询以及缓存内容
hibernate一级缓存的执行过程
Transaction接口
事务
由一条或多条操作数据库的SQL语句组成的一个不可分割的工作单元。
总结:一组对数据库的操作集合,它们要么全部成功,要么全部失败。
事务的四个特性
⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
事务的并发问题
1.脏读:指在一个事务处理过程里读取了另一个未提交的事务中的数据。
2.不可重复读:指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
3.虚读|幻读:一个事务读到了另一个事务已经提交的insert的数据,导致在同一个事务中的多次查询结果不一致。
事务的隔离级别
- Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
- Repeatable read (可重复读):可避免脏读、不可重复读的发生,MYSQL的默认级别。
- Read committed (读已提交):可避免脏读的发生,ORACLE的默认隔离级别。
- Read uncommitted (读未提交):最低级别,任何情况都无法保证。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发的效率就越低。一般情况下,采用读已提交或者可重复读,它能够有效避免脏读和不可重复读。
Hibernate中的事务管理
开启事务
Transaction transaction=session.beginTransaction();
常用方法
commit():提交相关联的session实例
rollback():撤销事务操作
除了在代码中对事务开启,提交和回滚外,还可以在Hibernate的配置文件中对事务进行配置,可以设置事务的隔离级别。
具体配置方法是在hibernate.cfg.xml中<session-factory>
标签元素中进行。
<hibernate-configuration>
<session-factory>
......
<!-- 事务隔离级别
0:TRANSACTION_NONE
1:TRANSACTION_READ_UNCOMMITTED
2:TRANSACTION_READ_COMMITTED
4:TRANSACTION_REPEATABLE_READ
8:TRANSACTION_SERIALIZABLE
-->
<property name="hibernate.connection.isolation">4</property>
......
</session-factory>
</hibernate-configuration>
在Hibernate的配置文件中,hibernate.current_session_context_class属性用于指定塞申斯哦你管理方式,可选值包括
thread:Session对象的生命周期与本地线程绑定
jta:Session对象的生命周期与JTA事务绑定
managed:Hibernate委托程序来管理Session对象的生命周期
在hibernate.cfg.xml中进行如下配置
<!-- 将Session与线程绑定=> 只有配置了该配置,才能使用getCurrentSession -->
<property name="hibernate.current_session_context_class">thread</property>
query接口
Query代表面向对象的一个Hibernate查询操作。在Hibernate中,通常使用session.createQuery()方法接受一个HQL语句,然后调用Query的list()或uniqueResult()方法执行查询。
在hibernate中使用Query对象的步骤
(1)获得Hibernate的Session对象
(2)编写HQL语句
(3)调用session.createQuery创建查询对象
(4)如果HQL语句包含参数,则调用Query的setXXX设置参数
(5)调用Query对象的list()或uniqueResult()方法执行查询
Query query=session.createQuery("from User");
List<User> list=query.list();
for(User user:list){
System.out.println(user);
}
Query常用方法
setter():设置查询语句中的参数,针对不同的数据类型,用不同的setter方法。
iterator():返回Iterator对象,在读取时只能按照顺序方式读取。
uniqueResult():返回唯一的结果,在确保只有一条记录的查询时使用
executeUpdate():支持HQL语句的更新和删除。
setFirstResult():设置获取第一个记录的位置,也就是它表示从第几条记录开始查询,默认从0开始计算。
setMaxResult():设置结果集的最大记录数。
Criteria接口
Criteria Query通过面向对象的设计,将数据查询条件封装为一个对象。简单来说,Criteria Query可以看作是传统SQL的对象化表示
使用Criteria对象查询数据的主要步骤
(1)获得Hibernate的Session对象。
(2)通过Session获得Criteria对象。
(3)使用Restrictions的静态方法创建Criterion条件对象。Restrictions类中提供了一系列用于设定查询条件的静态方法,这些静态方法都返回Criterion实例。每个Criterion实例代表一个查询条件。
(4)向Criteria对象中添加Criterion查询条件。Criteria的add()方法用于加入查询条件。
(5)执行Criteria的list()或uniqueResult()获得结果。
Criteria criteria=session.createCriteria(User.class);
List<User> list=criteria.list();
for(User user:list){
System.out.println(user);
}
SQLQuery
SQLQuery sqlQuery=session.createSQLQuery("select * from t_usesr");
List<Object[]> list=sqlQuery.list();
for(Object[] objects:list){
System.out.println(Arrays.toString(objects);
}
返回list集合每部分是数组
返回list中,每部分是对象
SQLQuery sqlQuery=session.createSQLQuery("select * from t_usesr");
List<User> list=sqlQuery.list();
for(User user:list){
System.out.println(Arrays.toString(user);
}