Hibernate——Hibernate核心类和接口

Hibernate核心类和接口

Configuration类

  1. 负责管理Hibernate的配置信息
  2. 读取hibernate.cfg.xml文件
  3. 加载hibernate.cfg.xml配置文件中配置的驱动,url,用户名,密码,连接池
  4. 管理 *.hbm.xml对象关系文件

hibernate.cfg.xml文件

  1. 该文件用于指定各个参数,是hibernate的核心文件
  2. 默认放在src目录下,也可以放在别的目录下
  3. 指定连接数据库的驱动、用户名、密码、url、连接池
  4. 指定对象关系映射文件的位置
  5. 也可以使用hibernate.properties文件来代替该文件(推荐使用hibernate.cfg.xml)

对象关系映射文件(*.hbm.xml)

  1. 该文件主要作用是建立表和类的映射关系,是不可或缺的重要文件
  2. 一般放在其映射的类的同一个目录下,但不是必须的
  3. 命名方式一般是:类名.hbm.xml,但不是必须的
  4. 示意图如下:

这里写图片描述

SessionFactory(会话工厂)接口

  1. 缓存SQL语句和某些数据(Session级缓存)
  2. 在应用程序初始化的时候创建,是一个重量级的类(吃内存),一般用单例模式保证一个应用中只需要一个SessionFactory实例
  3. 如果某个应用访问多个数据库,则要创建多个会话工厂实例,一般是一个数据库对应一个会话工厂实例
  4. 通过SessionFactory接口可以获得Session(会话)实例

Session(会话)接口

  1. Session一个实例代表与数据库的一次操作(当然一次操作可以使CRUD组合)
  2. Session实例通过SessionFactory获取,用完需要关闭
  3. Session是线程不同步的(不安全),因此要保证在同一个线程中使用,可以用getCurrentSession()
  4. Session可以看做是持久化管理器,它是与持久化操作相关的接口

这里讨论一下通过SessionFactory获取Session的两个方法,openSession()getCurrentSession()的区别:

(1) 采用getCurrentSession()创建的Session会绑定到当前线程中,而采用openSession()创建的Session则不会

(2) 采用getCurrentSession()创建的Session在commit或rollback时会自动关闭,而采用openSession()创建的Session必须手动关闭。

(3) 如果是通过getCurrentSession()获取Session,进行查询也需要通过事务提交

(4) 如果希望使用getCurrentSession(),我们需要在hibernate.cfg.xml文件中加入如下配置:

(1)如果使用的是本地事务(jdbc事务)

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

(2)如果使用的是全局事务(jta事务)

<property name="current_session_context_class">jta</property>

本地事务:针对一个数据库的事务

全局事务:跨数据库的事务(比如银行的跨行转账)


openSession()和getCurrentSession()究竟使用哪一个?原则是:

  1. 如果需要在同一线程中,保证使用同一个Session,则使用getCurrentSession()

  2. 如果在一个线程中,需要使用不同的Session,则使用openSession()

这里我们可以改进我们的入门案例,增加HibernateUtil类,使用ThreadLocal(线程局部变量模式)将Session与线程关联起来。

ackage com.gavin.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    private static SessionFactory sessionFactory = null;

    // 用ThreadLocal模式(线程局部变量模式)管理Session
    private static ThreadLocal<Session> threadLocal = new ThreadLocal<>();

    private HibernateUtil(){}

    static{
        sessionFactory = new Configuration().configure().buildSessionFactory();
    }

    /**
     * 获取全新的Session
     * @return
     */
    public static Session openSession(){
        return sessionFactory.openSession();
    }

    /**
     * 获取和线程关联的session
     * @return
     */
    public static Session getCurrentSession(){
        Session session =  threadLocal.get();
        if (session == null) {
            session = sessionFactory.openSession();
            // 把session对象设置到threadLocal
            // 相当于该session已经和线程绑定
            threadLocal.set(session);
        }
        return session;
    }
}

openSession()和getCurrentSession()深入讨论

在SessionFactory启动的时候,Hibernate会根据配置创建相应的CurrentSessionContext,在getCurrentSession()被调用的时候,实际执行的方法是CurrentSessionContext.currentSession()。在currentSession执行时,如果当前Session为空,currentSession会调用SessionFactory的openSession()


Session接口的几个重要方法:

(1) 保存一个对象(记录):——save方法

(2) 删除一个对象(记录):——delete方法

(3) 查询一个对象(记录):——get/load方法

(4) 修改一个对象(记录):——update方法


get()和load()方法的区别:

(1) get()方法直接返回实体类,如果查不到数据则返回nullload()会返回一个实体代理对象(当前这个对象可以自动转化为实体对象),但当代理对象被调用时,如果数据不存在,就会抛出个org.hibernate.ObjectNotFoundException异常

(2) load()方法先到缓存(session缓存/二级缓存)中去查,如果没有则返回一个代理对象(不马上到DB中去找),等后面使用这个代理对象操作的时候,才到DB中查询,这就是我们常说的load在默认情况下支持延迟加载(lazy)

(3) get()先到缓存(session缓存/二级缓存)中去查,如果没有就到DB中去查(即马上发出sql语句)。总之,如果你确定DB中有这个对象就用load(),不确定就用get()(这样效率高)

(4) 通过修改配置文件我们可以取消懒加载。–> 在对象关系映射文件中的class结点配置:lazy=”false”

Hibernate缓存的原理

Hibernate缓存分两级。通过缓存可以有效减少对数据库的频繁查询,提高性能。

Transaction(事务)接口

这里简单说明一些什么是事务:事务简单的说,就是一组对数据库的操作集合,它们要么全部成功,要么全部失败,这个保证数据的一致性,事务具有原子性。

  1. Transaction是底层的事务实现中抽象出来的接口
  2. 可能是一个JDBC或者JTA事务,这样有利于Hibernate在不同执行环境的移植
  3. Hibernate要求显示的调用事务(如果仅仅是查询则可以不调用)

Query接口

Query接口类型的对象可以对数据库操作,它可以使用HQL,QBC,QBE和原生SQL对数据库操作。官方推荐使用HQL语句。

举例:通过用户名查询数据:

public static void queryByName(String name){
   Session session = HibernateUtil.getCurrentSession();
   Transaction transaction = null;
   try {
       transaction = session.beginTransaction();
       // 获取Query引用[这里的Employee不是指的表,而是domain类名]
       Query query = session.createQuery("from Employee where name = '" + name + "'");
       // 通过list方法获取结果,这个list会自动地将结果封装成对应的domain对象类型
       List<Employee> list = query.list();
       list.forEach(e -> System.out.println("e = " + e));
       transaction.commit();
   }catch (Exception e){
       if (transaction != null) {
           transaction.rollback();
       }
       throw new RuntimeException(e);
   }finally {
       if (session != null && session.isOpen()) {
           session.close();
       }
   }
}

Criteria接口

Criteria接口也可用于面向对象方式的查询,关于它的具体用法这里先不做介绍。简单看几个案例:

  1. 最简单案例,返回50条记录
Criteria crit = session.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();
  1. 限制结果集内容:
List cats = session.createCriteria(Cat.class).add(Restrictions.like("name", "Fritz%")).add(Restrictions.between("weight", "minWeight", "maxWeight")).lsit();
  1. 测试代码如下:
public static void testCriteria(){
    Session session = HibernateUtil.getCurrentSession();
    Transaction transaction = null;
    try {
        transaction = session.beginTransaction();
        Criteria criteria = session.createCriteria(Employee.class).setMaxResults(2).addOrder(Order.desc("id"));
        List<Employee> list = criteria.list();
        list.forEach(e -> System.out.println("e = " + e));
        transaction.commit();
    }catch (Exception e){
        if (transaction != null) {
            transaction.rollback();
        }
        throw new RuntimeException(e);
    }finally {
        if (session != null && session.isOpen()) {
            session.close();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/gggavin/article/details/79452469
今日推荐