欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Hibernate

程序员文章站 2022-11-30 17:57:07
持久化类的编写规则什么是持久化类持久化:将内存中的一个对象持久化到数据库中的过程.Hibernate就是用来进行持久化的框架持久化类:一个Java对象与数据库的表建立了映射关系,那么这个类在Hibernate中称之为持久化类.(持久化类 = Java类 + 映射文件)编写规则1.对持久化类提供一个无参数的构造方法 — Hibernate需要使用凡是生成实例2.属性需要私有,对私有属性提供get和set方法 — Hibernate中获取,设置对象的值3. 对持久化类提供一个唯一标识OID与数...

持久化类的编写规则

什么是持久化类

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

编写规则

1.对持久化类提供一个无参数的构造方法 — Hibernate需要使用凡是生成实例
2.属性需要私有,对私有属性提供get和set方法 — Hibernate中获取,设置对象的值
3. 对持久化类提供一个唯一标识OID与数据库主键对应 — Java中通过对象的地址区分是否同一个对象,数据库中通过主键确定是否是同一个记录,而在Hibernate中通过持久化类的OID的属性区分是否是同一个对象
4. 持久化类中属性尽量使用包装类 — 因为基本数据类型默认是0,包装类默认值是null (int => Integer,long=>Long,double=>Double)
5. 持久化类不能使用final进行修饰 — 延迟加载本身是Hibernate一个优化的手段,返回的是一个代理对象(Javassist),如果不能继承,不能产生代理对象,延迟加载也就会失败,load方法和get方法将会一样.

主键生成策略

主键的分类

  • 自然主键:主键的本身就是表中的一个字段(实体中的一个具体的属性)
  • 代理主键:主键的本身不是表中必须的一个字段(不是实体中的某个具体属性)
    在实际开发中,尽量使用代理主键
    1.一旦自然主键参与业务逻辑中,后期有可能需要修改源码
    2.好的程序设计满足OPC原则,对程序的扩展是open的,对修改源码是close的

主键生成策略

在映射文件中配置

<id name="cust_id" column="cust_id">
	<generator class="native"/>
</id>
  • increment : Hibernate中提供的自动增长机制,适用short、int、long类型的主键,在单线程中使用 .(首先发送一条语句select max(id) from stu,然后将查到的id + 1作为下一条记录的主键)
  • identity : 适用short、int、long类型的主键.使用的是数据库的自动增长机制.适用于有自动增长机制数据库(MySQL、MSSQL),但是Oracle没有自动增长
  • sequence : 适用short、int、long类型的主键.采用序列的方式.(Oracle支持序列).但MySQL不能使用sequence
  • uuid : 适用于字符串类型主键.使用Hibernate中的随即方式生成字符串主键
  • native : 本地策略,可以在identity和sequence之间进行自动切换
  • assigned : Hibernate放弃外键的管理,需要通过手动编写程序或者用户自己设置.
  • foreign : 外部的,一对一的一种关联映射的情况下使用(了解)

持久化类的三种状态

三种状态

  • 瞬时态 : 没有唯一的标识OID,没有被session管理
  • 持久态 : 有唯一的标识OID,被session管理
  • 托管态 : 有唯一的标识OID,不被session管理
public void demo1() {
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		Customer customer = new Customer(); //瞬时态 : 没有唯一的标识OID,没有被session管理
		customer.setCust_name("张三");
		Serializable id = session.save(customer);//持久态 : 有唯一的标识OID,被session管理
		transaction.commit();
		session.close();
		System.out.println(customer.getCust_name());//托管态 : 有唯一的标识OID,不被session管理
	}

站在三种状态角度看saveOrUpdate()方法

public void demo2() {
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		
		/*当为瞬时态对象时执行save方法*/
		/*Customer customer = new Customer(); 
		customer.setCust_name("张三");
		session.saveOrUpdate(customer);*/
		
		/*当为托管态对象时执行update方法*/
		Customer customer = new Customer(); 
		customer.setCust_id(3l);
		customer.setCust_name("李四");
		session.saveOrUpdate(customer);

		transaction.commit();
		session.close();
	}

持久态对象特性 : 持久态对象自动更新数据库

	public void demo3() {
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		Customer customer = session.get(Customer.class, 3l);
		customer.setCust_name("王五");
		//不用执行update方法,持久态对象自动更新数据库
		//session.update(customer);
		transaction.commit();
		session.close();
	}

一级缓存

什么是缓存

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

Hibernate的一级缓存

  • Hibernate框架中提供了优化手段 : 缓存、抓取策略.
  • Hibernate中提供了两种缓存机制:一级缓存、二级缓存
  • Hibernate的一级缓存:称为是session级别的缓存,一级缓存生命周期与session一致(一级缓存是由Session中的一系列Java集合构成的).一级缓存是自带的不可卸载的.
  • Hibernate的二级缓存:时SessionFactory级别的缓存,需要配置,一般不用Hibernate中的二级缓存,一般用redis等

证明一级缓存的存在

public void demo4() {
		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);
		transaction.commit();
		session.close();
	}

一级缓存的特殊区域 : 快照区
Hibernate

事务管理

什么是事务

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

事务特性

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

不考虑隔离性,引发的安全问题

  • 读问题:
    1.脏读 : 一个事务读到另一个事务未提交的数据(因为另一个事务可能会回滚)
    2.不可重复读 : 一个事务读到另一个事务已经提交的,但是update数据,导致在前一个事务多次查询结果不一致
    3.虚读 : 一个事务读到另一个事务已经提交的,但是insert数据,导致在前一个事务多次查询结果不一致
  • 写问题:
    引发两类丢失更新(了解)

读问题的解决

  • 设置事务的隔离级别
    1.Read uncommitted : 以上读问题都会发生
    2.Read committed : 解决脏读,但是不可重复读和虚读有可能发生(Oracle一般用)
    3.Repeatable read : 解决脏读和不可重复读,但是虚读有可能发生(MySQL一般用)

    4.Serializable : 解决所有问题(不允许事务并发)

在Hibernate核心文件hibernate.cfg.xml中配置

<!-- 
	事务隔离级别
		1 -> Read uncommitted 
		2 -> Read committed 
		4 -> Repeatable read 
		8 -> Serializable 
-->
<property name="hibernate.connection.isolation">4</property>

Hibernate的事务管理:线程绑定的session

Hibernate

  • 必须保证连接对象是同一个
    1.向下传递
    2.使用ThreadLocal对象(将这个连接绑定到当前线程中,在DAO的方法中通过当前的线程获得连接)
  • Hibernate框架内部已经绑定好了ThreadLoacl
    在SessionFactory中提供了一个方法getCurrentSession();
    这个方法默认不能用,需要配置才能用
public static Session getCurrentSession() {
		return sf.getCurrentSession();
	}

在核心文件hibernate.cfg.xml中配置

<!-- 配置当前线程绑定的Session -->
<property name="hibernate.current_session_context_class">thread</property>
  • thread : 与当前线程绑定
  • jta : 跨服务器绑定,例:实现向Oracle与MySQL的操作在同一个事务中
  • managed : - - -

其他常用API

Query***

  • query接口用于接收HQL,查询多个对象
    HQL:Hibernate Query Language,Hibernate查询语言(面向对象的查询语言)
@Test
	/*
	 * Query
	 */
	public void demo4() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//简单查询
//		String hql = "from Customer";
//		Query query = session.createQuery(hql);
		//条件查询
//		String hql = "from Customer where cust_name like ?";
//		Query query = session.createQuery(hql);
//		query.setParameter(0, "王%");
		//分页查询
		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);
		}
		tx.commit();
	}

Criteria***

  • Criteria : QBC ==> Query By Criteria
    更加面向对象的一个查询方式
@Test
	/*
	 * Criteria
	 */
	public void demo5() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//简单查询
//		Criteria criteria = session.createCriteria(Customer.class);
		//条件查询
//		Criteria criteria = session.createCriteria(Customer.class);
//		criteria.add(Restrictions.like("cust_name", "张%"));
//		criteria.add(Restrictions.like("cust_name", "张",MatchMode.ANYWHERE));
		//分页查询
		Criteria criteria = session.createCriteria(Customer.class);
		criteria.setFirstResult(0);
		criteria.setMaxResults(3);
		List<Customer> list = criteria.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

SQLQuery

  • SQLQuery用于接收SQL,特别复杂情况下使用SQL(例如关联八九个表)

本文地址:https://blog.csdn.net/a1669820631/article/details/107296075