目录
一 、主键的分类
(1)、自然主键 :以表中的一个字段为主键
(2)、代理主键 :自定义一个与表中不相关的一个字段为主键
二 、主键的生成策略
increment :hibernate 中提供的自动增长机制 ,由Hibernate发送语句从数据库中查出主键的最大值(每个session只查1 次),以 该值为基础,每次增量+1,在内存中生成主键,在单线程中使用,适用于 short 、int 、long 类型的主 键。
identity :适用于 short 、int 、long 类型的主键。使用的是数据库底层的自动增长机制 ,因此适用于有自动增长机制的数 据 库(MySQL),不适用于Oracle,因为Oracle没有自动增长 ,是采用序列的方式 。
sequence :适用于 short 、int 、long 类型的主键。采用的是序列的方式,适用于Oracle ,不适用于MySQL
uuid :随机生成字符串类型的主键
native :根据使用的数据库自行判断采用identity、sequence其中一种作为主键生成方式
assigned :Hibernate不负责维护主键生成,需要手动设置
在映射配置文件中设置主键的生成策略,代码如下 : <generator class="native"/>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 建立类与表的映射 -->
<class name="czm.hibernate.demo.User" table="UserData"> //全路径+类名称 , 数据库表名称
<!-- 建立类中的属性与表中的主键对应 -->
<id name="uid" column="uid" >
<!-- 定义主键生成策略 -->
<generator class="native"/>
</id>
<!-- 建立类中的普通的属性和表的字段的对应 -->
<property name="username" column="username" length="32" />
<property name="age" column="age"/>
<property name="password" column="password"/>
<property name="phone" column="phone"/>
<property name="address" column="address"/>
</class>
</hibernate-mapping>
三 、持久化类的三种状态
1 、瞬时态 :此对象没有唯一的标识 id ,没有被 session 管理 ,称为瞬时态对象
2 、持久态 :此对象有唯一标识 id ,并且被 session 管理 ,称为持久态对象
3 、脱管态 :此对象有唯一标识 id ,但没有被 session 管理 ,称为脱管态对象
public void demo(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
User user = new User (); //瞬时态对象 :没有唯一id ,没被session管理
user.setName("张三");
Serializable id = session.save(user); //持久态对象:有唯一id ,被session管理
transaction.commit();
session.close(); //session失效
System.out.println("姓名 :" + user.getName()); //脱管态对象:有唯一标识 ,没被 session 管理
}
四 、一级缓存
- Hibernate中的一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数,当执行一次查询操作的时候,执行第二次查询操作,先检查缓存中是否有数据,如果有数据就不查询数据库,直接从缓存中获取数据。
- 一级缓存只在session范围内有效,session关闭,一级缓存失败。
- session的缓存是由hibernate维护的,用户不能操作缓存内容;如果想操作缓存内容,必须通过hibernate提供的 evict / clear方法操作
- session.flush(); :让一级缓存与数据库同步;
- session.evict(); :清空一级缓存中指定的对象;
- session.clear(); :清空一级缓存中所有的对象;
备注 :不同的session不会共享缓存数据
五 、事务管理
1 、事务概述 :事务就是指作为单个逻辑工作单元执行的一组数据操作,这些操作要么必须全部成功,要么必须全部失败,以保证数据的一致性和完整性。
2 、事务属性 :
- 原子性 :在事务中的所有操作要么都发生,要么都不发生。
- 一致性 :事务执行前后 ,数据的完整性保持一致
- 隔离性 :事务执行过程中 ,不应该受到其它事务的干扰
- 持久性 :事务执行完成 ,数据持久化
如果不考虑隔离性,会引发的安全性问题如下:
- 脏读:一个事务读到另一个事务未提交的更新数据。
- 幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
- 不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。
- 第一类丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
- 第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一个事务已提交的更新数据。
4 、为了解决多个事务并发会引发的问题 ,应该设置事务的隔离级别 :
- Read Uncommitted:以上读的问题都有可能发生。隔离级别最差
- Read Committed:解决脏读,但幻读和不可重复读有可能发生 (一般用于Oracle)
- Repeatable Read:解决脏读和不可重复读,但幻读有可能发生 (一般用于MySQL)
- Serializable:解决所有读的问题,隔离级别最高, 但效率低
5 、在Hibernate的配置文件中设置隔离级别。每一种隔离级别对应着一个正整数。
- Read Uncommitted: 1
- Read Committed: 2
- Repeatable Read: 4
- Serializable: 8
在hibernate.cfg.xml中设置隔离级别代码如下:
<session-factory>
<!-- 设置事务的隔离级别 -->
<property name="hibernate.connection.isolation">4</property>
</session-factory>
6 、线程绑定的 session :保证业务逻辑层与数据持久层是同一个事务连接对象
(1) 、在hibernate核心配置文件中配置 Session对象与本地线程进行绑定。
<session-factory>
<!-- 配置当前线程绑定的Session -->
<property name="hibernate.current_session_context_class">thread</property>
</session-factory>
(2)、编写工具类 HibernateUtils
package czm.hibernate.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
public static final Configuration cfg;
public static final SessionFactory sfa;
static{
cfg = new Configuration().configure();
sfa = cfg.buildSessionFactory();
}
public static Session openSession(){
return sfa.openSession();
}
public static Session getCurrentSession(){ //在工具类里面获取与本地线程绑定的session。
return sfa.getCurrentSession();
}
}
(3) 、 编写测试类
public void testdemo(){
Session session = HibernateUtils.getCurrentSession(); //调用getCurrentSession()方法
Transaction ts = session.beginTransaction();
User user = new User ();
user.setName("张三");
Serializable name = session.save(user);
ts.commit();
//session.close(); //绑定了本地线程的session后,无需手动关闭session,线程关闭,session也就被关闭了
}
注意 :绑定了本地线程的session是不用我们自己去关闭的!!!当本地线程被关闭后,session也就自然而然的被关闭了。如果我们的sesson是没有与本地线程绑定的,是通过sessionFactory.openSession()获取的,那么就要我们自己手动进行关闭。