zoukankan      html  css  js  c++  java
  • hibernate day02

    本节内容

    1.实体类的编写规则

    2. hibernate主键生成策略

    3 实体类操作

    4 hibernate的一级缓存

    5 hibernate的事务操作

    6 hibernate其他的api(查询)

    一、实体类编写规则

    持久化类:hibernate是一个持久层的ORM映射框架,专注于数据的持久化工作。所谓的持久化,就是将内存中的数据永久性的存储到关系型数据库中。那么什么是持久化类:持久化类指的是一个java类与数据库表建立了映射关系,那么这个类称为持久化类。

    持久化类的编写规则:

    1.持久化类需要提供无参数的构造方法。因为hibernate底层需要使用反射生成类的实例

    2.持久类中的属性需要私有化,对私有属性提供get与set方法。因为在hibernate底层会将查询到的数据进行封装

    3.持久化类的属性尽量使用包装类的类型。因为基本类型和包装类型的默认值不同,包装类的类型语义更清晰而基本数据类型不容易描述。

    4.持久化类要有一个唯一标识OID与表的主键对应

    5.持久化类尽量不要使用final修饰.

    二、hibernate主键生成策略

    主键:

     自然主键:把具有业务含义的字段设置为主键,称为自然主键:比如用户信息表中有一个用户姓名,使用姓名作为主键。

     代理主键:把不具备业务含义的字段作为主键,称为代理主键,例如id,通常为整数类型。

     hibernate要求实体类里面有一个属性作为唯一值,对应表主键,主键可以不同生成策略

    hibernate提供了几个内置的主键生成策略

    三、实体类操作

    对实体类进行CRUD操作

    添加操作:

     使用session中的save方法:

    //        添加操作
             Shop shop = new Shop ();
             shop.setS_name ("面条");
             shop.setS_describe ("意大利面");
             shop.setS_stock (123);
             shop.setS_price (10.0);
    
             session.save (shop);

    根据id查询:

    //         第一个参数:实体类的class  第二个参数:id值
             Shop shop1 = session.get (Shop.class,1);

    修改操作:

    1.首先根据id查询,然后修改

    //         修改操作
    //         第一个参数:实体类的class  第二个参数:id值
             Shop shop1 = session.get (Shop.class,1);
    //         修改查询到的数据
             shop1.setS_name ("披萨");
    //         进行修改:到shop1对象中找到id根据id进行修改
             session.update (shop1);

    删除操作;

    先查询后删除:

    //      删除操作
            Shop shop2 = session.get (Shop.class,1);
    
             session.delete (shop2);

    实体类对象状态:

    hibernate为了更好的来管理持久化类,特将持久化类分为了三中状态:瞬时态、持久态、脱管态。

    1.瞬时态:

    瞬时态称为:临时态或者自由态,瞬时态的实例是由new命令创建的,开辟内存空间的对象,不存在主键值,没有与hibernate Session关联,在数据库也没有记录,与数据库没有关系。

    2.持久态

    持久态的对象存在id主键值,并且相关联的session没有关闭,在数据库中有对应的记录,没条记录只对应唯一的持久化对象,持久态对象是在事务没有提交之前变成的持久态。

    3.脱管态

    托管态也称为离线态或者游离态,当某个持久化状态的实例与session的关联被关闭时,就变成了托管态,托管态的对象存在id主键值,并与数据库的数据存在关联,但是没有了session关联。发生改变hibernate不能检测。

     四、Hibernate的一级缓存

    1.什么是缓存

      缓存是计算机领域非常通用的一个概念。它介于应用程序与永久性数据存储源(如磁盘文件或者数据库)之间,其作用就是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是从数据源存储中数据拷贝。缓存的物理介质通常是内存。

    hibernate的缓存分为一级缓存和二级缓存,hibernate的这两级缓存都位于持久化层,存储的都是数据库的备份。其中一级缓存为Hibernate的内置缓存,不能被卸载。

    2.什么是hibernate的一级缓存

    hibernate的一级缓存就是指Session缓存,Session缓存就是一块内存空间,用来存放相互管理的Java对象,在使用hibernate查询对象的时候,会首先使用对象属性的OID 值在,hibernate的一级缓存中进行查找,如果找到匹配的IOD值对象,就直接将该对象返回,不会再查询数据库,如果没有找到相同的OID值的对象,则会去数据库查询,当从数据库中查到后,将该数据信息保存到一级缓存中。hibernate的一级缓存的作用高就是为了减少对数据库的访问次数。

    hibernate一级缓存的特点:

      当应用程序调用Session接口中的save、update、saveOrUpdae时,如果缓存中没有相应的对象,Hibernate就会 自动把数据库查询的相应的对象保存到一级缓存中。

    当调用Session接口的load、get方法,一级Query中的list、iterator方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询的对象,再去数据库中查询对应的对象,并保存到一级缓存中。

    当调用session中的close方法时,Session缓存会被清空。

    测试一级缓存:

    //    测试一级缓存
        @Test
        public void test1(){
            //1.加载配置文件
            //自动在src下查找hibernate.cfg.xml文件
            Configuration configuration = new Configuration ().configure ();
    
    
            //2.创建一个SessionFactory
            SessionFactory sessionFactory = configuration.buildSessionFactory ();
    
            //3.创建一个session对象  session对象类似于connection
    
            Session session = sessionFactory.openSession ();
    
            //4.开启事务
            Transaction transaction = session.beginTransaction ();
    //       马上发送一条sql语句查询数据库,并将数据添加到一级缓存
            Shop shop1 = session.get (Shop.class,1);
    //没有发送SQL语句,从一级缓存中获取
            System.out.println (shop1);
            Shop shop2 = session.get (Shop.class,1);
            System.out.println (shop2);
    //  缓存缓存的是对象的地址
            System.out.println (shop1==shop2);
    
            transaction.commit ();
            session.close ();
    
    
        }

    运行结果:

    Hibernate: 
        select
            shop0_.s_id as s_id1_0_0_,
            shop0_.s_name as s_name2_0_0_,
            shop0_.s_describe as s_descri3_0_0_,
            shop0_.s_stock as s_stock4_0_0_,
            shop0_.s_price as s_price5_0_0_ 
        from
            shop shop0_ 
        where
            shop0_.s_id=?
    com.hibernate.pojo.Shop@72fe8a4f
    com.hibernate.pojo.Shop@72fe8a4f
    true

    从以上代码的运行结果上可以看出,执行第一次查询时,发送了一条sql语句,当执行第2次查询时,发现没有发送sql,直返返回了对象。第二次直接从缓存中获取的数据。

    我们知道hibernate的持久态对象可以自动更新数据库,其实就是依赖于一级缓存,那么一级缓存为什么可以去更新数据库,是因为一级缓存的一块特殊区域就是快照区

    一级缓存的内部结构(快照区)

    hibernate向一级缓存中存放数据时,同时会复制一份数据放入到Hibernate快照区中,当使用 commit方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照区中的对象是否一致

    五、hibernate的事务操作

    Hibernate是对JDBC的轻量级封装,其主要功能是操作数据库,在操作数据库过程中,经常会遇到事务处理的问题,那么我们接下来就学习Hibernate的事务管理。

    1.什么是事务

    事务:由一条或者多条操作数据库的SQL语句组成的一个不可分割的工作单元。当事务中的所有操作都正常完成时,整个事务才能被提交到数据库,如果有一项操作没有完成,则整个事务会被回滚。

    总结:一条或者一组sql语句要么全部执行成功,要么全部失败。

    2.事务的四大特性(ACID)

    原子性:(Atomic)表示将事务中所做的操作捆绑成一个不可分割的单元,即事务所进行的数据修改等操作。要么全部执行,要么全部不执行。

    一致性:(Consistency):表示事务完成时,必须使所有的数据都保持一致状态。

    隔离性:(Isolation):指一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

    持久性:(Durability):持久性也称为永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。提交后的其他操作或者故障不会对其有任何影响。

    3.事务的并发问题:

    在实际使用事务的过程中,数据库数据要被多个用户所共同访问的,在多个事务同时使用相同的数据时,可能会发生并发的问题:

    脏读:一个事务读取到另一个事务未提交的数据。

    不可重复读:一个事务读到了另一个事务已经提交的update的数据,导致在同一个事务中的多次查询结果不一致。

    虚读/幻读:一个事务读取到了另一个事务已经提交的insert的数据,导致在同一个事务中的多次多次查询结果不一致。

    4.事务的隔离级别

    为了避免事务并发问题的发生,在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同。

    读未提交:(Read Uncommitted  1)一个事务在执行过程中,即可以访问其他事务未提交的新插入的数据,又可以访问未提交的修改数据。如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此数据。防止丢失更新

    已提交读:(Read Committed 2)一个事务在执行过程中,即可以访问其他事务成功提交,新插入的数据,又可以访问成功修改的数据,读取数据的事务允许其他事务继续访问该数据,但是未提交事务将会禁止其他事务访问该行数据,有效防止脏读

    可重复读:(Repeatable Read 4)一个事务在执行过程中,可以访问其他事务成功提交的数据,但是不可以访问成功修改的数据,读数据的事务将会禁止写事务(允许读),写事务则禁止任何其他事务,防止不可重复读和脏读

    序列化/串行化:(Serializable 8)提供严格的事务隔离。它要求事务序列化执行。事务只能一个接一个的执行,但不能并发执行。次隔离级别可有效防止脏读,不可重复读,或者幻读。

    事务隔离级别,是由数据库提供的,并不是所有数据库都支持四种隔离级别。

    在使用数据库时候,隔离级别越高,安全性越高,性能越低。实际开发中,不会选择最高或者最低隔离级别。一般选择默认的级别Oracle(Read Committed) mysql(Repeatable Read)

     

    5.hibernate中的事务管理

    在Hibernate中可以通过代码来操作管理事务,如通过:Transaction tx = session.beginTransaction 开启一个事务,持久化操作后,通过 tx.commit 提交事务,如果事务出现异常,通过 tx.rollback 操作来撤销事务(事务回滚)

    除了在代码中对事务开启,提交和回滚操作外,还可以在Hibernate的配置文件中对事务进行配置。配置文件中,可以设置事务的隔离级别,在hibernate.cfg.xml文件中的<session-factory>标签中进行。

        <!--设置事务的隔离级别-->
            <property name="hibernate.connection.isolation">4</property>

    设置事务的隔离级别,那么我们的事务一般不使用在dao层,而是使用在service层中,在一个service中调用多个dao中的方法来实现一个逻辑操作。

    那么我们需要保证的是在service中开启事务时,使用的Session对象和Dao中多个操作使用的是同一个session对象。

    有2种方式可以实现:

          1 可以在业务层获取到Session,并将Session作为参数传递给Dao

          2可以使用 ThreadLocal 将业务层获取到的,Session绑定到当前线程中,然后在dao层获取Session的时候,从当前线程中获取。

    一般我们都使用第二种,具体的实现不需要我们来完成,hibernate内部已经做好了,我们只需要完成一段配置即可。

    Hibernate5自身提供了3种管理Session对象的方法。

    Session对象的生命周期与本地线程绑定。

    Session对象的生命周期与JTA事务绑定

    Hibernate委托程序管理 Session对象的生命周期。

    在Hibernate的配置文件中,通过hibernate.current_session_context_class来指定Session的管理方式:

    thread:Session对象的生命周期与本地线程绑定

    jta:session对象的生命周期与JTA事务绑定

    managed:Hibernate委托程序管理Session对象的生命周期。

    在hibernate中配置:

      

        <property name="hibernate.current_session_context_class">thread</property>

    hibernate提供sessionFactory.getCurrentSession() 创建一个 session和ThreadLocal绑定方法。

    package com.hibernate.util;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    public class HibernateUtil {
    
       private static SessionFactory sessionFactory;
          static {
              Configuration configuration = new Configuration ().configure ();
              sessionFactory = configuration.buildSessionFactory ();
    
          }
    
    
          //  获取当前线程绑定的会话
          public static Session getCurrentSession(){
    
    
              return sessionFactory.getCurrentSession ();
          }
    
    }

    hibernate中提供的这个与线程绑定的Session可以不用关闭,当线程执行结束后,就会自动关闭。

    六、Hibernate的其他API(查询)

     1.Query

       query代表面向对象的一个Hibernate查询操作,在hibernate中通常使用createQuery方法接收一个HQL语句,然后调用Query的list方法或者uniqueResult 方法执行查询。

    HQL:Hibernate Query Language 缩写 语法很像sql,但是他是完全面向对象的。sql操作的是表,HQL操作的是实体类。

    Hibernate中使用Query对象的步骤:

     1.获取Hibernate的session对象

     2.编写HQL语句

    3.调用createQuery创建查询对象

    4.如果HQL语句包含参数,则使用Query的setXXX方法设置参数

    5.调用Query的list方法或者uniqueResult 方法执行查询

    Session session = HibernateUtil.getCurrentSession ();
         Transaction transaction =  session.beginTransaction ();
         //查询所有
    //    Query query = session.createQuery ("from Shop");
    
    //   List<Shop> list =  query.list ();
    //
    //   list.forEach ( shop ->{
    //       System.out.println (shop.getS_name ());
    //   });
    //     //条件查询
    //     Query query1 = session.createQuery ("from Shop where s_id=?0");
    //
    //     query1.setParameter (0,1);
    
            //分页查询
            Query query = session.createQuery ("from Shop ");
    
            query.setFirstResult (1);
            query.setMaxResults (10);
    
    
    
    
    
        List<Shop> list = query.list ();
               list.forEach ( shop ->{
           System.out.println (shop.getS_name ());
       });
    
       transaction.commit ();
       session.close ();
    
    
        }

     2.Criteria

    Criteria是一个完全面向对象,可扩展的条件查询API,它不用考虑数据库底层的实现,以及SQL如何编写,它是Hibernate框架的核心查询对象,Criteria查询又称为“QBC”查询,他是Hibernate的另一种对象检索方式。由于它的API比较多,使用比较繁琐,所以在我们的开发中很少有人使用。

    使用步骤;

    1.创建查询:CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();

    2.设置查询语句信息 :criteriaBuilder.createQuery

    3.定义查询的From子句中能出现的类型,也可以用root.get()获取具体的某个属性:

    Root root = criteriaQuery.from (Shop.class);

    4.设置条件
      criteriaQuery.where
    5.创建Query对象并获取结果集list
    Query query =  session.createQuery (criteriaQuery);
    List<Shop> list = query.list ();

      @Test
        public void test4(){
            Session session = HibernateUtil.getCurrentSession ();
            Transaction transaction =  session.beginTransaction ();
            CriteriaBuilder criteriaBuilder =session.getCriteriaBuilder ();
            CriteriaQuery criteriaQuery = criteriaBuilder.createQuery (Shop.class);
    
            Root root = criteriaQuery.from (Shop.class);
            criteriaQuery.select (root);
    
            Path<Integer> path = root.get("s_id");
            Path<String> path1 =root.get ("s_name");
            //多条件查询
            Predicate predicate =criteriaBuilder.or (criteriaBuilder.equal (path,1),criteriaBuilder.equal (path1,"面条"));
            Predicate predicate1 =criteriaBuilder.or (criteriaBuilder.equal (path,2));
    
      // criteriaQuery.where (criteriaBuilder.equal (root.get ("s_id"),1),criteriaBuilder.equal (root.get ("s_name"),"面条"));
         criteriaQuery.where (predicate,predicate1);
    
         Query query =  session.createQuery (criteriaQuery);
         List<Shop> list = query.list ();
    
          list.forEach (shop ->{
              System.out.println (shop.getS_price ());
          });
    
        }

    3.SQLQuery

      SQLQuery这个就比较简单了,这个借口用于接收一个sql语句进行查询,然后调用list或者uniqueResult方法进行查询,但是sql语句不会直接封装到实体对象中,需要我们手动写代码才可以封装到实体中

        @Test
        public void test5(){
            Session session = HibernateUtil.getCurrentSession ();
            Transaction transaction =  session.beginTransaction ();
            //全查询
    //        String sql = "select * from shop";
    //        NativeQuery nativeQuery =session.createNativeQuery (sql,Shop.class);
    //
    //       List<Shop> list =  nativeQuery.getResultList ();
            //分页查询
            String sql = "select * from shop";
            NativeQuery nativeQuery = session.createNativeQuery (sql,Shop.class).setFirstResult (1)
                    .setMaxResults (10);
             List<Shop> list =  nativeQuery.getResultList ();
    
            
            transaction.commit ();
             list.forEach (shop ->{
                 System.out.println (shop.getS_name ());
             });
    
    
        }
  • 相关阅读:
    .netcore ioc 循环依赖问题及其相关思考之DispatchProxy
    通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪
    通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
    通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流
    通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权
    通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权百度版
    通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理
    通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
    通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
    VS 模板制作
  • 原文地址:https://www.cnblogs.com/wuzhilong/p/9953359.html
Copyright © 2011-2022 走看看