zoukankan      html  css  js  c++  java
  • Hibernate框架笔记02_主键生成策略_一级缓存_事务管理

    0. 结构图

    结构图

    1. 持久化类的编写规则

    1.1 持久化和持久化类

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

    1.2 持久化类的编写规则

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

    2. 主键生成策略

    2.1 主键的分类

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

    2.2 主键生成策略

    • 在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置。在Hibernate中为了减少程序的编写,提供了很多种的主键生成策略。
    • increment:Hibernate中提供的自动增长机制,适用short、int、long类型的主键。在单线程程序中使用。
      • 首先发送一条Sql语句:select max(id) from 表;,然后让id +1 作为下一条的记录的主键
    • identity:适用于short、int、long类型的主键,使用的是数据库底层的自动增长机制。适用于有自动增长机制的数据库(Mysql、MSSQL),但是Oracle没有自动增长。
    • sequence:适用于short、int、long类型的主键,采用的时序列的方式。Oracle支持序列,但Mysql不能使用sequence。
    • uuid: 适用于字符串类型主键。使用Hibernate中随机方式生成字符串主键。
    • native:本地策略,可以在identity和sequence之间进行自动切换。
    • assigned:hibernate放弃外键的管理,需要手动编写程序或者自己设置。
    • foreign:外部的。一对一的一种关联映射的情况下使用。(了解)

    3. 持久化类的三种状态【了解】

    3.1 持久化类的三种状态

    • Hibernate时持久层框架,通过持久化类完成ORM操作。Hibernate为了更好的管理持久化类,将持久化类分为三种状态。
    • 持久化类 = Java类 + 映射
      1. 瞬时态:这种对象没有唯一的标识OID,没有被session管理,称为瞬时态对象。
      2. 持久态:这种对象有唯一标识OID,被session管理,称为持久态对象。
        • 持久化类的持久态的对象,可以自动更新数据库
      3. 托管态:这种对象有唯一标识OID,没有被session管理,称为托管态对象。

    3.2区分三种持久化状态

    @Test
    	//三种状态的区分
    	public void demo1() {
    		Session session = HibernateUtils.openSession();
    		Transaction tx = session.beginTransaction();
    		
    		Customer customer = new Customer();	// 瞬时态对象:没有唯一标识OID,没有被session管理
    		customer.setCust_name("王晓东");
    		
    		Serializable id = session.save(customer); // 持久态对象:有唯一标识OID,被session管理
    		
    		tx.commit();
    		session.close();
    		
    		System.out.println("客户名称: " + customer.getCust_name()); // 托管态对象:有唯一标识OID,没有被session管理
    	}
    

    3.3 持久化的三种状态的转换

    3.3.1 持久态的三种状态转换图

    转换图

    3.3.2 瞬时态对象

    • 获得:
      • Customer customer = new Customer();
    • 状态转换
      • 瞬时---->持久
        • save(Obejct obj)、saveOrUpdate(Object obj);
      • 瞬时----->托管
        • customer.setCust_id(1);

    3.3.3 持久态

    • 获得
      • get()、load()、find()、iterate()
      • Customer customer = session.get(Customer.class,1L);
    • 状态转换
      • 持久----->瞬时
        • delete()
      • 持久----->托管
        • close()、clear()、evict(Object obj)

    3.3.4 托管态对象

    • 获得
      • Customer customer = new Customer();
      • customer.setCust_id(1L);
    • 状态转换
      • 托管---->持久
        • update()、 saveOrUpdate()
      • 托管----->瞬时
        • customer.setCust_id(null)

    3.3.5 持久态对象的特性

    • @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();
      	}
      

    4. Hibernate的一级缓存

    4.1 缓存概述

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

    4.2 hibernate的缓存

    • Hibernate框架中提供了很多优化手段,比如缓存、抓取策略。Hibernate中提供了两种缓存机制,一级缓存和二级缓存。
    • Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放互相管理的Java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配的OID值得对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同得OID值得对象,则会去数据库中查找相应得数据。当从数据中查询到到所需数据时,该数据信息也会放置到一级缓存中。Hibernate得一级缓存的作用就是减少对数据库的访问次数。
    • 再在Session接口的实现中包含了一系列的Java集合,这些Java集合构成了Session缓存。只要Session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。所以一级缓存也被称为是Session基本的缓存。
    • Hibernate的二级缓存是SessionFactory级别的缓存,需要配置的缓存。二级缓存已经被Redis取代,实际开发过程不会使用。
    • 一级缓存是自带的不可卸载的

    4.3 证明一级缓存的存在

    package com.itzhouq.hibernate.demo1;
    
    import java.io.Serializable;
    
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    import org.junit.Test;
    
    import com.itzhouq.hibernate.utils.HibernateUtils;
    
    public class Demo3 {
    	// 证明一级缓存的存在
    	@Test
    	public void test() {
    		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);
    		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();
    	}
    }
    

    4.4 一级缓存的结构

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

      一级缓存中的特殊区域

    5. Hibernate事务管理

    5.1 什么是事务

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

    5.2 事务的特性

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

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

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

    5.4 读问题的解决

    • 设置事务的隔离级别
      • Read uncommitted:以上读问题都会发生
      • Read committed:解决脏读,但是不可重复读和虚读有可能发生(Oracle)
      • Repeatable read:解决脏读和不可重复读,但是虚读有可能发生(Mysql)
      • Serlializable:解决所有读问题

    5.5 设置事务的隔离级别

    • 在主配置文件中添加以下配置

      <!-- 设置事务的隔离级别 -->
      		<property name="hibernate.connection.isolation">4</property>
      
    • 4为MySQL数据库的默认级别

    • 数字和隔离级别的对应关系

      • 1----------Read uncommitted isolation
      • 2----------Read committed isolation
      • 4----------Repeatable read isolation
      • 8----------Serializable isolation

    5.6 Hibernate解决Service事务管理

    • Service层的事务

      service事务

    • 代码和配置

      1. 改写工具类,添加getCurrentSession()订单

        package com.itzhouq.hibernate.utils;
        
        import org.hibernate.Session;
        import org.hibernate.SessionFactory;
        import org.hibernate.cfg.Configuration;
        
        /*
         * Hibernate的工具类
         */
        public class HibernateUtils {
        	public static final Configuration cfg;
        	public static final SessionFactory sf;
        	
        	static {
        		cfg = new Configuration().configure();
        		sf = cfg.buildSessionFactory();
        	}
        	
        	public static Session openSession() {
        		return sf.openSession();
        	}
        	
        	public static Session getCurrentSession() {
        		return sf.getCurrentSession();
        	}
        }
        
      2. 在主配置文件中配置当前线程绑定的Session

        <!-- 配置当前线程绑定的Session -->
        		<property name="hibernate.current_session_context_class">thread</property>
        
      3. 测试

        package com.itzhouq.hibernate.demo1;
        
        import org.hibernate.Session;
        import org.hibernate.Transaction;
        import org.junit.Test;
        
        import com.itzhouq.hibernate.utils.HibernateUtils;
        
        /*
         *  	测试当前线程绑定的Session
         */
        public class Demo4 {
        	@Test
        	public void test() {
        		Session session = HibernateUtils.getCurrentSession();
        		Transaction transaction = session.beginTransaction();
        		Customer customer = new Customer();
        		customer.setCust_name("王希");
        		session.save(customer);
        		
        		transaction.commit();
        		//session.close();//不需要关闭
        	}
        }
        
    • 注意:绑定线程的session不需要手动关闭。因为当前线程自动获得与当前线程绑定的Session,线程结束之后,自动关闭Sesson,不需要手动关闭。

    6. HIbernate的其他API

    6.1 Query

    • Query接口使用接收HQL,查询多个对象

      • HQL:Hibernate Query Language:HIbernate查询语言,这种语言与SQL的语法及其类似,面向对象的查询语言。
      • 代码
      package com.itzhouq.hibernate.demo1;
      
      import java.util.List;
      
      import org.hibernate.Query;
      import org.hibernate.Session;
      import org.hibernate.Transaction;
      import org.junit.Test;
      
      import com.itzhouq.hibernate.utils.HibernateUtils;
      
      /*
       * 	HIbernate的其他API
       */
      public class Demo5 {
      	
      	@Test	// Query
      	public void test() {
      		Session session = HibernateUtils.getCurrentSession();
      		Transaction transaction = session.beginTransaction();
      		
      		
      		// 通过Session获得Query接口
      		//简单查询
      		//String hql = "from Customer";
      		//条件查询
      		//String hql = "from Customer wehre cust_name like ?";
      		//分页查询
      		String hql = "from Customer";
      		Query query = session.createQuery(hql);
      		//设置条件
      		//query.setParameter(0, "王%");
      		//设置分页
      		query.setFirstResult(0);
      		query.setMaxResults(3);
      		
      		List<Customer> list = query.list();
      		for (Customer customer : list) {
      			System.out.println(customer);
      		}
      		
      		transaction.commit();
      	}
      }
      

    6.2 Criteria

    • 条件查询:Query By Criteria

      • 更加面向对象的一种查询方式
    • 代码

      @Test	// Criteria
      	public void test2() {
      		Session session = HibernateUtils.getCurrentSession();
      		Transaction transaction = session.beginTransaction();
      		//通过Session获得Criteria对象
      		Criteria criteria = session.createCriteria(Customer.class);
      		//List<Customer> list = criteria.list();
      		
      		//条件查询
      //		Criteria add = criteria.add(Restrictions.like("cust_name", "王%"));
      //		List<Customer> list = criteria.list();
      		
      		//分页查询
      		criteria.setFirstResult(0);
      		criteria.setMaxResults(2);
      		List<Customer> list = criteria.list();
      		
      		for (Customer customer : list) {
      			System.out.println(customer);
      		}
      		
      		transaction.commit();
      	}
      

    6.3 SQLQuery【了解】

    • SQLQuery用于接收SQL。特别复杂情况下使用SQL。
  • 相关阅读:
    JVM
    事务
    Spring中AutowireMode(自动装配模型)
    ImportAware应用
    spring中几个比较重要的扩展点
    动态代理在Spring中的应用
    基于ImportSelector模拟简单的Aop
    正则表达式分组(Grouping)
    正则表达式断言(Assertions)
    一个JSON解析器
  • 原文地址:https://www.cnblogs.com/itzhouq/p/hibernate02.html
Copyright © 2011-2022 走看看