热门IT资讯网

Hibernate入门三

发表于:2024-11-25 作者:热门IT资讯网编辑
编辑最后更新 2024年11月25日,使用Hibernate最大的目的就是对数据库进行crud操作。在讲解之前,我们需要了解持久化以及持久化对象的三种状态。什么是持久化持久化就是把内存中的数据永久的存储到数据库中什么是持久化类持久化类就是
    使用Hibernate最大的目的就是对数据库进行crud操作。在讲解之前,我们需要了解持久化以及持久化对象的三种状态。

什么是持久化

持久化就是把内存中的数据永久的存储到数据库中

什么是持久化类

持久化类就是Java类与数据库建立的一种映射关系,并把这个类称做持久化类。实际上,就是一张数据表中的字段与类中的属性字段相对象的类。

持久化类的编写规范

1.需要提供无参数的构造方法
  因为Hibernate通过反射机制生成类的实例
2.需要私有属性,并提供对应的get和set方法
  因为Hibernate底层会对获取到的数据惊醒封装
3.属性尽量使用包装类类型
   区分空和null
4.类中必须存在一个唯一标识 OID与表中的主键对应
   Hibernate利用这个这个唯一标识来区分内存中是否是同一个持久化类
5.不要使用final修饰类
  因为Hibernate有加载延迟机制,这个机制会产生代理对象。代理对象是通过字节 码增强技术来完成的,其实就是通过产生子类的方式,如果使用final修饰持久化类,这个机制就会失败。加载延迟机制是一种优化的手段。

Hibernate主键生成策略

主键的类型

  1. 自然主键
    把具有业务含义的字段作为主键,称为自然主键。比如,客户的姓名(必须保证姓名不重复,唯一,非空),这类主键往往会因为业务的改变重新设计表,造成数据库维护困难。
  2. 代理主键
    把具有非业务字段作为主键,称为代理主键。通常是ID,类型是整数类型(比字符串节省空间)
  3. Hibernate提供了几个内置主键生成策略
    1.increment:用于short int long类型。以自动增长的方式,每次增量是1。
    2.identity:采用底层数据库本身提供的主键生成标识,前提是数据库支持自动增长的类型。
    3.sequence:Hibernate根基底层序列生成标识符,前提是数据库支持序列。
    4.native:根据底层数据库生成能力来判断生成identity、sequence、hilo中的一种。适合跨数据库开发。
    5.uuid:采用128位uuid算法生成标识符
    6.assigned:由Java程序负责生成标识符。如果不指定id的generator属性,默认使用该属性。适合自然类型。

Hibernate持久化对象的三种状态

  1. 瞬时态
    也称为临时态,托管态,实例是new出来的。不存在唯一标识OID,也没有和Hibernate Session关联
  2. 托管态
    也称为离线态,游离态。当某个持久态状态的实例与session失去关联的时候就变成为托管态。但是,托管态对象仍然存在唯一 标识OID,与数据库中的数据存在关联,只不过托管态对象发生改变的时候,Hibernate无法检测到。
  3. 持久态
    对象存在OID,并且与Session关联。值得注意的是,持久态对象在是事务还没有提交之前变成持久态的。

下面通过列举例子来说明上述内容

@Test    public void demo() {        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();        Session session = sessionFactory.openSession();        Transaction transaction = session.beginTransaction();        // 瞬时态,此时没有OID,也没有与session关联        User user = new User();         user.setUsername("robin");        Serializable save = session.save(user); // 持久态        transaction.commit();        session.close();        sessionFactory.close();        // 托管态,此时session关闭,没有与session关联,但是有OID        System.out.println(user);      }

转换关系

瞬时态
1.瞬时态 -- 持久态
  调用save()或者saveOrUpdate()
2.瞬时态 -- 托管态
  为瞬时态添加 OID

持久态:可以从Session get() load()方法获取,或者Query对象等
1.持久态 -- 瞬时态
  session.delete()删除持久态化对象
2.持久态 -- 托管态
  session.evict()、clear()、close()方法。evict()用于清除一级缓存中的某一个对象,clear()用于清除一级缓存中的所有对象, close()关闭session,并且清除一级缓存。

托管态
1.托管套 -- 持久态
  执行update()、saveOrUpdate() lock()等
2,托管态 -- 瞬时态
  把对象的OID设置为null

持久态对象可以自动更新数据库

依赖Hibernateu一级缓存

@Test    public void demo() {        Session session = null;        Transaction transaction = null;        try {            session = HibernateUtil.getSession();            transaction = session.beginTransaction();            User user = session.get(User.class, 2);            user.setUsername("Robin");           // session.update(user); 这句话可以省略,因为持久态的对象会自动更新数据库            transaction.commit();        } catch (Exception e) {            transaction.rollback();        }    }}

Hibernate一级缓存

缓存是计算机为了提高读取速度而设计的。通常介于应用程序和永久性存储介质之间。提高应用的运行能力,通常是内存。

Hibernate缓存分为一级缓存和二级缓存(redis替代),一级缓存是Hibernate内置缓存,不能删除。

Hibernate一级缓存实际上就是session缓存。Session缓存是一个内存空间,存放相互管理的Java对象。在使用对象查找的时候,会使用OID在Hibernate一级缓存中进行查找,如果查找到了,就返回此对象,否则,就会去数据库查找与之相同OID的对象。

只要session实例没有结束生命周期,存放在它上面的缓存也不会消失。

    一级缓存的特点    当应用程序调用Session的save()、update、saveOrUpdate()的时候,Session缓存中没有相应的对象的时候,Hibernate会自动的从数据库中提取对应的数据加载到一级缓存中    当应用程序调用Session load()、get(),以及Query中的、list()、iterator()的时候,Hibernate首先会从以及缓存中寻找对象,如果存在则不需要去数据库中查找。,如果没有则从数据库中获取并加载到一级缓存中    当调用Session.close()的时候,session缓存会被清空。

测试一级缓存

观察控制台输出的SQL语句

@Test    public void demo() {        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();        Session session = sessionFactory.openSession();        Transaction transaction = session.beginTransaction();        /**         * 查询两次         */        /**         * 第一次执行你会查询数据库         * 第二次查询只会去缓存中寻找         */        User user = session.get(User.class, 1);        User user1 = session.get(User.class, 1);        transaction.commit();        session.close();        sessionFactory.close();    }

一级缓存内部结构

    Hibernate向一级缓存中存储数据的时候,会拷贝一份数据放在Hibernate快照区,当使用事务提交之后,会根据OID比较一级缓存中的数据和快照区中的数据是否一致,如果不一致,则执行更新操作,并且同步快照区的数据,否则则不执行任何操作。

Hibernate对事务的控制

  • 什么是事务?
    通常对数据库的操作过程中,一项事务会有一条或者多条SQL语句,只有当所有的语句正常执行的时候,所有的操作才会正常完成。如果中间出现异常现象,那么所有的语句执行都不成功。换句话说,对于一组操作,要么全部成功,要么全部失败。
  • 事务的四个基本特性
    原子性 一致性 隔离行 持久性
    原子性:对事务的操作,要不全部成功,要么全部失败。
    一致性:事务完成的时候,必须使所有的数据保持一致。
    隔离性:一个事务不能被另外一个事务干扰。
    持久性:一旦提交了事务,对数据库进行了操作,所有的操作就不可逆。永久性的被改变。
  • 事务并发引发的问题
    脏读 不可重复读 幻读(虚读)
    脏读:一个事务读取到另一个未提交事务的数据
    不可重复读:一个事务中读取到另外一个事务已提交的update数据,造成同一个事务中多次读读取数据不一致
    幻读:一个事务中读取到另外一个事务已提交的insert数据,造成同一个事务中多次读读取数据不一致
  • 事务的隔离级别
    读未提交(read uncommitted 1级):允许读取还未提交的数据,会造成脏读,不可重复读,幻读
    已提交读(read committed 2级):允许在事务并发时,读取已经提交的数据,可防止脏读
    可重复读(repeatable read 4级):对相同字段的多次读取结果是一样的,可以防止脏读,不可重复读
    幻读(serializable 8级):提供严格的事务隔离,可防止脏读,不可重复读,幻读

Hibernate事务管理

  • 设置事务隔离级别(在核心配置文件中配置)
    4
  • 在业务层处理事务的方法
    1.在业务层中获取session,把它传递给持久层
    2.使用ThreadLocal将业务层获取到的session绑定到当前线程中去。然后到业务层获取的时候获取当前线程的session.

      thread    sessionFactory.getCurrentSession()    可以不需要关闭session,线程结束之后会自动关闭    thread: Session对象的生命周期与本地线程绑定    jta:Session对象的生命周期与JTA事务绑定    managed:Hinernate委托程序来管理Session对象的生命周期

Hibernate其它的API

  • Query
  • Criteria
  • SQLQuery

    Query是面对对象的Hibernate查询操作。通过session.createQuery(),传递一个HQL语句,获取Query对象。

@Test    public void demo() {        Session session = null;        Transaction transaction = null;        try {            session = HibernateUtil.getSession();            transaction = session.beginTransaction();            /**             * 创建Query             * 调用对象的方法             */            Query query = session.createQuery("from User");            List list = query.list();            for (User user : list) {                System.out.println(user);            }            transaction.commit();        } catch (Exception e) {            transaction.rollback();        }    }

Criteria是一个完全面对对象,可扩展的条件查询API,它不需要考虑数据库底层的实现,以及SQL语句的编写。它是Hibernate核心查询对象,又称为OBC(Object By Criteria)

@Test    public void demo() {        Session session = null;        Transaction transaction = null;        try {            session = HibernateUtil.getSession();            transaction = session.beginTransaction();            /**             * Criteria             *  创建Criteria对象             *  调用方法             */            Criteria criteria = session.createCriteria(User.class);            List list = criteria.list();            for (User user : list) {                System.out.println(user);            }            transaction.commit();        } catch (Exception e) {            transaction.rollback();        }    }

SQLQuery用来接收SQL语句,需要我们手动封装数据

@Test    public void demo03() {        Session session = null;        Transaction transaction = null;        try {            session = HibernateUtil.getSession();            transaction = session.beginTransaction();            /**             * 对象             * 调用方法             */            String sql = "select * from `tb_user`";            SQLQuery sqlQuery = session.createSQLQuery(sql);            sqlQuery.addEntity(User.class);            List list = sqlQuery.list();//            List list = sqlQuery.list();//            for (Object[] user : list) {//                System.out.println(Arrays.toString(user));//            }            for (User user : list) {                System.out.println(user);            }            transaction.commit();        } catch (Exception e) {            transaction.rollback();        }    }
0