JAVAEE框架学习——Hibernate——事务 查询API应用、查询优化

Hibernate 事物

Hibernate是对JDBC的轻量封装,主要功能是操作数据库。

Hibernate中的事物管理

在Hibernate中,可以通过API接口来操作管理事物。可以通过session.beginTransaction()开启一个事物,持久化操作后,通过commit()提交事物。如果事物异常,通过rollback()来进行事物的回滚。
除了在代码中对事物开启,提交和回滚操作外,还可以在Hibernate的配置文件中对事物进行配置。配置文件中,可以设置事物的隔离级别。


事物隔离级别
  • 在hibernate.cfg.xml文件中的<session-factory>标签元素中进行配置
 <!--配置数据库隔离级别
            0001 1 读未提交
            0010 2 读已提交
            0100 4 可重复读
            1000 8 串行
        -->
        <property name="hibernate.connection.isolation ">4</property>

基本点:在项目中如何管理事物:

在项目中,通过经验我们有一个基本的认识:
在业务开始之前打开事物,在业务执行之后提交事物,执行过程中如果出现异常,则回滚事物

  • 在dao层操作数据库的时候需要用到session对象,在service控制事物也是使用session对象完成,所以我们要确保dao层和service层使用的是同一个session对象
    注意1:调用getCurrentSession方法必须配合主配置中的一段配置
   <!--指定session与当前线程绑定-->
        <property name="current_session_context_class">thread</property>

注意2:通过getCurrentSession方法获得的Session对象,当事物提交时,session会自动关闭,不需要手动调用close关闭,session会自动被回收

Hibernate 查询API

HQL查询

HQL(Hibernate Query Language) 是面向对象的查询语言。使用的是类、对象和属性的概念。没有表和字段的概念。Hibernate提供的Query接口是专门的HQL查询接口,能够执行各种复杂的HQL查询语句。
由于HQL是面向对象的,所以不会出现和表名列名有关的语句。应该使用的是对象名 属性名

  • 完整的HQL语句
select...from...where...group...by...having...order by...asc/desc

当检索数据表中的所有记录时,查询语句中可以省略select关键字

获得Hibernate的Session对象
编写HQL语句
调用session.createQuery 创建查询对象
通过Query的setXxx设置参数
调用Query对象的list()或uniqueResult()执行查询

查询所有记录

  //编写HQL语句
String hql = "from cn.probuing.domain.Customer";
//根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//根据查询对象获得
List<Customer> list = query.list();//返回list

排序查询

  /**
     * 排序语法
     */
    @Test
    public void HQLSort(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        String hql = "from cn.probuing.domain.Customer order by cust_id desc";
        Query query = session.createQuery(hql);
        List<Customer> list = query.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }

根据条件进行查询

 /**
     * 条件查询
     */
    @Test
    public void HQLCondition(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
//        String hql = "from cn.probuing.domain.Customer order where cust_id=?";
        String hql2 = "from cn.probuing.domain.Customer order where cust_id=:id";//另一种写法
        Query query = session.createQuery(hql2);
        //设置占位符
//        query.setParameter(0,2);
        //另一种占位符写法
        query.setParameter("id",2);
        List<Customer> list = query.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }

分页查询

  /**
     * 分页查询
     */
    @Test
    public void HQLPage(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
//        String hql = "from cn.probuing.domain.Customer order where cust_id=?";
        String hql2 = "from cn.probuing.domain.Customer";//另一种写法
        Query query = session.createQuery(hql2);
        //表示从0条开始
        query.setFirstResult(0);
        //表示查找2条
        query.setMaxResults(2);
        List<Customer> list = query.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }

聚合函数

   /**
     * 聚合函数
     */
    @Test
    public void HQLCount() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
//        String hql = "from cn.probuing.domain.Customer order where cust_id=?";
        String hql2 = "select count(*) from cn.probuing.domain.Customer";
        //求和 指定列名
        String hql3 = "select sum(cust_id) from cn.probuing.domain.Customer";
        String hql4 = "select avg(cust_id) from cn.probuing.domain.Customer";
        String hql5 = "select max(cust_id) from cn.probuing.domain.Customer";
        String hql6 = "select min(cust_id) from cn.probuing.domain.Customer";
        Query query = session.createQuery(hql4);
        Number number = (Number) query.uniqueResult();
        System.out.println(number);
        tx.commit();
        session.close();
    }

投影查询

查询对象的某一个属性

 @Test
    public void testHQLDemo2() {
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction transaction = session.beginTransaction();


        //编写HQL语句
//        String hql = "from cn.probuing.domain.Customer where cust_id =? ";
        String hql = "from cn.probuing.domain.Customer where cust_id = :cust_id ";
        //根据HQL语句创建查询对象
        Query query = session.createQuery(hql);
        //设置参数 指定类型
//        query.setLong(0,1l);
        //设置参数 不指定参数
//        query.setParameter(0,1l);
        //根据参数名设置参数
        query.setParameter("cust_id", 1l);
        //根据查询对象获得
        Customer customer = (Customer) query.uniqueResult();//接收唯一的查询结果
        System.out.println(customer.toString());
        //提交事物,关闭资源
        transaction.commit();
        session.close();
    }

在指定条件时有以下几个方法:

  • 指定参数需要使用setXxx()指定类型
  • 不指定参数需要使用setParameter(占位符索引,值)
  • 根据名称指定条件值 setparameter(名称,值)

分页查询

hql语句中没有limit(?,?)这样的语句,需要使用API方法来实现分页的功能

  • setFirstResult() 设置起始的位置
  • setMaxResult() 设置最大的条数
   public void testHQLDemo3() {
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction transaction = session.beginTransaction();
        String hql = "from cn.probuing.domain.Customer ";
        //根据HQL语句创建查询对象
        Query query = session.createQuery(hql);
        //设置起始信息
        query.setFirstResult(0);
        //设置最大条数
        query.setMaxResults(2);
        //根据查询对象获得
        List<Customer> list = query.list();
        System.out.println(list.toString());
        //提交事物,关闭资源
        transaction.commit();
        session.close();
    }

Criteria查询

Criteria是一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何实现,以及SQL语句如何编写。Criteria查询又称为QBC查询。它是Hibernate的另一种对象检索方式
org.hibernate.criterion.Criterion是Hibernate提供的一个面向对象查询条件接口。一个单独的查询就是Criterion接口的一个实例。用于限制Criteria对象的查询。在Hibernate中Criterion对象的创建时通过Restriction工厂类完成

主要步骤:

(1) 获得Hibernate的Session对象
(2) 通过Session获得Criteria对象
(3) 使用Restriction的静态方法创建Criterion条件对象。Restrictions类中提供了一系列用于设定查询条件的静态方法
(4) 向Criteria对象中添加Criterion查询条件

基本查询

//获得session
        Session session = HibernateUtils.openSession();
        //通过session获得Criteria对象 参数表示指定查询所有的Customer对象
        Criteria criteria = session.createCriteria(Customer.class);
        //使用Restrictions对象进行查询 返回集合
        List<Customer> list = criteria.list();
        //返回单个结果
//        Customer customer = (Customer) criteria.uniqueResult();
        System.out.println(list.toString());

条件查询

 @Test
    public void testHQLDemo4() {
        //获得session
        Session session = HibernateUtils.openSession();
        //通过session获得Criteria对象 参数表示指定查询所有的Customer对象
        Criteria criteria = session.createCriteria(Customer.class);


        //调用add方法添加参数 => 查询cust_id 为1的Customer对象
        criteria.add(Restrictions.eq("cust_id", 1l));
        // 条件:>
        //使用Restrictions对象进行查询 返回集合
//        List<Customer> list = criteria.list();
        //返回单个结果
        Customer customer = (Customer) criteria.uniqueResult();


        System.out.println(customer.toString());
        session.close();

    }

对应条件API:

条件查询

分页查询

/**
     * Criteria 查询
     */
    @Test
    public void testHQLDemo4() {
        //获得session
        Session session = HibernateUtils.openSession();
        //通过session获得Criteria对象 参数表示指定查询所有的Customer对象
        Criteria criteria = session.createCriteria(Customer.class);
        //指定起始
        criteria.setFirstResult(0);
        criteria.setMaxResults(2);
//        使用Restrictions对象进行查询 返回集合
        List<Customer> list = criteria.list();
        System.out.println(list.toString());
        session.close();
    }

查询总记录数

  @Test
    public void testHQLDemo4() {
        //获得session
        Session session = HibernateUtils.openSession();
        //通过session获得Criteria对象 参数表示指定查询所有的Customer对象
        Criteria criteria = session.createCriteria(Customer.class);
        //设置查询的聚合函数
        criteria.setProjection(Projections.rowCount());
        Long result = (Long) criteria.uniqueResult();
        System.out.println(result);
        session.close();
    }

排序查询

  @Test
    public void BaseCriteriaOrder() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //操作数据
        //创建criteria
        Criteria criteria = session.createCriteria(Customer.class);
        criteria.addOrder(Order.asc("cust_id"));
//        criteria.addOrder(Order.desc("cust_id"));
        List list = criteria.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }

原生SQL查询

普通查询

  @Test
    public void sqlQuery() {
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //书写SQL语句
        String sql = "select * from cst_customer";
        //创建查询对象
        SQLQuery query = session.createSQLQuery(sql);
        //封装对象:将结果集指定封装对象
        query.addEntity(Customer.class);
        //查询结果 接收封装对象集合
//        List<Customer> list = query.list();
        //查询结果 未指定封装对象
        List<Object[]> list = query.list();
        System.out.println(list.toString());
        tx.commit();
        session.close();
    }

条件查询

 @Test
    public void sqlQuery() {
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //书写SQL语句
        String sql = "select * from cst_customer where cust_id = ?";

        //创建查询对象
        SQLQuery query = session.createSQLQuery(sql);
        //设置参数
        query.setParameter(0, 1);
        //指定封装对象
        query.addEntity(Customer.class);
        List<Customer> list = query.list();
        System.out.println(list.toString());
        tx.commit();
        session.close();
    }

分页查询

   public void sqlQuery() {
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //书写SQL语句
        String sql = "select * from cst_customer limit ?,? ";
        //创建查询对象
        SQLQuery query = session.createSQLQuery(sql);
        //设置条件参数
        query.setParameter(0, 0);
        query.setParameter(1,1);
        //封装对象:将结果集指定封装对象
        query.addEntity(Customer.class);
        //查询结果 接收封装对象集合
        List<Customer> list = query.list();
        //查询结果 未指定封装对象
//        List<Object[]> list = query.list();
        System.out.println(list.toString());
        tx.commit();
        session.close();
    }

离线查询

DetachedCriteria翻译为离线条件查询,它可以脱离session来使用的一种条件查询对象


传统查询
  • 传统的查询方式过于依赖session对象。减少参数的传递。


    离线查询

使用离线查询思路为:
在web层或者service层不依赖session创建查询对象Criteria。并设置好条件等相关参数
传递Criteria对象到Dao层
Dao层将离线的Criteria对象与session关联。关联后会将离线的Criteria对象转换为普通的Criteria对象。
通过普通的Criteria对象执行数据操作

实例代码

 @Test
    public void fun1() {
        //模拟service层或web层
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
        //拼装好条件
        detachedCriteria.add(Restrictions.idEq(2l));
        //dao层
        Session session = HibernateUtils.openSession();
        //离线对象关联session 关联session后 就会由离线的Criteria对象变为普通的Criteria对象
        Criteria c = detachedCriteria.getExecutableCriteria(session);
        //执行查询
        List<Customer> list = c.list();
        System.out.println(list);
    }

查询优化

类级别查询优化

延迟加载

类级别的延迟指的是查询某个对象的时候,是否采用有延迟。通常在<class>标签上配置lazy属性,lazy属性的默认值是true

  • lazy:true 加载时,不查询,使用时才查询
  • lazy:false 加载时立即查询
    <class name="Customer" table="cst_customer" lazy="true">
  • load方法 在执行时不发送任何sql语句,返回一个对象,使用该对象时,才执行查询
Customer c = session.load(Customer.class,2l);

原理解释

在加载时,返回的是代理对象 代理对象会在使用对象属性时,根据关联的session查询数据库,加载数据
注意 使用懒加载时要确保,调用属性加载数据时,session是打开的 还没有关闭。否则会抛出异常

关联级别查询优化

关联级别查询优化

关联级别就是指对象的关联属性,分为两种:集合级别的关联。对象级别的关联

集合级别的关联策略

  • lazy:延迟加载
    lazy属性:延迟加载
    true:默认值 延迟加载
    false:立即加载
    extra:极其懒惰 与懒加载效果基本一致,如果只获得集合的size,只查询集合的size(count语句)
  • fetch:抓取策略
    fetch属性:决定加载策略,使用什么类型的sql语句加载集合数据
    select:单表查询加载
    join:使用多表查询加载集合 此种情况下 lazy属性失效 相当于立即加载 多表数据会直接全部加载
    subselect:使用子查询加载集合


    集合属性策略

对象属性级别的关联策略

主要作用于<many-to-one>

  • lazy
    • false: 立即加载
    • proxy: 代理加载 由指定的代理决定加载策略
  • fetch
    • select: 使用单表查询
    • join: 使用多表查询


      关联属性策略

我们总结来说就是:fetch主要控制抓取关联对象的时候发送SQL语句的格式的lazy主要控制查询其关联对象的时候是否采用延迟加载的
为了提高效率:fetch的选择应该选择select lazy的取值应该选择true

批量抓取

批量抓取
 <!--
            batch-size:抓取集合的数量为3
        -->
        <set name="linkMens" inverse="true" batch-size="3">
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 本文包括:1、Hibernate 的查询方式2、HQL (Hibernate Query Language) 查询...
    廖少少阅读 2,649评论 0 15
  • hibernate(20170731) 1.导包:hibernate-distribution-3.5.6-Fin...
    潇湘雨smile阅读 531评论 0 0
  • Hibernate: 一个持久化框架 一个ORM框架 加载:根据特定的OID,把一个对象从数据库加载到内存中OID...
    JHMichael阅读 1,956评论 0 27
  • 每年的这个时间大家都在忙碌着筹办圣诞节。这是时候当圣诞树出来,所有的装饰品都被挂好后,整个圣诞节气氛完全呈现出来。...
    打豆豆阅读 614评论 0 2
  • ——春天的主旋律 世事无常,热爱本职工作的我却被迫换到了另一个岗位,丢失了自己的专业,也丢掉了曾经为...
    春天的主旋律阅读 302评论 3 4