Hibernate QBC查询
Hibernate day_02
- 持久化类以及编写规则.
持久化类就是我们说的实体类(符合 JavaBean 的规则)。
以后分包:entity(实体),pojo(简单的 Java 对象),domian(域对象)
1. 属性的声明必须使用私有的 private
2. 通过 get,set 方法获得设置和获得属性值
3. 属性的声明不能使用 final 关键字
4. [可选]建议实现一个序列接口 Serializable.如果需要将对象缓存到本地文件,必须加上
- 主键生成策略
所谓的主键生成策略,就是 Hibernate 提供了多种生成主键值的方法
常用的策略有:increment identity sequence native uuid assigned
- increment策略
不使用数据库的本地的增长策略,而是由程序(Hibernate框架)产生一个自增长的ID 值,赋予数据库.
<generator class="increment"></generator>
这种策略的好处:
由于ID自增长的值由程序生成,忽略了各种数据库ID自增长的差异,所以兼容性好
坏处:
因为每次增加一个ID值,都需要调用max()函数,效率不高。
应用场景:
- 是用在一些需要支持多种数据库的产品型项目。!!
- identity策略(只能用于有 ID 自增长类型的数据库 如 mysql sqlserver ,对不支持自增长策略的数据库 如 oracle db2)在配置前 一定要设置相应表格的 id 自增长
这种策略的好处:效率高。因为直接认为数据库就是使用ID自增长的!!
缺点:兼容性差,只支持有ID自增长的数据库。
- native 策略
根据数据库的本地策略生成主键值,如果数据库支持ID自增长策略的,使用ID自增长。如果数据库使用的是序列来生成ID值的,那么就是序列!!
--native效率高于increment,低于identity和sequence.由于不上不下的效率,使用不多!
- uuid 策略(注意 对应的字段必须为字符串)
所谓的uuid就是一个唯一的字符串。一般是32位。
那么什么时候使用UUID呢?
应用场景:
有几个开发人员同时开发一个项目。前提每个开发人员使用的都是自己电脑的数据库。
如果使用 ID 自增长作为 ID 列的值,就会导致每个人的数据的 ID 冲突。
但是如果大家使用 UUID。那么冲突的概率,极小
UUID 用于存储基础数据的表。所谓的基础数据,就是系统必须依赖的数据。
- assigned策略
HIbernate不使用任何的数据库策略,由调用方手工输入。
手工输入使用的概率不多。一般使用手工输入ID的策略用于一对一的情况
- sequence
序列策略:一般用于有序列的数据库。如果像MySQL数据库这种没有序列的数据库使用sequence策略,会使用的一个表来模拟序列。ID值生成规则存放在这个模拟表里面!
- 实体类状态转换(难点) 会获得持久态对象
实体类(持久化类)对象是有状态的。
为什么实体类对象会有状态?
答:由于 HIbernate 框架是一个先映射,后操作的框架。所谓的状态就是实体类的对象和数据库是否
有关联的情况。
男孩比作一个对象
女孩子比作一个数据库对象
Hibernate 的持久化类有三种状态:
1. 瞬时态(自由态):与数据库的表没有任何关联关系的实体对象
Customer customer=new Customer();
2. 持久态:正在与数据库保持连接的关系。
Customer customer=session.get(Customer.class,2L);
3. 游离态:曾经被 session 操作过,但 session 失效了。关闭,清除
- 瞬时态:
Customer c=new Customer();
- 持久态:
- 创建的对象被 sesssion 操作过了 ,操作不包括删除!!
@Test public void save(){ //1.获得数据库的操作对象,session Session session = HibernateUtils.getSession(); //2.Hibernate默认必须先启动事务,才可以操作(增删改) Transaction transaction = session.beginTransaction(); //3.封装一个有数据的实体类对象 Customer c=new Customer(); c.setCustName("阿里巴巴"); //4.保存 session.save(c); //5.提交 transaction.commit(); //这个时候 c,被 session 操作过了。就和数据库建立关系。 //6.关闭 session.close(); } |
- 游离态: 创建的对象被 sesssion 操作过了,session 关闭了。
瞬时态和游离态,这个两个状态都是和数据库没有关联了。他们区别是:是否曾经被操作过!!
对象状态转移图如下:
注意:根据状态转移图,我们学会如何获得持久态对象就可以(会使用get方法就可以了)了!!!
为什么需要了解如何获得持久态对象呢?
答:因为持久态对象是正在和数据库关联的状态的对象。所以支持以下数据库的操作。
- 快照机制支持
- 缓存机制的支持
- 导航查询的支持。
- 一级缓存
HIbernate 的持久态对象是支持一级缓存。所谓的一级缓存就是 Session 级别的缓存。
意思就是说,同一个 session 查询同样的数据,只查询一次数据库。如果出现同多次同样的查询(get/load)
直接返回缓存的数据
问题:如何清除一级缓存?
答:关闭session。和清空session。
. session.close() session.clear()
注意,close,clear,evit 清空缓存只是将持久态转成游离态,清空的是数据和数据库的关联,而不是清空数据。对象的属性和数据依然存在.
清除缓存的应用场景:秒杀,团购。遇到数据的数据不断更新,而查询的session又不能不断关闭。所以每次查询数据库表之前,需要清空清除一个缓存!!
- 快照机制
当对象变成持久态对象(调用get方法时候)的时候,和数据库表关联后。在 session 中会保存两份数据的副本
一份是缓存,一个是快照。
缓存的作用:用于提高查询的效率
快照的作用:用于更新数据,作对比使用。
快照的支持就是持久态对象直接可以通过修改属性更新数据,不需要 update 方法
这里修改持久态对象的属性 直接对该对象数据库中的信息进行更新.
@Test public void update() { // 1.获得数据库的操作对象,session Session session = HibernateUtils.getSession(); //2.更新需要启动事务 Transaction transaction = session.beginTransaction(); //获得持久态对象 Customer customer = session.get(Customer.class, 1L); //修改属性 customer.setCustName("alibaba"); //提交 transaction.commit(); // .关闭 session.close(); } |
执行流程图:
- 线程绑定(比进程更小的运行单位) web项目理解为多线程 每一次请求都是一个线程(Session绑定)
所谓的线程绑定,就是将session的对象绑定到当前的线程变量里面。这样确保了在同一条线程中使用的session对象是相同的!!!
为什么需要线程绑定呢?
答:如果不使用线程绑定,要处理同时对数据库两个操作的业务,需要通过参数传递的方式来确保session的唯一的。
为什么同时操作两个业务的需求,需要session唯一呢?
答:因为数据库事务处理的前提,必须是同一个连接(同一个session)
实现线程绑定的方式:
方式一:
- 使用HIbernate的内置实现
Hibernate框架内置支持将对象绑定到当前线程
<property name="hibernate.current_session_context_class">thread</property>
这个时候获得 session 的时候不能够使用 openSession() 方法 要使用 getCurrentSession()方法 获得当前Session 对象.
注意标注红色字体部分.
public class HibernateUtils { //通过一个静态变量,确保整个项目里面只有一个SessionFactory对象 //为什么建议一个项目只有一个SessionFactory对象? //答:如果一个项目有多个连接池,可以导致事务不同步!!! public static SessionFactory sessionFactory=HibernateUtils.createSessionFactory(); //获得会话工厂 private static SessionFactory createSessionFactory(){ //1.获得Configuration对象 Configuration config=new Configuration(); //2.读取配置文件,默认读取的就是classpath根目录的hibernate.cfg.xml config.configure(); //3.构建会话工厂 SessionFactory sessionFactory = config.buildSessionFactory(); return sessionFactory; } //获得会话,就是一个操作对象 public static Session getSession(){ //1.每次都需要在当前线程获得session对象 //注意:getCurrentSession必须要先配置线程绑定才可以使用 return sessionFactory.getCurrentSession(); } //测试 public static void main(String[] args) { System.out.println(HibernateUtils.getSession()); } } |
注意事项:
//注意:hibernate内置实现的线程绑定,已经实现随线程启动而启动,随线程关闭而关闭,所以session不能手工关闭
//session.close();
//注意:实现了内置线程绑定后,必须要先启动事务,才可以查询。所以增删改查都需要开启事务!!!
- 第二:使用自定义的方式实现 线程绑定.实现代码:
public class HibernateUtils { //通过一个静态变量,确保整个项目里面只有一个SessionFactory对象 //为什么建议一个项目只有一个SessionFactory对象? //答:如果一个项目有多个连接池,可以导致事务不同步!!! public static SessionFactory sessionFactory=HibernateUtils.createSessionFactory(); //声明一个线程变量,作用就是确保存在在线程变量里面的对象,同一条线程是相同的。 private static ThreadLocal<Session> threadLocal=new ThreadLocal<>(); //获得会话工厂 private static SessionFactory createSessionFactory(){ //1.获得Configuration对象 Configuration config=new Configuration(); //2.读取配置文件,默认读取的就是classpath根目录的hibernate.cfg.xml config.configure(); //3.构建会话工厂 SessionFactory sessionFactory = config.buildSessionFactory(); return sessionFactory; } //获得会话,就是一个操作对象 public static Session getSession(){ //判断,线程变量是否存在session if(threadLocal.get()==null){ Session session = sessionFactory.openSession(); //将session对象放在线程变量里面 threadLocal.set(session); } return threadLocal.get(); } //实现一个关闭的方法,在关闭session后,要移除线程变量里面的session对象 public static void closeSession(){ if(threadLocal.get()!=null){ Session session = threadLocal.get(); //关闭只是session和数据库断开了,但对象还在!! session.close(); //关闭session后,必须要将线程变量里面的session移除 threadLocal.remove(); } } |
- Hibernate查询 API: get(类字节码,id)
- QBC查询:Query By Criteria。(通过Criteria查询API查询)
- 示例代码(查询所有客户):
- QBC查询:Query By Criteria。(通过Criteria查询API查询)
//需求:查询所有的客户,使用Criteria实现 @Test public void findAll(){ //1.获得操作对象,session Session session = HibernateUtils.getSession(); //2.获得Criteria查询对象 Criteria criteria = session.createCriteria(Customer.class); //3.通过criteria对象,查询数据,返回多条数据,使用list List<Customer> customers = criteria.list(); for(Customer c:customers){ System.out.println(c.getCustName()); } session.close(); } |
- 模糊查询:
/** * 需求:查询客户名有"百"的客户 */ @Test public void findByName(){ //1.获得操作对象,session Session session = HibernateUtils.getSession(); //2.获得Criteria查询对象 Criteria criteria = session.createCriteria(Customer.class); //设置条件 criteria.add(Restrictions.like("custName", "%百%")); //3.通过criteria对象,查询数据,返回多条数据,使用list List<Customer> customers = criteria.list(); for(Customer c:customers){ System.out.println(c.getCustName()); } session.close(); } |
- 分页查询:
//需求:查询第 3 条开始,取 4 条件数据 @Test public void findByPage(){ //1.获得操作对象,session Session session = HibernateUtils.getSession(); //2.获得Criteria查询对象 Criteria criteria = session.createCriteria(Customer.class); //设置分页 //(1)设置开始的位置,开始位置从0开始,第三条数据的下标为2 criteria.setFirstResult(2); //(2)设置每页的记录数,每页返回的数据时4条,设置为4 criteria.setMaxResults(4); //3.通过criteria对象,查询数据,返回多条数据,使用list List<Customer> customers = criteria.list(); for(Customer c:customers){ System.out.println(c.getCustName()); |
- HQL查询(实际开发中较常用)
- Hql(hibernate query language)查询所有客户:
package com.bdqn.test; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.junit.Test; import com.bdqn.entity.Customer; import com.bdqn.utils.HibernateUtils; public class CustomerDAOTest { // 需求:查询所有的客户,使用hql实现 @Test public void findAll() { // 1.获得操作对象,session Session session = HibernateUtils.getSession(); // 2.获得hql查询对象 Query query = session.createQuery("from Customer"); // 3.通过criteria对象,查询数据,返回多条数据,使用list List<Customer> customers = query.list(); for (Customer c : customers) { System.out.println(c.getCustName()); } session.close(); } @Test public void findAll1() { // 1.获得操作对象,session Session session = HibernateUtils.getSession(); // 2.获得hql查询对象 // 注意,select返回不能是*,必须是一个属性或者对象的别名 Query query = session.createQuery("select c from Customer c"); // 3.通过criteria对象,查询数据,返回多条数据,使用list List<Customer> customers = query.list(); for (Customer c : customers) { System.out.println(c.getCustName()); } session.close(); } |
- Hql模糊查询
/** * 需求:查询客户名有"百"的客户 */ @Test public void findByName() { // 1.获得操作对象,session Session session = HibernateUtils.getSession(); // 2.获得Criteria查询对象 Query query = session.createQuery("from Customer c where c.custName like ?"); // 设置条件,注意,设置的下标0,为hql的第一个?的值 query.setString(0, "%百%"); // 3.通过criteria对象,查询数据,返回多条数据,使用list List<Customer> customers = query.list(); for (Customer c : customers) { System.out.println(c.getCustName()); } session.close(); } |
- Hql分页查询:
// 需求:查询第 3 条开始,取 4 条件数据 @Test public void findByPage() { // 1.获得操作对象,session Session session = HibernateUtils.getSession(); // 2.获得hql查询对象 Query query = session.createQuery("from Customer"); // 设置分页条件 // (1)设置开始位置,从0开始,第三条数据下标为2 query.setFirstResult(2); // (2)设置每页的记录数据,为4 query.setMaxResults(4); // 3.通过criteria对象,查询数据,返回多条数据,使用list List<Customer> customers = query.list(); for (Customer c : customers) { System.out.println(c.getCustName()); } session.close(); } |
- Hql查询总记录:
// 需求:统计记录数据 @Test public void count() { // 1.获得操作对象,session Session session = HibernateUtils.getSession(); // 2.获得hql查询对象 // 注意,select返回不能是*,必须是一个属性或者对象的别名 Query query = session.createQuery("select count(c) from Customer c"); // 3.返回一条数据,使用uniqueResult // 注意:如果返回的数据不确定,随便设置一个类型让它报错。通过错误信息分析返回的类型 Long uniqueResult = (Long) query.uniqueResult(); System.out.println(uniqueResult); session.close(); } |
- Hql:投影查询(查询部分属性) 了解
// 需求:查询客户的信息,返回custName和custSource @SuppressWarnings("unchecked") @Test public void findAll2() { // 1.获得操作对象,session Session session = HibernateUtils.getSession(); // 2.获得hql查询对象 // 注意,select返回不能是*,必须是一个属性或者对象的别名 Query query = session.createQuery("select c.custName,c.custSource from Customer c"); // 3.通过criteria对象,查询数据,返回多条数据,使用list List<Object[]> customers = query.list(); for (Object[] object : customers) { System.out.println("客户名:" + object[0] + ",客户来源:" + object[1]); } session.close(); } // 需求:查询客户的信息,返回custName和custSource,但是必须使用一个customer对象接收 /** * * 当查询的记录不是所有字段。而是指定的字段。 * 如果需要使用一个实体类接收。那么需要一个有参数的构造方法。我们将这种,有构造方法参数的查询,称为投影查询 */ @Test public void findAll3() { // 1.获得操作对象,session Session session = HibernateUtils.getSession(); // 2.获得hql查询对象 // 注意,select返回不能是*,必须是一个属性或者对象的别名 Query query = session.createQuery("select new Customer(c.custName,c.custSource) from Customer c"); // 3.通过criteria对象,查询数据,返回多条数据,使用list List<Customer> customers = query.list(); for (Customer c : customers) { System.out.println("客户名:" + c.getCustName() + ",客户来源:" + c.getCustSource()); } session.close(); } } |
- HQL操作
所谓的HQL操作,就是使用HQL实现数据库的删改。
- Hql删除:
注意:HQL是不支持增加的!!!
public class CustomerDAOTest { //需求:删除客户名有"百"的客户 @Test public void delete(){ //1.获得操作对象 Session session = HibernateUtils.getSession(); //2.操作需要开启事务 Transaction transaction = session.beginTransaction(); //3.获得hql操作对象 Query query = session.createQuery("delete from Customer c where c.custName like ?"); //4.设置删除的条件 query.setString(0, "%百%"); //5.执行hql,返回的是影响行数 int count = query.executeUpdate(); System.out.println(count); transaction.commit(); session.close(); } //需求:删除客户名有"百"的客户,使用命名参数实现 //所谓的命名参数,就是使用一个自定义的名字代替原来的? @Test public void delete1(){ //1.获得操作对象 Session session = HibernateUtils.getSession(); //2.操作需要开启事务 Transaction transaction = session.beginTransaction(); //3.获得hql操作对象 //注意:命名参数声明的时候,使用有 :(冒号的) Query query = session.createQuery("delete from Customer c where c.custName like :custName"); //4.设置删除的条件,设置条件的时候,命名参数是没有冒号的 query.setString("custName", "%小%"); //5.执行hql,返回的是影响行数 int count = query.executeUpdate(); System.out.println(count); transaction.commit(); session.close(); } } |
- Hql更新:
//需求:通过hql实现,更新客户名名,有“百”的客户来源,为互联网 @Test public void update(){ //1.获得操作对象 Session session = HibernateUtils.getSession(); //2.操作需要开启事务 Transaction transaction = session.beginTransaction(); //3.获得hql操作对象 //注意:命名参数声明的时候,使用有 :(冒号的) Query query = session.createQuery("update Customer c set c.custSource = ? where c.custName like ?"); //4.设置删除的条件,设置条件的时候,命名参数是没有冒号的 query.setString(0, "互联网"); query.setString(1, "%百%"); //5.执行hql,返回的是影响行数 int count = query.executeUpdate(); System.out.println(count); transaction.commit(); session.close(); } |
相对于SQL,使用HQL的好处是什么?
答:HQL操作的是对象,不是数据库的表。所以所有的数据库的语法是一样的。屏蔽了不同数据库的方言的差异!!!!
由于Criteria查找接口比较笨重,所以建议使用HQL。
- 总结
1今天学习了各种HIbernate的组件。
ID生成策略
- identity
必须要知道如何获得持久态对象。
- 通过查询可以获得 get(类字节码,id)
- 可以通过更新获得 update(object)
- 可以通过插入获得 save(object)
持久态对象有什么用
- 支持缓存
- 支持快照
- 支持导航查询
线程绑定:目的是为了不用传递参数,在同一条线程操作上,任何位置获得的session是相同的。
为什么有这个需求
原因因为事务处理必须是同一个session才可以实现!!!!!
三种实现线程绑定的方式,会内置配置方式和自定义配置方式。
查找的API。
使用Criteria查找接口。就是使用纯Java对象。查询数据库。(了解)
使用HQL查询接口,通过HQL实现数据库的操作(重点)
相对于SQL,使用HQL的好处是什么?
答:HQL操作的是对象,不是数据库的表。所以所有的数据库的语法是一样的。屏蔽了不同数据库的方言的差异!!!!
Hibernate QBC查询相关推荐
- Hibernate 学习笔记(二)—— Hibernate HQL查询和 QBC 查询
目录 一.Hibernate 的 HQL 查询 1.1.查询所有数据 1.2.条件查询 1.3.排序查询 1.4.统计查询 1.5.分页查询 1.6.投影查询 二.Hibernate 的 QBC 查询 ...
- Hibernate的集中查询方式 : hql查询,QBC查询和QBE查询
转载:http://blog.csdn.net/iijse/article/details/6161143 通常使用的Hibernate通常是三种:hql查询,QBC查询和QBE查询: 1.QBE( ...
- Hibernate学习之路(十三):Hibernate中的QBC查询和本地sql操作
什么是hibernate的QBC查询 QBC 查询就是通过使用 Hibernate 提供的 Query By Criteria API 来查询对象,这种 API 封装了 SQL 语句的动态拼装,对查询 ...
- Hibernate通常是三种:hql查询,QBC查询和QBE查询:
一:Hibernate QBC与HQL优缺点 QBC 全称:Query By Criteria HQL 全称:hibernate Query Language HQL优点:与sql相近,可读性好,功能 ...
- Hibernate中的QBC查询方式详解
Hibernate中的QBC查询方式详解 QBC:Query By Criteria,条件查询. 是一种更加面向对象化的查询的方式. 1.QBC简单查询 测试代码: package com.pipi. ...
- Hibernate框架--学习笔记(下):hibernate的查询方式、多表查询、检索策略、批量抓取
一.hibernate的查询方式: 主要有五种:对象导航查询:OID查询:hql查询:QBC查询:本地sql查询. 1.对象导航查询:根据id查询某个客户,再查询这个客户里面所有的联系人. 2.OID ...
- hibernate的查询方式
hibernate的查询方式常见的主要分为三种: HQL, QBC(Query By Criteria)查询, 以及使用原生SQL查询 HQL查询 • HQL(Hibernate Query Lang ...
- Hibernate各种查询方法
1 hibernate的查询方式 2 对象导航查询 3 hql查询 (1)查询所有 (2)条件查询 (3)排序查询 (4)分页查询 (5)投影查询 (6)聚集函数使用 4 qbc查询 (1)查询所有 ...
- hibernate QBC和QBE精讲与案列分析(上)
转载:http://blog.sina.com.cn/s/blog_7fff746d0101ese2.html 本章的主要内容包括: ● QBC数据检索 ● 连接查询 ● Hibernate的数据检索 ...
最新文章
- 全国大学生智能汽车竞赛-讯飞智慧餐厅
- OBJECT_METHOD初窥
- python如何删除文件夹下文件和文件夹?
- 08年最热门七大技术和最紧缺的IT人才
- swiper默认选中_Swiper
- GitHub网站使用的基础入门
- python中response对象的属性_Django 中的响应对象 Response
- 使用Zookeeper实现负载均衡原理
- 论文赏析[EACL17]K-best Iterative Viterbi Parsing(K-best迭代维特比句法分析)
- NetBeans在Apache基金会取得的进展
- stopwords怎么用_【技术】怎么用Python画出好看的词云图?
- 详解全局免流原理(转载)
- java图书管理系统的简单实现
- 又一北京“假名媛”曝光,蹭吃蹭喝21天,暴露人性最真实一面
- 2021-08-18 关于PC与ipad的远程控制
- p3.第一章 Python基础入门 -- Python编程基本概念 (三)
- win8计算机的录音功能,win8电脑录音机功能在哪|win8录音功能使用方法
- CSDN什么时候倒闭啊
- 哈工大软件构造第一章总结
- ue4 android联机,UE4 局域网联机(LAN)