Hibernate第二天:Hibernate的一级缓存、其他的API
目录
Hibernate第二天:Hibernate的一级缓存、其他的API
1持久化类的编写规则
1.1什么是持久化类
持久化,将内存中的一个对象持久化到数据库的过程。Hibernate框架就是用来进行持久化的框架。
持久化类,一个Java对象与数据库表建立了映射关系,那么这个类在Hibernate中称为持久化类。
持久化类=Java类+映射文件。
1.2持久化类的编写规则
- 持久化类提供一个无参的构造方法 Hibernate底层需要使用反射生成实例。
- 属性需要私有,对私有属性提供public的set和get方法:Hibernate中获取,设置对象的值。
- 对持久化类提供一个唯一的标识OID与数据库主键对应:Java中通过对象的地址区是否是同一个对象,数据库表中通过主键绑定是否是同一个记录,在Hibernate中通过持久化类的OID的属性区分是否是同一个对象。
- 持久化类中的属性,尽量使用包装类类型:因为基本数据类型默认值是0,会有很多歧义,包装类默认值为NUll。
- 持久化类不要用使用final进行修饰:延迟加载本身是hibernate一个优化的手段,返回的是一个代理对象(javassist可以对没有实现接口的类产生代理-使用了非常底层的字节码增强技术,继承这个类进行代理),如果不能继承,不能产生代理对象,延迟加载就会失效,load()和get()方法一致。
2主键生成策略
2.1主键的分类
2.1.1自然主键
- 自然主键,主键的本身就是表中的一个字段(实体中的一个具体属性)。
- 创建一个人员表,人员就会有一个身份证号(唯一且不可重复),使用了身份证号作为主键,这种主键称为是自然主键。
2.1.2代理主键
- 代理主键,主键的本身不是表中必须的一个字段(不是实体中的某个具体属性)。
- 创建一个人员表,没有使用人员中的身份证号,用了一个与这个表不相关的字段ID,(PNO)。这种主键称为是代理主键。
在实际开发中,尽量使用代理主键,因为一旦主键参与到业务逻辑中,后期可能需要修改原代码。好的程序设计满足OCP原则,对程序的扩展是Open的,对修改源码是close的。
2.2主键生成策略
在实际开发中,一般不允许用户手动设置主键,一般将主键交给数据库,或者手动编写程序进行设置。在Hibernate中为了减少程序编写,提供了很多主键生成策略。
- Increment :hibernate中提供的自动增长机制,适用short,int,long类型党的主键,在单线程中使用。首先发送一条语句,select id from 表,然后让id+1作为下一条记录的主键。
- Identity:自动增长,适用short,int,long类型的主键,使用的是数据库底层的自动增长,适用于有自动增长机制的数据库(MySQL,MSSQL),Oracle没有自动增长。
- Sequence:自动增长,适用short,int,long类型的主键,采用序列方式(Oracle支持序列)。Mysql不能使用。
- UUID:适用于字符串类型,使用Hibernate中的随机方式生成字符串主键。
- Native:本地策略,可以在Identity和Sequence之间进行自动切换。
- Assigned:hibernate放弃外键管理,需要通过手动编写程序或者自己设置。
- Foreign:外部的,一对一的关联映射的情况下使用。(了解)
3持久化类的三种状态
3.1持久化类的三种状态
Hibernate是持久层框架,通过持久化类完成ORM操作,为了更好的管理持久化类,hIbernate把持久化类分层三种转态。
持久化类=Java类+映射
(1)瞬时态(Transient):没有唯一标识OID,没有被Session管理。
(2)持久态(Persistent):有唯一标识OID,被Session管理。
(持久化类的持久态对象,可以自动更新数据库)
(3)脱管态(Detached):有唯一标识OID,没有被Session管理。
3.2区分三种状态对象
@Test
// 三种状态区分
public void demo1() {
// 1通过工具类获取Session
Session session = HibernateUtils.openSession();
// 2开启事务
Transaction tx = session.beginTransaction();
// 3操作
// 向数据库插入一条记录
Customer Customer = new Customer(); // 1.瞬时态:没有位移标识OID(主键id),没有被session管理
Customer.setCust_name("小涵涵"); //
session.save(Customer); // 2.持久太:有唯一标识OID,被session管理
// 4事务提交 //
tx.commit(); //
// 5释放资源 //
session.close(); //
System.out.println(Customer.getCust_name()); // 3.托管态:有唯一标识OID,没有被session管理
}
3.3持久化类的状态转换(了解)
- 瞬时态:
获得:由new关键字创建
- 瞬时态转换为持久态:执行Session中的save()方法或saveOrUpdate0方法
- 瞬时态转换为脱管态:为瞬时态对象设置持久化标识OID
Customer customer = new Customer)://瞬时态customersetCust id(1); //脱管态
(2)持久态,
获得,通过Session的get()、load()方法或者Quey查询从数据库中获得.
- 持久态转换为瞬时态:执行Session中的delete()方法。
- 持久态转换为脱管态:执行Session的evict()、close()或clear()方法用于清除一级缓存中某个对象,clear()清除一级缓存 中的所有对象。
(3)脱管态,
获得,脱管态无法获得,只能由其他状态转换而来。
- 脱管态转换为持久态, 执行Session的update()、 saveOrUpdate()或lock()方法。
- 脱管态转换为瞬时态,将脱管态对象的持久化标识OID设置为null
3.4持久化类持久态对象自动更新数据库
@Test
/****
* 持久太的对象可以以自动更新数据库
*/
public void demo2() {
// 1通过工具类获取Session
Session session = HibernateUtils.openSession();
// 2开启事务
Transaction tx = session.beginTransaction();
// 3操作
/** 获取一个持久太对象了 **/
Customer Customer = (Customer) session.get(Customer.class, 1l);
Customer.setCust_name("王哈哈");
/** 此处可以省略一个update(如果此处数据和数据库一样,不执行Update()) **/
//session.update(Customer);
// 4事务提交
tx.commit();
// 5释放资源
session.close();
}
4Hibernate的一级缓存
4.1缓存概述
缓存是一种优化的方式,将一些数据放在内存,使用的时候直接从缓存中获取,不用通过数据源。
4.2Hibernate缓存
4.2.1Hibernate一级缓存
Hibernate一级缓存又称为“Session的缓存”。
Session内置不能被卸载,Session的缓存是事务范围的缓存(Session对象的生命周期通常对应一个数据库事务或者一个应用事务)。
一级缓存中,持久化类的每个实例都具有唯一的OID。
依赖于hibernate一级缓存【就是将数据库/硬盘文件中数据,放到缓存中(就是内存中一块空间),当再次使用时,可以直接从内存中获取数据信息】。
4.2.2证明Hibernate一级缓存存在
@Test
/****
* 证明一级缓存的存在
*/
public void demo3() {
// 1通过工具类获取Session
Session session = HibernateUtils.openSession();
// 2开启事务
Transaction tx = session.beginTransaction();
// 3操作
/**
* 分别用两次get执行两次查询id=1的客户,按道理执行两次get应发送两条sql语句,
* 且Customer1与Customer2不是同一个对象,
* 实际上只发送一次,且Customer1与Customer2是同一个对象
* 证明第二次查询使用的是一级缓存中的数据
**/
/** 数据库中第一本书的信息 **/
Customer Customer1 = (Customer) session.get(Customer.class, 1l);
System.out.println(Customer1);
/** 一级缓存中中第一本书的信息 **/
Customer Customer2 = (Customer) session.get(Customer.class, 1l);
System.out.println(Customer2);
System.out.println(Customer1==Customer2);
// 4事务提交
tx.commit();
// 5释放资源
session.close();
}
4.2.3Hibernate一级缓存结构
@Test
/****
* 深入了解持久态的对象可以以自动更新数据库
* 基于一级缓存:快照区
*/
public void demo4() {
// 1通过工具类获取Session
Session session = HibernateUtils.openSession();
// 2开启事务
Transaction tx = session.beginTransaction();
// 3操作
Customer Customer = (Customer) session.get(Customer.class, 1l);
/** 将信息存储于快照区 **/
Customer.setCust_name("张三丰");// 先将一级缓存区的【cust_name】修改为【"张三丰"】-----中间会进行一个比对查看是否一致,如果一致不更新(不会执行update语句),如果不一致----再将快照区中的【cust_name】修改为【"张三丰"】(执行update语句)。
// 4事务提交
tx.commit();
// 5释放资源
session.close();
}
5Hibernate的事务管理
5.1什么是事务
事务:指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
5.2事务的特性
1.原子性
(Atomic)(Atomicity)
事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
2.一致性
(Consistent)(Consistency)
事务在完成时,必须使所有的数据都保持一致状态。
3.隔离性
(Insulation)(Isolation)
由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。
4.持久性
(Duration)(Durability)
事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。
5.3如果不考虑隔离性,引发安全性问题
读的问题:
脏读:一个事务读到另一个事务未提交的数据。
不可重复读:一个事务读到另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致。
虚读:一个事务读到另一个事务已经提交的insert数据,导致在前一个事务多次查询结果不一致。
写问题(了解)
引发丢失更新。
5.3读问题的解决
设置事务的隔离级别
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
5.4Hibernate设置事务隔离级别
核心配置文件中加入:
<!-- 事务隔离级别
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>
5.5Hibernate解决Service的事务管理
改写工具类:
package top.yangxianyang.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* Hibernate的工具类
* @author yxy
*
*/
public class HibernateUtils {
public static final Configuration cfg;
public static final SessionFactory sf;
static{
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
/*
* 提供获得session的方法
*/
public static Session openSession(){
return sf.openSession();
}
/*
* 提供获得session的方法
*/
public static Session getCurrentSession(){
return sf.getCurrentSession();
}
}
核心文件配置:
<!-- 配置当前线程绑定的Session -->
<property name="hibernate.current_session_context_class">thread</property>
代码:
package top.yangxianyang.demo1;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import top.yangxianyang.utils.HibernateUtils;
/*
* Hibernate线程绑定Session
* @author yxy
*
*/
public class HibernateTest3 {
@Test
public void demo1(){
Session session=HibernateUtils.getCurrentSession();
Transaction tx=session.beginTransaction();
Customer Customer = new Customer();
Customer.setCust_name("涵涵");
session.save(Customer);
tx.commit();
}
}
6Hibernate的其他API
6.1Query
1 使用query对象,不需要写sql语句,但是写hql语句
(1)hql:hibernate query language,hibernate提供查询语言,这个hql语句和普通sql语句很相似
(2)hql和sql语句区别:
- 使用sql操作表和表字段
- 使用hql操作实体类和属性
2 查询所有hql语句:
(1)from 实体类名称
3 Query对象使用
(1)创建Query对象
(2)调用query对象里面的方法得到结果
@Test
//Query
public void demo1(){
Session session=HibernateUtils.getCurrentSession();
Transaction tx=session.beginTransaction();
//通过session获得Query接口
//String hql="from Customer";//简单查询
//条件查询
//String hql="from Customer where cust_name like ?";
//分页查询
String hql="from Customer";
Query query=session.createQuery(hql);
//设置条件
//query.setParameter(0, "张%");
//设置分页
query.setFirstResult(0);
query.setMaxResults(2);
List<Customer> list=query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
6.2Criteria
1使用这个对象时候,不需要写语句,直接调用方法实现,更加面向对象。
2 实现过程
(1)创建criteria对象
(2)调用对象里面的方法得到结果
@Test
//Criteria
public void demo2(){
Session session=HibernateUtils.getCurrentSession();
Transaction tx=session.beginTransaction();
//通过session获得Criteria对象
Criteria ct=session.createCriteria(Customer.class);
//条件查询
ct.add(Restrictions.like("cust_name", "张%"));
List<Customer> list=ct.list();
//分页
ct.setFirstResult(0);
ct.setMaxResults(2);
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
6.3SQLQuery
1 使用hibernate时候,调用底层sql实现
2 实现过程
(1)创建对象
(2)调用对象的方法得到结果
@Test
// 查询所有
public void demo6(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 接收SQL:
SQLQuery query = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
tx.commit();
session.close();
}
今天任务完成。
源码地址:
链接:https://pan.baidu.com/s/1rMQ9XBMIeu2O_VbNZBo3MQ 密码:0hgz