学习Hibernate框架笔记-第2天

持久化类的编写规则

一、持久化类的概述

1、什么是持久化类

  • 持久化:将内存中的一个对象持久化到数据库中的过程。
    • Hibernate框架就是用来进行持久化的框架。
  • 持久化类:一个Java对象与数据库中的表建立了映射关系,那么这个类在Hibernate中就被称为是持久化类。
    • 持久化类 = Java类 + 映射文件。

二、编写规则

1、持久化类的编写规则

  • 对持久化类提供一个无参的构造方法 : Hibernate底层需要使用反射生成实例。
  • 属性需要私有,对私有属性提供public的get和set方法 : Hibernate中获取,设置对象的值。
  • 对持久化类提供一个唯一标识符OID与数据库主键对应 : Java中通过对象确定是否是同一个对象,数据库中通过主键确定是否是同一个记录,在Hibernate中通过持久化类的OID的属性区分是否是同一个对象
  • 持久化类中的属性尽量使用包装类类型(Integer,Long,Double等):因为基本数据类型默认是0,那么0就会有很多歧义。而包装类类型默认值是null。
  • 持久化类不要使用final进行修饰 :延迟加载本身是Hibernate的一个优化手段,返回的是一个代理对象(javassist可以对没有实现接口的类产生代理——使用了非常底层的字节码增强技术,继承这个类进行代理)。如果使用final之后,则不能被继承,就不能产生代理对象,延迟加载也就失效了;此时,load方法与get方法一致。

主键生成策略

一、主键的分类

1、自然主键

  • 自然主键 : 主键的本身就是表中的一个字段(实体中的一个具体的属性)。
    • 创建一个人员表,每个人员都会有一个身份证号(唯一的不可重复的),并且使用了身份证号作为主键,这种主键被称为是自然主键。

2、代理主键

  • 代理主键 : 主键的本身不是表中必须的一个字段(不是实体中的某个具体的属性)。
    • 创建一个人员表,没有使用人员表中的身份证号作为主键,而是用了一个与这个表不相关的字段ID(如PNO)作为主键。这种主键被称为是代理主键。
  • 在实际开发中,要尽量使用代理主键
    • 因为一旦自然主键参与到业务逻辑中,后期就有可能需要修改源代码
    • 一个好的程序设计需要满足OCP原则 : 对程序的扩展是open的,对修改源码是close的

二、主键生成策略

1、Hibernate的主键生成策略

在实际开发过程中一般是不允许用户进行手动设置主键的,一般是将主键交给数据库、手动编写程序进行设置的。在Hibernate中为了减少程序的编写,提供了多种主键生成策略。
  • increament : hibernate中提供了自动增长机制,适用于short、int、long类型的主键,并且只能在单线程程序中使用。
    • 首先先发送一条语句:select max(id)from 表;然后让id+1作为下一条记录的主键,这个时候在多线程下就容易引发进程问题。
  • identity:适用于short、int、long类型的主键,它使用的是数据库底层的自动增长机制。注意:仅适用于有自动增长机制的数据库(如:MySQL、MSSQL),Oracle没有自动增长机制,故不适用
  • sequence:适用于short、int、long类型的主键,采用的是序列的方式。Oracle支持序列,但是像MySQL就不能使用sequence。
  • uuid:适用于字符串类型的主键,它使用的是hibernate中的随机方式生成字符串主键,类似java中的uuid。
  • native: 本地策略,可以认为它是在identity和sequence之间进行自动切换。就是说如果你把这个本地策略配置成MySQL,此时native就相当于identity;如果你把本地策略配置成Oracle,那么此时的native就当于是sequence。
  • assigned:hibernate放弃外键的管理,需要通过手动编写程序或者用户自己设置。
  • foreign:外部的,只有在一对一的一种关联映射的情况下使用。有一种情况就是,主键对应的情况,即我的主键也是你的主键,这个时候可以用,否则都不能用这个。

持久化类的三种状态

一、持久化类的三种状态

Hibernate是持久层框架,通过持久化类完成ORM操作。Hibernate为了更好的管理持久化类,将持久化类分成三种状态。

1、 瞬时态:transient
  • 这种对象没有唯一的标识OID,没有被session管理,称为瞬时态对象。
2、 持久态:persistent
  • 这种对象有唯一标识OID,被session管理,称为持久态。
    • 持久化类的持久态对象,可以自动更细你数据库。
3、 脱管态(游离态):detached
  • 这种对象有唯一标识OID,但是没有被session管理,称为脱管态对象。
4、区分三种状态对象:
@Test
// 区分三种状态对象
public void demo1() {
	Session session = HibernateUtils.openSession();
	Transaction transaction = session.beginTransaction();
		
	Customer customer = new Customer();			// 瞬时态对象:没有唯一标识OID,没有被session管理
	customer.setCust_name("小明");
	// 可以获取保存的这条数据的id
	Serializable id = session.save(customer);	// 持久态对象: 有唯一标识OID,被session管理,即有session操作
	
	session.get(Customer.class, id);
	
	transaction.commit();
	session.close();
	
	System.out.println("客户名:"+customer.getCust_name());	// 脱管态对象,有位移标识OID,但是没有被session管理
}

二、持久化类的状态转换(了解)

1、三种状态转换图

在这里插入图片描述

2、瞬时态对象

  • 瞬时态对象
    • 获得:直接创建即可,new一个
      • Customer customer = new Customer();
    • 状态转换:
      • 瞬时–>持久:调用session的save、saveOrUpdate方法
        • save(Object obj)、saveOrUpdate(Object obj);
      • 瞬时–>脱管:给创建的对象设置一个id
        • customer.setCust_id(1l);

3、持久态对象

  • 持久态对象
    • 获得:调用session的get、load、find、iterate方法即可
      • get()、load()、find()、iterate()
      • Customer customer = session.get(Customer.class,1l);
    • 状态转换
      • 持久–>瞬时:调用session的delete方法
        • delete();
      • 持久–>脱管:调用session的close、clear、evict方法
        • close()、clear()(清空所有)、evict(Obeject obj)(清空某一个);

4、托管态对象

  • 脱管态对象
    • 获得:没有直接获得的办法,但可以创建完之后设置一个id
      • Customer customer = new Customer();
      • customer.setCust_id(1l);
    • 状态转换
      • 脱管–>持久:调用session的update、saveOrUpdate方法
        • update(Object obj)、saveOrUpdate(Object obj);
      • 脱管–>瞬时:将id设置为null即可
        • customer.setCust_id(null);

三、持久态对象特性

1、持久化类持久态对象自动更新数据库

@Test
// 持久态对象自动更新数据库
public void demo2() {
	Session session = HibernateUtils.openSession();
	Transaction transaction = session.beginTransaction();
	
	// 获得持久态对象
	Customer customer = session.get(Customer.class, 1l);	// 持久态对象,有自动更新数据库的功能
	customer.setCust_name("李小宝");
	// session.update(customer);
	
	transaction.commit();
	session.close();
}
当设置的名字和原来的一样的时候,只进行查询,不进行更新,很智能。
原理:依赖了hibernate的一级缓存。

Hibernate的一级缓存

一、缓存的概述

1、什么是缓存

缓存:是一种优化的方式,将数据存入到内存中,使用的时候直接从缓存中获取,不用通过存储源。

二、Hibernate的缓存

1、Hibernate的一级缓存

Hibernate框架中提供了多种多样的优化手段:缓存、抓取策略。
Hiernate中提供了两种缓存机制:
  • 一级缓存
    • Hibernate的一级缓存称为是Session级别的缓存,以及缓存生命周期与session一致。即如果session创建了,则以及缓存也就存在了,session如果被销毁,那么一级缓存也就没有了,因为一级缓存是由session中的一系列Java集合构成的。
    • 一级缓存是自带的不可卸载的。
  • 二级缓存
    • Hibernate二级缓存是SessionFactory级别的缓存,需要配置的缓存,也就是说,二级缓存默认是不开启的,如果要使用二级缓存,则需要你自己去进行配置。
    • 现在企业中一般很少用二级缓存,基本上不用,替代的是redis。

2、证明一级缓存的存在

@Test
// 证明一级缓存的存在
public void demo1() {
	Session session = HibernateUtils.openSession();
	Transaction transaction = session.beginTransaction();
	
	/*Customer customer1 = session.get(Customer.class, 1l);	// 发送sql语句
	System.out.println(customer1);
	
	Customer customer2 = session.get(Customer.class, 1l);	// 不发送sql语句,是从缓存里获取,不去数据库查询
	System.out.println(customer2);
	
	System.out.println(customer1 == customer2);*/
	
	Customer customer = new Customer();
	customer.setCust_name("王峰");
	Serializable id = session.save(customer);
	
	Customer customer2 = session.get(Customer.class, id);	// 不发送sql语句
	System.out.println(customer2);
	
	transaction.commit();
	session.close();
}

三、Hibernate的一级缓存的内部结构

1、一级缓存中的特殊区域:快照区

@Test
// 一级缓存的快照区
public void demo2() {
	Session session = HibernateUtils.openSession();
	Transaction transaction = session.beginTransaction();
	
	Customer customer = session.get(Customer.class, 1l);	// 发送SQL语句,同时放到一级缓存中去
	customer.setCust_name("王大锤");
	
	transaction.commit();
	session.close();
}

在这里插入图片描述

Hibernate的事务管理

一、事务的回顾

1、什么是事务

  • 事务:事务指的是逻辑上的一组操作,组成这组操作的各个逻辑单元要么全部成功,要么全部失败。

2、事务特性

  • 原子性:代表事务不可分割;
  • 一致性:代表事务执行的前后,数据的完整性保持一致;
  • 隔离性:代表一个事务执行的过程中,不应该受到其他事务的干扰;
  • 持久性:代表事务执行完成后,数据就持久到数据库中。

3、如果不考虑隔离性,则会引发安全性问题

  • 读问题
    • 脏读:一个事务读到另一个事务未提交的数据;
    • 不可重复读:一个事务读到另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致;
    • 虚读:一个事务读到另一个事务已经提交的insert数据,导致在前一个事务多次查询结果不一致。
  • 写问题(了解)
    • 引发两类丢失更新

4、读问题的解决

  • 设置事务的隔离级别
    • Read uncommitted : 以上读问题都会发生;
    • Read committed : 解决脏读,但是不可重复读和虚读有可能发生;(Oracle采用)
    • Repeatable read : 解决脏读和不可重复读,但是虚读有可能发生;(MySQL采用)
    • Serializable : 解决所有读问题,不能有事务的并发。(效率最低,安全性最高,故基本不用)

二、Hibernate中设置事务隔离级别

1、Hibernate中设置事务的隔离级别

  • 1 --Read uncommitted : 以上读问题都会发生;
  • 2 --Read committed : 解决脏读,但是不可重复读和虚读有可能发生;(Oracle采用)
  • 4 --Repeatable read : 解决脏读和不可重复读,但是虚读有可能发生;(MySQL采用)
  • 8 --Serializable : 解决所有读问题。(效率最高,安全性最低,故基本不用)

在这里插入图片描述

三、Service层事务

1、Hibernate解决Service的事务管理

  • 改写工具类
      public class HibernateUtils {
    
      	// 定义session创建所需要的Configuration,SessionFactory,都定义成静态的
      	public static final Configuration cfg;
      	public static final SessionFactory sf;
      	
      	// 对上面的两个对象进行赋值,静态代码块
      	static{
      		cfg = new Configuration().configure();
      		sf = cfg.buildSessionFactory();
      	}
      	
      	// 对外提供一个方法,返回openSession()
      	public static Session openSession(){
      		return sf.openSession();
      	}
      	
      	public static Session getCurrentSession() {
      		return sf.getCurrentSession();
      	}
      }
    
  • 配置完成

在这里插入图片描述

Hibernate的其他API

一、Hibernate的其他API

1、Query

  • Query借口给用户接受HQL,查询多个对象;
    • HQL: Hibernate Query Language Hibernate查询语言,这种语言与SQL的语法极其类似,是面向对象的查询语言。
        @Test
       // Query
       public void demo1() {
       	Session session = HibernateUtils.getCurrentSession();
       	Transaction transaction = 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(3);
        	query.setMaxResults(3);
        	List<Customer> list = query.list();
        	for (Customer customer : list) {
        		System.out.println(customer);
        	}
        	
        	transaction.commit();
        }
      

2、Criteria

  • Creteria : QBC(Query By Criteria)
    • 更加面向对象的一种查询方式。
        @Test
        // Criteria
        public void demo2() {
        	Session session = HibernateUtils.getCurrentSession();
        	Transaction transaction = session.beginTransaction();
        
        	// 通过session获得Criteria的对象
        	/*Criteria criteria = session.createCriteria(Customer.class);
        	List<Customer> list = criteria.list();*/
        	// 条件查询
        	/*Criteria criteria = session.createCriteria(Customer.class);
        	criteria.add(Restrictions.like("cust_name", "李%"));*/
        	// 还有一种写法,like后面是三个参数,最后一个是%,END是在后面,START是在前面,ANYWHERE是恰后都有
        	//criteria.add(Restrictions.like("cust_name", "李", MatchMode.ANYWHERE));
        	// 分页查询
        	Criteria criteria = session.createCriteria(Customer.class);
        	criteria.setFirstResult(3);
        	criteria.setMaxResults(4);
        	List<Customer> list = criteria.list();
        	
        	for (Customer customer : list) {
        		System.out.println(customer);
        	}
        	
        	transaction.commit();
        }
      

3、SQLQuery

  • SQLQuery用于接收SQL。在sql语句特别复杂的时候使用SQLQuery,否则一般情况下使用前两种方法就可以了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值