HIbernate中的HQL查询

Hibernate中的查询方式:
1,使用HQL:使用hibernate提供的面向对象的查询语句;
2,使用SQL:在hibernate中允许使用原生的SQL直接查询;
3,使用Criteria:hibernate提供的完全的面向对象的查询方式;

1,HQL:
HQL的学习方法HQL是面向对象的,但是HQL借鉴了SQL的语法结构,把SQL中关系模型的概念替换成面向对象的概念;

      //HQL是模型对象的,但是HQL借鉴了SQL的语法结构,把SQL中的关系模型的概念替换为面向对象的概念String hql = "SELECT e FROM Employee e WHERE e.name LIKE ? AND e.id BETWEEN ? AND ? ";List<Employee> ems = session.createQuery(hql).setParameter(0, "%a%").setParameter(1, 1L).setParameter(2, 10L).list();System.out.println(ems);

2,SQL:使用session.createQuery来创建基于SQL的查询,
查询出来的结果是Object[]的集合;

     //使用SQL查询到的结果集是Object[] 的列表(list)String sql = "select * from employee where name like ? and id between ? and ?";List<Object[]> ret = session.createSQLQuery(sql).setParameter(0, "%a%").setParameter(1, 1L).setParameter(2, 10L).list();for (int i = 0; i < ret.size(); i++) {System.out.println(Arrays.toString(ret.get(i)));}

3,Criteria:完全的面向对象的查询,所有的查询及条件的拼装都是通过Criteria对象的方法完成的(使用较少);

        //select * from employee//List<Employee> ret = session.createCriteria(Employee.class).list();List<Employee> ret = session.createCriteria(Employee.class).add(Restrictions.like("name", "a",MatchMode.ANYWHERE)).add(Restrictions.between("id", 1L, 10L)).list();System.out.println(ret);

选择:
1,HQL:面向对象的查询,查询出来的实体都是持久化的,hibernate为HQL做了很多的查询相关的优化,一般来说,对于简单的查询,我们都可以使用HQL(我们都是学过SQL的人)
2,SQL:对于性能要求较高的查询,我们一般直接使用SQL来完成查询;
3,Criteria:完全面向对象的,学习非常简单,对于某些简单的查询,可以直接使用Criteria,对于稍微复杂一点的查询,Criteria完全没有办法处理

分页查询:
1,分页需要些什么东西?总条数,每一页需要多少条数据,当前是第几页,当前页的数据;
2,查询当前页的数据,对于mysql来说,LIMIT ?,?
3,使用query.setFirstResult()方法来设置从第几条数据开始查询;
4,使用query.setMaxResult()方法来设置查询多少条数据;
5,setFristResult和setMaxResult对于SQL和Criteria的查询都有效;

     String hql = "select e from Employee e where e.name like ? and e.id between ? and ?";List<Employee> ems = session.createQuery(hql).setParameter(0, "%a%").setParameter(1, 1L).setParameter(2, 10L).setFirstResult((currentPage -1)*pageSize)//setFirstResult==limit的第一个参数,代表从第几条数据开始查询.setMaxResults(pageSize)//setMaxResults==limit的第二个参数,代表最大查询多少条数据.list();System.out.println(ems);

查询总条数:
但是使用这种方式非常的不方便,因为我们知道我们查询出来的结果就只有一行数据;

        String hql = "select count(e) from Employee e";//在count中写e比写e.id要好,因为hibernate可以自动根据映射文件找到Employee的主键列,并使用主键列来替换count的内容List<Long> count = session.createQuery(hql).list();System.out.println(count.get(0));

使用query.uniqueResult()方法;

        //使用uniqueResult,这个方法可以真正的去执行查询//注意,这个方法只能用在我们确定结果集只有一行数据的时候,如果查询结果多于一行,则报错//uniqueResult方法对HQL和Criteria都有效Long count = (Long) session.createQuery("select count(e) from Employee e").uniqueResult();System.out.println(count);

  

查询参数设置:
位置占位符:就是使用?号来代表查询参数,通过setParameter(index,object)来根据?的位置来设置参数的;
1,写HQL的时候很方便;
2,如果参数值不多,还是比较容易识别;
3,如果参数值过多,会造成索引不容易识别;如果调整参数位置,所有的设置参数的位置都要变;如果一个参数在多个条件中使用,必须重复设置;

名称占位符:
1,使用 :参数名称 格式来添加名称占位符;

      String hql = "select e from Employee e where e.name like :name and e.id between :low and :hi";List<Employee> ret = session.createQuery(hql).setParameter("name", "%a%").setParameter("low", 1L).setParameter("hi", 10L).list();System.out.println(ret);

2,使用setParamter(String name,object)这个方法为名称占位符添加参数;
3,可以为多个参数起相同名字的名称占位符,在设置参数的时候只需要设置一次值,就可以在所有的位置设置好参数;
4,使用名称占位符可以给参数传列表值进去,很容易的完成in等查询;但是使用位置占位不行(只能直接拼在HQL里面);

     String hql = "select e from Employee e where e.id in (:ids)";List<Employee> ret = session.createQuery(hql).setParameterList("ids", new Long[]{1L, 2L,3L}).list();System.out.println(ret);

3,可以通过setEntity方法直接给HQL设置一个实体对象的参数,hibernate会自动的根据实体的关系,创建好对应的SQL

     Department dept = new Department();dept.setId(1L);//在hibernate中可以直接给查询语句的参数设置一个实体对象(可以使用位置占位符或者名称占位符)String hql = "select e from Employee e where e.dept = ?";List<Employee> ret = session.createQuery(hql).setEntity(0, dept).list();System.out.println(ret);

  

查询结果:
1,查询一个实体对象;
  直接查询实体对象返回的是实体对象的列表;注意,这个列表中所有的对象都是持久化对象,所以如果查询的数据量过大,记得分页+及时清空一级缓存;
2,投影查询;
  1,查询一个简单属性;

      //查询一个简单属性,返回该属性类型的list集合List<String> ret = session.createQuery("select e.name from Employee e").list();System.out.println(ret);//如果查询的属性是一个实体对象,返回这个实体对象的列表//这个列表里的所有对象也都是持久化对象//使用属性的导航查询(e.dept),此处使用join来连接查询List<Department> dept = session.createQuery("select e.dept from Employee e").list();System.out.println(dept);//查询多个简单属性,返回Object[]类型的list集合List<Object[]> ret = session.createQuery("select e.name,e.salary from Employee e").list();for (int i = 0; i < ret.size(); i++) {System.out.println(Arrays.toString(ret.get(i)));}//查询多个简单属性并且其中包含实体对象属性,返回Object[]类型的list集//查询出来的实体对象都是持久化的对象List<Object[]> ret = session.createQuery("select e.name,e.salary,e.dept from Employee e").list();for (int i = 0; i < ret.size(); i++) {System.out.println(Arrays.toString(ret.get(i)));}

hibernate查询结果的封装:
员工的id,员工的工资,员工的姓名,员工对应部门的编号和部门名称,员工所在的城市

     //返回一个Object[]类型的list集合(1)String hql = "select e.id,e.name,e.salary,e.dept.name,e.dept.address.city,e.dept.sn from Employee e";List<Object[]> ret = session.createQuery(hql).list();for (Object[] os : ret) {System.out.println(Arrays.toString(os));}//使用new list把每一行数据包装成list对象(2)String hql = "select new list(e.id,e.name,e.salary,e.dept.name,e.dept.address.city,e.dept.sn) from Employee e";List<List<Object>> ret = session.createQuery(hql).list();for (List<Object> os : ret){System.out.println(os);}//使用new map 把每一行数据包装成map对象(3)//1.默认情况下,把查询的属性的位置作为map的key//2.可以给查询的属性添加别名,别名作为map的key,查询结果作为map的valueString hql = "select new Map(e.id as eid,e.name as ename,e.salary as esalary,e.dept.name as dname,e.dept.address.city as dcity,e.dept.sn as dsn) from Employee e";List<Map<String, Object>> ret = session.createQuery(hql).list();for (Map<String, Object> os : ret){System.out.println(os);}//直接通过new VO对象来把结果包装成一个VO对象(4)//注意,VO对象需要一个构造方法,这个构造方法参数的顺序必须和查询的顺序匹配String hql = "select new EmployeeVO(e.id,e.name,e.salary,e.dept.name,e.dept.address.city,e.dept.sn) from Employee e";List<EmployeeVO> ret = session.createQuery(hql).list();for (EmployeeVO os : ret){System.out.println(os);}

  

NamedQuery查询:
在hibernate中,执行查询需要先将HQL先翻译成SQL,再执行SQL。如果HQL比较复杂翻译的效率是比较低的。如果一条HQL重复执行,会重复翻译。效率低下。
如果在代码不同的地方重复使用到了相同的HQL,需要在不同的地方反复重写HQL;
hibernate提供了NamedQuery方式,来稍微提高静态HQL语句的执行效率。和对HQL的统一管理
NamedQuery使用:
在实体映射文件中添加:
<!--为HQL起名为findCustomersByName,该HQL在hibernate启动的时候就会翻译成SQL -->
<query name="findCustomersByName">
<![CDATA[from Customer c where c.name like :name]]>
</query>
查询的时候使用:
//通过getNamedQuery,得到的就是已经翻译为SQL的query对象,只需要设置参数查询就行了
NamedQuery的使用限制:NamedQuery里面只能配置静态的HQL。

二级缓存概念:
1,生命周期为整个应用的缓存(二级缓存是sessionFactory上的缓存,能提供整个应用中所有的session使用。)
2,所有的get,load方法,总是先查一级缓存,再查二级缓存,如果都没有,在去数据库里面查询。
3,不是所有的对象都适合放到二级缓存中。(读>>>写)
4,二级缓存有一些性能的指标
  1),命中率(总的从二级缓存中取得的数量/总的取的数量)
  2),最大对象数量;
  3),最大空闲时间;
5,二级缓存实际上就是一个缓存,所以,hibernate并没有实现自己的二级缓存框架,而是用的开源的。
对象缓存策略:
  1),usage="read-only" :放到二级缓存里面的对象是只读(性能最高)
  2),usage="read-write":允许读写(对并发支持较好)
  3),usage="nonstrict-read-write":允许读写,但是在并发事务情况下会产生脏数据
  4),usage="transactional" :允许读写,并且支持全事务(只能在ApplicationServer环境下有用)
ehcache的配置:
<defaultCache>:默认的cache,相当于公用cache;
<cache>:自定义的cache;
共同的配置:
1,maxElementsInMemory:该缓存池放在内存中最大的缓存对象个数;
2,eternal:是否永久有效,如果设置为true,内存中对象永不过期;
3,timeToIdleSeconds:缓存对象最大空闲时间,单位:秒;
4,timeToLiveSeconds:缓存对象最大生存时间,单位:秒;
5,overflowToDisk:当内存中对象超过最大值,是否临时保存到磁盘;
6,maxElementsOnDisk:能保存到磁盘上最大对象数量;
7,diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒
8,memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。

默认策略是LRU(最近最少使用),可以设置为FIFO(先进先出)或是LFU(较少使用)
在默认的情况下,不同类型的对象都是放在defaultCache中的;
自定义二级缓存(把某一个对象放到某一个特定的二级缓存区域)
1,在hibernate.cfg.xml文件中的class-cache添加region; (添加二级缓存区域)
<class-cache usage="nonstrict-read-write" class="com._520it.hibernate.day4.query.Employee" region="EMPLOYEE"/>
2,在hibernate.cfg.xml文件中的hibernate.propertie属性上添加region_prefix (添加二级缓存前缀)
<property name="cache.region_prefix">hibernate</property>
3,在ehcache.xml中配置一个cache,名字为region_prefix.region (为自己的对象配置一个缓存区域 :前缀.缓存区域)
<cache name="hibernate.EMPLOYEE"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
二级缓存的操作
//得到二级缓存对象
Cache cache=sf.getCache();
//剔除一个实例
cache.evictEntity(User.class, 1L);
//剔除某种类型的所有实例
cache.evictEntityRegion(User.class);
//剔除所有二级缓存实例
cache.evictEntityRegions();

查询缓存:(使用非常少,因为可能带来非常大的负面性能影响)
1,默认情况下,hibernate没有打开查询缓存;
2,使用查询缓存:
  1),打开查询缓存:
  2),在查询的时候,使用Query对象的.setCacheable(true)方法;
3,查询缓存使用的条件:
  1,两条查询的HQL和查询参数必须完全一致;

Hibernate中的事务管理
使用Hibernate的锁机制主要是用来避免第一类丢失更新和第二类丢失更新;
Hibernate使用悲观锁其实就是使用数据库锁:
如果数据库不支持设置的锁机制,hibernate会使用该数据库提供的合适的锁机制来完成,而不会报错。

1,使用session.load(class,id,LockOptions);加悲观锁,相当于发送SELECT ... FOR UPDATE

2,使用session.get(class,id,LockOptions);加悲观锁,相当于发送SELECT ... FOR UPDATE

3,使用session.buildLockRequest(LockOptions).lock(entity);加悲观锁,相当于发送SELECT id FROM ... FOR UPDATE

4,使用query.setLockOptions(LockOptions);加悲观锁,相当于发送SELECT... FOR UPDATE

使用一个额外的版本控制字段来防止第二类丢失更新(乐观锁机制);

1,给表添加一个额外的数字类型字段version;

2,在insert一个对象的时候初始化version值为0;

3,在select的时候,查询出对象的版本号;

4,在update的时候,

  1),更新版本号,version = version+1;

  2),在update的where条件中带上当前更新对象的版本号 where .. and version = ?

  3),如果update返回影响条数>0,说明更新成功;

  4),如果update返回影响条数=0,说明更新的对象已经被其他事务更新或者删除,抛出异常,回滚当前事务;

在hibernate中使用乐观锁,推荐使用version方式;

1,给对象添加一个int version字段,最好设置属性为private;

2,在mapping文件中添加<version>元素即可;

事务并发5类问题(如果数据库没有做任何并发处理的情况下):

  第一类丢失更新:两个事务更新相同数据,如果一个事务提交,另一个事务回滚,第一个事务的更新会被回滚

  脏读:第二个事务查询到第一个事务未提交的更新数据,第二个事务根据该数据执行,但第一个事务回滚,第二个事务操作脏数据

  虚读:一个事务查询到了另一个事务已经提交的新数据,导致多次查询数据不一致

  不可重复读:一个事务查询到另一个事务已经修改的数据,导致多次查询数据不一致

  第二类丢失更新:多个事务同时读取相同数据,并完成各自的事务提交,导致最后一个事务提交会覆盖前面所有事务对数据的改变

一般情况,数据库都会处理一些事务并发的问题,数据库提供了不同的事务隔离级别来处理不同的事务并发问题,事务隔离级别定义如下:

READ_UNCOMMITED:允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读(相当于没有做任何事务隔离)

READ_COMMITTED:允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生(ORACLE默认级别)

REPEATABLE_READ:对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。(MYSQL默认级别)

SERIALIZABLE:完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。(ORACLE支持)

所以,数据库的隔离级别除了SERIALIZABLE,都不能处理第一类丢失更新和第二类丢失更新;

所以,数据库提供了锁机制来防止第一类丢失更新和第二类丢失更新;

转载于:https://www.cnblogs.com/Java0120/p/9867503.html

Hibernate-day04相关推荐

  1. Hibernate笔记辅助代码

    本博客为此篇博客的辅助博客,就是一些自己写的demo代码部分 目录 day03 工具类HibernateUtils(Main方法就可以帮助生成表结构) 简单配置和一对多 customer.java L ...

  2. java面试常见问题之Hibernate总结

    1  Hibernate的检索方式 Ø  导航对象图检索(根据已经加载的对象,导航到其他对象.) Ø  OID检索(按照对象的OID来检索对象.) Ø  HQL检索(使用面向对象的HQL查询语言.) ...

  3. Spring中启用Hibernate二级缓存步骤

    1.在applicationContext.xml配置文件中SessionFactory  bean中配置缓存 <!-- 配置会话工厂对象 --> <bean id="se ...

  4. ssh(Struts+spring+Hibernate)三大框架整合-简述

    ssh(Struts+spring+Hibernate)三大框架配合使用来开发项目,是目前javaee最流行的开发方式,必须掌握: 注意: 为了稳健起见,每加入一个框架,我们就需要测试一下,必须通过才 ...

  5. Hibernate框架第二天

    ### Hibernate的持久化类 ### ---------- **什么是持久化类** 1. 持久化类:就是一个Java类(咱们编写的JavaBean),这个Java类与表建立了映射关系就可以成为 ...

  6. Hibernate **关于hibernate4.3版本之后org.hibernate.service.ServiceRegistryBuilder被弃用**

    之前一直都是使用hibernate4.2.21的我,有一天突然没有使用本地的jar包而是让IDEA自动下载最新版本的hibernate5.2.2之后,发现有几个经常使用的方法报错了. //创建配置对象 ...

  7. 使用hibernate与mysql时数据不能插入的原因及解决办法

    1.背景 之前从没用过hibernate,因此在网上搜了一下hibernate快速入门方面的信息,最后我按照<Myeclipse Hibernate 快速入门 中文版>(CSDN,百度文库 ...

  8. IntelliJ IDEA下自动生成Hibernate映射文件以及实体类

    转自:https://blog.csdn.net/qq_34197553/article/details/77718925 1.构建项目并添加项目结构配置以及配置初始参数 1.1.如图将基本的架子搭建 ...

  9. Spring Hibernate JPA 联表查询 复杂查询

    (转自:http://www.cnblogs.com/jiangxiaoyaoblog/p/5635152.html) 今天刷网,才发现: 1)如果想用hibernate注解,是不是一定会用到jpa的 ...

  10. 5 -- Hibernate的基本用法 --2 1 Hibernate 下载和安装

    1. 下载Hibernate压缩包 2. 解压:文件结构 ⊙ documentation : 该路径下存放了Hibernate的相关文档,包括Hibernate的参考文档和API文档等. ⊙ lib ...

最新文章

  1. PgSQL · 特性分析 · full page write 机制
  2. 收集了100+论文的最新综述来了!基于深度学习的图像深度重建
  3. 我的心愿秀、大家也来秀(show)一下
  4. JSP网站开发基础总结《六》
  5. python issubclass 和 isinstance函数
  6. python前端开发之准备开发环境(建议收藏)
  7. 开源http协议库curl和wget的区别和使用
  8. LeetCode 537. 复数乘法
  9. C++基础与深度解析第三章:数组、vector与字符串
  10. android token机制_Android之window机制token验证
  11. GC root 解决了循环引用的垃圾回收问题
  12. Java泛型原理、类型擦除
  13. cass软件注记的字体类型和字体大小的问题
  14. 身份证OCR识别,居民二代身份证识别第三方数据接口
  15. Excel系列教程(1):如何自动填充单元格
  16. 使用ffmpeg的调色板对图片压缩
  17. [C/C++后端开发学习] 7 tcp服务器的epoll实现以及Reactor模型
  18. python在地图上画路线_使用Python和Perl绘制北京跑步地图
  19. 什么是美国次贷危机,看后你就明白了
  20. 【Maven】org.codehaus.plexus.component.repository.exception.ComponentLookupException

热门文章

  1. 《Docker容器:利用Kubernetes、Flannel、Cockpit和Atomic构建和部署》——2.2 容器式Linux系统的Docker配置...
  2. selenium一些基本语句
  3. 是什么浪费了我的时间
  4. 使用Query Object 模式 基于jpql实例
  5. 降Mail十八章(上)
  6. C#温故而知新学习系列之.NET框架高级特性—概述.NET框架中的反射(一)
  7. 怎样理解雷达的相参与非相参
  8. TI 实时操作系统SYS/BIOS使用总结
  9. java字符串 n换行符_java切割字符串中的回车应注意是\n\r不是\n
  10. java十六进制转二进制_Java进制都有哪些?