-
自然主键: 把有特定业务含义的字段作为了主键 eg: 用户的名字, 身份证号码
-
代理主键: 把没有特定业务含义的字段作为了主键 eg: id
开发里面的话通常用代理主键
2.主键的生成策略
Hibernate中为了更好的维护数据, 提供很多种主键生成策略.
2.2 主键策略类型
-
increment :自动增长,适用类型:short,int,long类型主键.在多进程和集群下不要使用.用的不是数据库的自动增长, hibernate底层的增长策略,select max(id) from customer; 然后+1作为下一条记录的ID.
-
assigned:需要用户手动输入OID的.
-
identity:自动增长,用的是数据库的自动增长。适用类型:short,int,long类型主键.支持自动增长数据库如Mysql
-
sequence:序列,适用类型:short,int,long类型主键.支持序列的数据库如:Oracle.
-
native:本地策略,根据数据库的底层采用使用identity还是sequence.
-
uuid:随机的字符串,适用于字符串类型的主键.
规则: 如果主键类型是 int short long 用 native
如果主键类型是字符串, 用uuid
1.持久化类概述
在Hibernate中,用来描述数据库表结构的类,称之为持久化类.
Java类与数据库的某个表建立了映射关系.这个类就称为是持久化类
持久化类 = Java类 + hbm的配置文件
2.持久化类定义规范
-
遵循JavaBean定义规范
类是公有的
需要一个无参的构造函数
属性是私有的,需要提供公共的getter和setter方法进行访问属性
-
必须用一个属性描述数据库表的主键
-
主键属性的类型必须是引用类型,且需要实现Serializable接口
1.概述
由持久化类创建的对象就是持久化对象。Hibernate为了管理持久化对象:将持久化对象分成了三个状态.hibernate底层实现过程中,定义的三种状态主要方便开发人员调用session的API.
区分三种状态:
瞬时态 :没有持久化标识OID的,没有纳入到session的管理.
持久态 :有持久化标识OID的,已经纳入到session的管理.
托管(游离态)态:有持久化标识OID的,没有纳入到session的管理.
java代码:
/** * 区分三种状态: * 瞬时态: 没有持久化标识oid,没有纳入Session管理 * 持久态: 有持久化标识oid,并且纳入了Session管理 * 托管态: 有持久化标识oid,但没有纳入Session管理 */ @Test public void fun01(){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); transaction.begin(); User user = new User();//瞬时态 user.setUname("张三"); user.setUage(18); session.save(user); System.out.println(user.toString());//持久态 transaction.commit(); session.close(); System.out.println(user.toString());//托管态 }
没有持久化标识OID, 没有被纳入到Session对象的管理
-
获得:new对象
-
状态转换:
瞬时态--->持久态:save()/saveOrUpdate();
瞬时态--->托管态:把瞬时态对象设置一个id
2.2持久态对象
有持久化标识OID,已经被纳入到Session对象的管理
-
获得:get()/load()/find()..
-
状态转换:
持久态--->瞬时态:session.delete(); (Hibernate中不建议使用的)
持久态--->托管态:close()/clear()/evict(Object obj);
2.3托管态对象
有持久化标识OID,没有被纳入到Session对象的管理
-
获得:new对象,给对象设置id
-
状态转换:
托管态-->瞬时态:把对象的id设置为null
托管态--->持久态:update()/saveOrUpdate();
持久态对象依赖于缓存可以自动更新数据库
-
Java代码
1 @Test 2 public void fun05(){ 3 Session session = HibernateUtils.openSession(); 4 Transaction transaction = session.beginTransaction(); 5 transaction.begin(); 6 //持久态对象 7 User user = session.get(User.class, 1); 8 user.setUname("李四"); 9 //session.update(user);可以不写,因为当前的user是持久化对象 10 11 transaction.commit(); 12 session.close(); 13 }
1.缓存概述
缓存就是一块内存空间。
将数据源(数据库或者文件)中的数据读取出来存放到缓存中,再次获取的时候 ,直接从缓存中获取,这样可以提升程序的性能!
作用:提升程序的性能
2.Hibernate的缓存类别
一级缓存:session对象的缓存,自带的不可卸载的. 一级缓存的生命周期与session一致。
二级缓存:二级缓存可以在多个session中共享数据。一般不会用,企业里通常使用Redis
3.一级缓存
在 Session 接口的实现中包含一系列的 Java集合,这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期.
当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图get()、 load()对象时,会判断缓存中是否存在该对象,有则返回,此时不查询数据库。没有再查询数据库.
@org.junit.Test public void fun03(){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); //持久态对象 User user1 = session.get(User.class, 1);//马上发送一条sql语句 System.out.println(user1.toString()); User user2 = session.get(User.class, 1);//马上发送一条sql语句 System.out.println(user1 == user2);//true transaction.commit(); session.close(); }
测试结果:
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.uname as uname2_0_0_,
user0_.uage as uage3_0_0_
from
user user0_
where
user0_.uid=?
User{uid=1, uname='李四', uage=18}
true
4.一级缓存的内部结构:(缓存区, 快照区)
事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败.
2.事务的特性
原子性: 事务不可分割.
eg: 张三 1000 李四 1000; 张三给李四转100, 要么转账成功,要么失败
一致性: 事务执行的前后数据的完整性保持一致.
eg: 张三 1000 李四 1000 =2000; 张三给李四转100, 成功了 张三 900 李四1100 = 2000; 失败
隔离性: 一个事务执行的过程中,不应该受到其他的事务的干扰.
持久性: 事务一旦提交,数据就永久保持到数据库中.
eg: 张三 1000 李四 1000, 给李四转520;
3.不考虑隔离性会出现的相关问题
-
脏读: 一个事务读到了另一个事务未提交的数据.
-
不可重复读: 一个事务读到了另一个事务已经提交的update数据,导致多次查询结果不一致. 张三 1000 ; 李四 1000
-
虚读: 一个事务读到了另一个事务已经提交的insert数据,导致多次查询结构不一致.
4.隔离级别
隔离级别 | 含义 |
---|---|
READ_UNCOMMITTED | 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读 |
READ_COMMITTED | 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生 |
REPEATABLE_READ | 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。 |
SERIALIZABLE | 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。 |
实际开发中,不会选择最高或者最低隔离级别,选择 READ_COMMITTED(oracle 默认)、REPEATABLE_READ (mysql默认)
5.Hibernate配置隔离级别
hibernate通过在hibernate.cfg.xml的配置文件中设置隔离级别:
<property name="hibernate.connection.isolation">4</property>
取值
1: Read uncommitted isolation,读未提交
2: Read committed isolation,读已提交,解决脏读。
4: Repeatable read isolation,可重复读
8: Serializable isolation,串行化
6.hibernate对 session的管理
6.1把Session绑定在当前线程
在开发中,通常在业务层进行事物管理,在Dao层操作数据库. 也就是说业务层需要连接(Session)开启事物,Dao层需要连接(Session)操作数据库,如何保证这些连接是同一个呢?
在JDBC阶段,我们通过了两种方式解决:
1.向下传递参数
2.绑定到TreadLocal里面.
在Hibernate中,Session 对象与本地线程绑定很简单,只需要两步:
-
在hibernate.cfg.xml文件中,添加属性,开启与本地线程绑定的session
<property name="hibernate.current_session_context_class">thread</property>
-
通过SessionFactory的getCurrentSession()方法获得Session
Session session = sessionFactory.getCurrentSession();
注意:通过getCurrentSession()方法获得的session,无需调用close方法释放资源。当事物提交或者回滚,会自动释放资源.
6.2 Session获取方式的区别
-
调用getCurrentSession()方法时,会判断当前线程中是否绑定了session。
如果绑定了,直接返回线程中绑定的session
如果没有绑定,先去创建一个session,然后讲session存储到当前线程中,再返回。
-
调用openSession()方法时,只会创建一个新的session,且不会存储到当前线程。
-
通过getCurrentSession()方法获得的session,无需调用close方法释放资源. 通过openSession()方法获得的session需要手动释放资源。