一、持久化类
1.持久化类的概述
持久化:将内存中的一个对象持久化到数据库中的过程,Hibernate框架就是用来进行持久化的框架。
持久化类:一个java对象与数据库的表建立的映射关系,那个这个类在Hibernate中成为持久化类。
持久化类=java类+映射文件
2.持久化类的编写规则
(1)对持久化类提供一个无参构造方法
Hibernate底层需要使用反射生成实例。
(2)属性需要私有,对私有属性提供public的get和set方法
Hibernate需要获取、设置对象的值。
(3)对持久化类提供一个唯一标识OID与数据库主键对应
Java中通过对象的地址区分是否是同一个对象,数据库中通过主键确定是否是同一个记录,在Hibernate中通过持久化类的OID的属性区分是否是同一个对象。
(4)持久化类中尽量使用包装类型
基本数据类型的默认值是0,会产生很多歧义。包装类类型默认值是null。
(5)持久化类不要使用final修饰
延迟加载本身是Hibernate一个优化的手段,返回的是一个代理对象(javassist可以对没有实现接口的类产生代理----使用了非常底层的字节码增强技术,继承这个类进行代理)。如果不能被继承,就不能产生代理对象,延迟加载就会失效,load()方法和get()方法效果将一样。
二、主键
1.主键的分类
(1)自然主键
自然主键,主键的本身就是一个字段(实体中的一个具体的属性)
(2)代理主键
代理主键,主键的本身不是表中的任一一个字段
在实际开发中,应尽量使用代理主键。
一旦自然主键参与到业务逻辑中,后期有可能需要修改源代码。
好的程序设计应满足OCP原则,即对程序的拓展是open的,对修改源代码是close的。
2.主键的生成策略
在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置,在Hibernate中为了减少程序编写,提供了很多种主键的生成策略。
increment:用于为long、short或者int类型生成唯一标识。在单线程中使用。
sequence:用于为long、short或者int类型生成唯一标识。采用的是序列的方式(一些数据库比如Oracle支持,一些数据库比如MySQL不支持)
identity:用于为long、short或者int类型生成唯一标识。使用的是数据库底层的自动增强机制,适用于有自动增强机制的数据库(MySQL、MS SQL Server等)。
uuid:适用于字符串类型主键。使用Hibernate中的随机方式生成字符串主键。
native:本地策略,可以在identity和sequence中自动切换。
assigned:Hibernate放弃外键的管理,需要通过手动编写程序或者用户自己设置。
foreign:外部的,一对一的一种关联映射的情况下使用。
<!-- 建立类中的属性与表中的主键的联系 -->
<id name="cust_id" column="cust_id">
<generator class="native"/>
</id>
三、持久化类的三种状态
Hibernate是持久层框架,通过持久化类完成ORM操作。Hibernate为了更好的管理持久化类,将持久化类分为三种状态。
1.瞬时态(transient)
这种对象没有唯一的标识OID,没有被Session管理。数据库中没有对应的记录存在。
2.持久态(persistent)
这种对象有唯一标识OID,被Session管理。这时缓存中的对象与数据库是同步的。
注意:该状态可以自动更新数据库。
3.托管态(detached)
这种对象有唯一标识OID,没有被Session管理。数据库中有数据,缓存中没有数据,因为数据库中有数据,所以它是可以再被持久化的.
@Test
public void fun4() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//瞬时态对象,没有唯一标识OID,没有被Session管理
Customer customer=new Customer();
customer.setCust_name("朱茵");
//持久态对象,有唯一标识OID,被Session管理
Serializable id = session.save(customer);
Customer customer2 = session.get(Customer.class, id);
System.out.println(customer2);
transaction.commit();
session.close();
//托管态对象,有唯一标识OID,不被Session管理
System.out.println(customer.getCust_name());
}
四、Hibernate的缓存
1.什么是缓存
是一种优化的方式,将数据存入到内存中,使用的时候直接从内存中获取,不用通过存储源。
2.Hibernate的一级缓存
Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找不到的时候,才会到数据库中查找相应的数据。Hibernate的一级缓存就是减少对数据库的访问次数。
一级缓存的特点:
(1)当应用程序调用Session接口中的save()、update()、saveOrUpdate()时,如果Session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询出来的对象信息加入到一级缓存中。
(2)当调用Session接口的load()、get()方法一级Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果没有,再去数据库中查询相应对象,并添加到一级缓存中。
(3)当调用Session接口的close()方法时,Session缓存会被清空。
五、Hibernate的事务管理
1.什么是事务
事务(Transaction)是指逻辑上的一组操作,组成这组操作的各个逻辑单元要么全部成功,要么全部失败。
2.事务特性
原子性(Atomicity):事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
一致性(Consistency):事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。
隔离性(Isolation):隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。
持久性(Durability):一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。
3.事务隔离级别
(1)事务的并发读问题
脏读:读取到另一个事务未提交数据;
不可重复读:两次读取不一致;
幻读(虚读):读到另一事务已提交的数据。
(2)四大隔离级别
4个等级的事务隔离级别,在相同数据环境下,使用相同的输入,执行相同的工作,根据不同的隔离级别,可以导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力是不同的。
1.SERIALIZABLE(串行化)
不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的;
性能最差;
2.REPEATABLE READ(可重复读)(MySQL)
防止脏读和不可重复读,不能处理幻读问题
性能比SERIALIZABLE好
3.READ COMMITTED(读已提交数据)(Oracle)
防止脏读,没有处理不可重复读,也没有处理幻读;
性能比REPEATABLE READ好
4.READ UNCOMMITTED(读未提交数据)
可能出现任何事务并发问题
性能最好
4.Hibernate中设置事务隔离级别
在hibernate.cfg.xml文件中的<session-factory>标签中,配置如下信息:
<peoperty name="hibernate.connection.isolation">4</property>
该配置中的属性有如下值:
1-----Read uncommitted isolation
2-----Read committed isolation
4-----Repeatable read isolation
8----Serializable isolation
六、Hibernate线程绑定的Session
package cn.yfy.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
public static final Configuration configuration;
public static final SessionFactory sessionFactory;
static {
configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}
//得到一个Session对象
public static Session openSession() {
return sessionFactory.openSession();
}
//得到当前线程的Session对象
public static Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
}
若要使用SessionFactory的getCurrentSession()对象,还需要在hibernate.cfg.xml中配置如下信息:
<property name="hibernate.current_session_context_class">thread</property>
该配置中的属性有如下值:
thread-----对象的生命周期与本地线程绑定
jta-----对象的生命周期与JTA事务绑定
managed-----Hibernate委托程序来管理Session对象的生命周期
七、Hibernate的其他API
1.Query
Query接口用于接受HQL,查询多个对象。
HQL:Hibernate Query Language:Hibernate查询语言,面向对象。
@Test
public void fun2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 查询Customer关联的表中的所有数据
// String hql="from Customer";
/**
* 通过Session获得Query接口
* 条件查询
* 设置参数
*/
// String hql="from Customer where cust_name like ?";
// Query query = session.createQuery(hql);
// query.setParameter(0, "刘%");
/**
* 设置分页查询
* 设置参数,两个参数分别为sql语句中的limit x,y
*/
String hql = "from Customer";
Query query = session.createQuery(hql);
query.setFirstResult(0);
query.setMaxResults(3);
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
2.Criteria
OBC(Query By Criteria)
更加面向对象的一种查询方式。
@Test
public void fun6() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//通过Session获取Criteria对象
Criteria criteria = session.createCriteria(Customer.class);
//条件查询,条件为cust_name属性 模糊查询 "刘%"
criteria.add(Restrictions.like("cust_name","刘%"));
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
3.SQLQuery
SQLQuery用于接收SQL,一般在特别复杂的情况下使用SQLQuery。