美文网首页
Hibernate配置文件HQL、QBC查询详解(四)

Hibernate配置文件HQL、QBC查询详解(四)

作者: 程序猿峰岑 | 来源:发表于2022-06-23 00:03 被阅读0次

    HQL简介

    HQL(Hibernate Query Language)描写对象操作的一种查询语言,Hibernate特有HQL的语法和SQL语法基本一致,不同的是HQL是面向对象的查询,查询的是对象和对象中的属性,HQL的关键字不区分大小写,但类名和属性区分大小写

    语法示例
    • SELECT 别名/属性名/表达式
    • FROM 实体AS别名
    • WHERE 过滤条件
    • HAVING 分组后的结果的查询条件
    • ORDER BY 排序条件

    查询案例

    投影查询

    不能把结果封装成对象,如果强制转换会报java.lang.ClassCastException异常错误

     List<Object[]> list = (List<Object[]>) session.createQuery("select s.id,s.username from Student s").list();
            for (int i = 0; i < list.size(); i++) {
                Object[] objs = list.get(i);
                for (int j = 0; j < objs.length; j++) {
                    System.out.println("------------------");
                    Object obj = objs[j];
                    System.out.println(obj);
                }
            }
    
    排序查询(desc降序、asc升序)
      List<Object[]> list = (List<Object[]>) session.createQuery("select s.id,s.username from Student s order by s.id desc").list();
            for (int i = 0; i < list.size(); i++) {
                Object[] objs = list.get(i);
                for (int j = 0; j < objs.length; j++) {
                    System.out.println("------------------");
                    Object obj = objs[j];
                    System.out.println(obj);
                }
            }
    
    聚合函数和分组查询
    • 聚合函数,总记录数 注意返回的结果是long类型
    Query query = session.createQuery("select count(*) FROM Student");
            long count = (long) query.uniqueResult();
            System.out.println(count);
    
    • 平均数
       Query query = session.createQuery("select avg(s.id) FROM Student s");
            double avg = (double) query.uniqueResult();
            System.out.println(avg);
    
    • 分组
     Query query = session.createQuery("select o.customer,count(o) from Order o group by Customer having count (o) > 2");
            List<Object[]> list = query.list();
            for (int i = 0; i < list.size(); i++) {
                Object[] objs = list.get(i);
                System.out.println("-------------------------------");
                for (int j = 0; j < objs.length; j++) {
                    System.out.println(objs[j]);
                }
                System.out.println("-------------------------------");
            }
    
    image.png
    连接查询

    INNER JOIN 在表中存在至少一个匹配时,INNER JOIN关键字返回行 LEFT OUT JOIN 关键字会从左表(table-name)返回所有的行即便右表(table-name)中没有匹配的行
    RIGHT OUTER JOIN:关键字会在右表(table-name)返回所有的行,即使在左表(table-name)中没有匹配到行


    image.png
    隐式内连接,等效SQL隐式内连接
      Query query = session.createQuery("from Customer c,Order o where c = o.customer");
            List<Object[]> list = query.list();
            for (int i = 0; i < list.size(); i++) {
                Object[] objs = list.get(i);
                System.out.println("----------------------");
                for (int j = 0; j < objs.length; j++) {
                    Object obj = objs[j];
                    System.out.println(obj);
                }
    
            }
            System.out.println(query.list());
    
    内连接
     List<Object[]> list = session.createQuery("from Customer c inner join c.orders").list();
            for (int i = 0; i < list.size(); i++) {
                System.out.println("---------------------");
                Object[] objects = list.get(i);
                for (int j = 0; j < objects.length; j++) {
                    Object obj = objects[j];
                    System.out.println(obj);
                }
            }
    
    迫切内连接
            List<Customer> customers = session.createQuery("from Customer c inner join fetch c.orders").list();
            for (int i = 0; i < customers.size(); i++) {
                System.out.println("---------------");
                Customer customer = customers.get(i);
                if (customer.getOrders().size() == 0) {
                    System.out.println(customer);
                }else{
                    Iterator<Order> iterator = customer.getOrders().iterator();
                    while (iterator.hasNext()) {
                        Order order = iterator.next();
                        System.out.println(customer +":" + order);
                    }
                }
            }
    
    案例8,命名查询把HQL写在映射文件的query标签
    • HQL语句写在Java文件中,有时候不灵活,如果要修改语句,要重新编译项目打包
    • 我们可以在*hbm.xml中命名查询语句,然后Java会从hbm.xml取出hql语句,这样之后开发,可以直接找hbm.xml进行配置
      把HQL写在映射文件中比较灵活,HQL写入映射文件有两种方式
      第一种:写在类Class标签里面,HQL是局部【name赋值前面要加包名+类名】
      Customer.hbm.xml
    <class name="Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="name"></property>
            <set name="orders" inverse="false" cascade="save-update,delete" batch-size="2">
                <key column="customer_id"></key>
                <one-to-many class="Order"></one-to-many>
            </set>
            <query name="hql1">from Customer</query>
        </class>
    

    代码示例: 查询语句【包名+类名+查询name的赋值】

        Query query = session.getNamedQuery("com.zzx.hibernate.domain.Customer.hql1");
            List<Customer> list = query.list();
            for (int i = 0; i < list.size(); i++) {
                System.out.println("--------------");
                Iterator<Order> iterator = list.get(i).getOrders().iterator();
                while (iterator.hasNext()) {
                    Order order = iterator.next();
                    System.out.println(list.get(i) + ":" +order);
                }
            }
    

    第二种:写在hibernate-mapping的标签,HQL是全局的
    Customer.hbm.xml

    <hibernate-mapping package="com.zzx.hibernate.domain">
        <class name="Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="name"></property>
            <set name="orders" inverse="false" cascade="save-update,delete" batch-size="2">
                <key column="customer_id"></key>
                <one-to-many class="Order"></one-to-many>
            </set>
        </class>
        <query name="hql1">from Customer where name=?</query>
    </hibernate-mapping>
    

    代码示例:查询语句直接写入hbm.xml query标签name的赋值即可

        Query query = session.getNamedQuery("hql1");
        query.setParameter(0,"鲁智深");
        Customer customer = (Customer) query.uniqueResult();
        System.out.println(customer.getName()+":" + customer.getOrders());
    

    QBC查询

    关于QBC查询,Hibernate系列章节一有讲QBC查询链接

    离线查询

    Detached Criteria离线查询对象,不需要使用session就可以拼凑查询条件,一般使用在web层或service层拼凑,将此对象传递给DAO层,此时将与Session进行绑定执行查询

       DetachedCriteria dc = DetachedCriteria.forClass(Order.class);
            dc.add(Restrictions.ge("id",2));
            Criteria criteria = dc.getExecutableCriteria(session);
            List<Order> orders = criteria.list();
            for (Order order : orders) {
                System.out.println("-------------------");
                System.out.println(order);
            }
    

    Hibernate的常见配置

    整合C3P0连接池

    第一步导入C3P0 Jar包工程
    默认Hibernate提供的框架中有C3P0包
    第二步:配置C3P0 查找Hibernate.properties

            <property name="hibernate.c3p0.max_size">2</property>
            <property name="hibernate.c3p0.min_size">2</property>
            <property name="hibernate.c3p0.timeout">500</property>
            <property name="hibernate.c3p0.max_statements">100</property>
            <property name="hibernate.c3p0.idle_test_period">3000</property>
            <property name="hibernate.c3p0.acquire_increment">2</property>
            <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    
    事务的隔离级别
    • 原子性:整体【原子性是指事务包含的所有操作要么全部成功,要么全部失败】
    • 一致性:数据【一个事务执行之前和执行之后都必须处于一致性状态】
    • 隔离性:并发【对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到其他事务在并发的执行】
    • 持久性:结果【持久性是指一个事务一旦被提交了,要么对数据库中的数据的改变是永久性的】
    隔离问题
    • 脏读:一个事务读到另外一个事务未提交的内容【读取提交的内容】,在读隔离级别,所有事务都可以看到其他未提交事务的执行结果,本隔离级别很少用于实际应用,因为它的性能也比不了其他的级别
    • 不可重复读:一个事务读到另外一个已经提交的内容(insert)【读取提交内容】这个大多数数据库系统默认隔离级别(但不是MYSQL默认的)它满足了隔离的简单定义,一个事务只能看见已经提交事务所作的改变
    • 虚读(幻读):一个事务读到另外一个已经提交的事务的内容(update)这个MYSQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取的问题,幻读,简单的说,幻读指当用户读取某一些范围的数据行时,另一个事务又在该范围内插入一行新的行,当用户再读取该范围的数据行时,才会发现新的幻读行
    • Serializable (可串行化)
      这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读的问题,简言之,它是在每个读的数据行上加入共享锁,在这个级别,可能导致大量的超时现象和锁竞争
      read uncommitld 读未提交,存在三个问题
      read committed 读已提交,解决,脏读存在两个问题
      Serializable 串行化,单事务,没有问题
    Hibernate中设置隔离级别
    <property name="hibernate.connection.isolation">4</property>
    

    相关文章

      网友评论

          本文标题:Hibernate配置文件HQL、QBC查询详解(四)

          本文链接:https://www.haomeiwen.com/subject/obhyvrtx.html