二:hibernate的持久化类和对象标识符

二 hibernate的持久化类和对象标识符
1.1持久化类的编写规范
1.1.1什么是持久化类:
Hibernate是持久层的ORM映射框架,专注于数据的持久化工作。所谓的持久化,就是将内存中的数据永久存储到关系型数据库中。那么知道了什么是持久化,什么又是持久化类呢?其实所谓的持久化类指的是一个Java类与数据库表建立了映射关系,那么这个类称为是持久化类。其实你可以简单的理解为持久化类就是一个Java类有了一个映射文件与数据库的表建立了关系。那么我们在编写持久化类的时候有哪些要求呢?接下来我们来看一下:
1.1.2持久化类的编写规则:
我们在编写持久化类的时候需要有以下几点需要注意:
持久化类需要提供无参数的构造方法。因为在Hibernate的底层需要使用反射生成类的实例。
持久化类的属性需要私有,对私有的属性提供公有的get和set方法。因为在Hibernate底层会将查询到的数据进行封装。
持久化类的属性要尽量使用包装类的类型。因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更清晰而基本数据类型不容易描述。举个例子:
假设表中有一列员工工资,如果使用double类型,如果这个员工工资忘记录入到系统中,系统会将默认值0存入到数据库,如果这个员工工资被扣完了,也会向系统中存入0.那么这个0就有了多重含义,而如果使用包装类类型就会避免以上情况,如果使用Double类型,忘记录入工资就会存入null,而这个员工工资被扣完了,就会存入0,不会产生歧义。
持久化类要有一个唯一标识OID与表的主键对应。因为Hibernate中需要通过这个唯一标识OID区分在内存中是否是同一个持久化类。在Java中通过地址区分是否是同一个对象的,在关系型数据库的表中是通过主键区分是否同一条记录。那么Hibernate就是通过这个OID来进行区分的。Hibernate是不允许在内存中出现两个OID相同的持久化对象的。
持久化类尽量不要使用final进行修饰。因为Hibernate中有延迟加载的机制,这个机制中会产生代理对象,Hibernate产生代理对象使用的是字节码的增强技术完成的,其实就是产生了当前类的一个子类对象实现的。如果使用了final修饰持久化类。那么就不能产生子类,从而就不会产生代理对象,那么Hibernate的延迟加载策略(是一种优化手段)就会失效。.
持久化类我们已经可以正常编写了,但是在持久化类中需要有一个唯一标识OID与表的主键去建立映射关系。而且主键一般我们是不会让客户手动录入的,一般我们是由程序生成主键。那么Hibernate中也提供了相应的主键生成的方式,那么我们来看下Hibernate的主键生成策略。
简单的说:
我们的实体类都需要遵从JavaBean的编写规范。
什么是JavaBean:
Bean:在软件开发领域,Bean表示可重用组件。
JavaBean就是用java语言开发的可重用组件。
JavaBean的编写规范是什么:
类都是public的
都有默认无参构造函数
成员变量都是私有的
都有公有的get/set方法
一般都实现Serializable接口。
基本类型和包装类的选择问题:
由于包装类可以有null值。所以实际开发中都是用包装类。
1.2hibernate中对象标识符(OID)
OID全称是Object Identifier,又叫做对象标识符。
它是hibernate用于区分两个对象是否是同一个对象的标识。
我们都知道,虚拟机内存区分两个对象看的是内存的地址是否一致。数据库区分两个对象,靠的是表的主键。hibernate负责把内存中的对象持久化到数据库表中,靠的就是对象标识符来区分两个对象是否是同一个。实体类中映射主键的字段就是OID,如下图所示:
这里写图片描述
1.3hibernate的主键生成策略
在讲解Hibernate的主键生成策略之前,先来了解两个概念,即自然主键和代理主键,具体如下:
自然主键:把具有业务含义的字段作为主键,称之为自然主键。例如在customer表中,如果把name字段作为主键,其前提条件必须是:每一个客户的姓名不允许为null,不允许客户重名,并且不允许修改客户姓名。尽管这也是可行的,但是不能满足不断变化的业务需求,一旦出现了允许客户重名的业务需求,就必须修改数据模型,重新定义表的主键,这给数据库的维护增加了难度。

代理主键:把不具备业务含义的字段作为主键,称之为代理主键。该字段一般取名为“ID”,通常为整数类型,因为整数类型比字符串类型要节省更多的数据库空间。在上面例子中,显然更合理的方式是使用代理主键。
这里写图片描述

Hibernate的一级缓存和对象状态
2.1hibernate的一级缓存
2.1.1hibernate中的一级缓存:
Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。

在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存。只要 Session 实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。固一级缓存也被称为是Session基本的缓存。

Hibernate的一级缓存有如下特点:
当应用程序调用Session接口的save()、update()、saveOrUpdate时,如果Session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。
当调用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。
当调用Session的close()方法时,Session缓存会被清空。
2.1.2测试一级缓存
@Test
// 证明Hibernate的一级缓存的存在:

public void demo1(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();        
        Customer customer1 = session.get(Customer.class, 1l);/

/ 马上发生一条sql查询1号客户.并将数据存入了一级缓存

System.out.println(customer1);
        Customer customer2 = session.get(Customer.class, 1l);

// 没有发生SQL语句从一级缓存中获取数据.

System.out.println(customer2);
System.out.println(customer1 == customer2);// true 一级缓存缓存的是对象的地址.
        tx.commit();
        session.close();
    }

2.1.3快照机制:
Hibernate 向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。

数据库中的数据:

程序代码:

@Test
    public void test2(){    
        Customer c2 = null;//内存中的一个对象
        //1.获取Session对象
        Session s = HibernateUtil.openSession();
        //2.使用Session对象开启事务
        Transaction tx = s.beginTransaction();
        //3.执行查询:查询ID为2的客户对象
        c2 = s.get(Customer.class, 2L);
        System.out.println(c2);//custName
        //修改客户名称为:文正大厦
        c2.setCustName("文正大厦");
        System.out.println(c2);//custName:文正大厦
        //4.提交事务
        tx.commit();
        //5.关闭Session
        s.close();          
        //当程序走到此处时,一级缓存就没了,但是并不影响我继续使用客户对象
        System.out.println(c2);//custName到底是什么
    }

问题:
custName输出的到底是什么?
分析:
如果是,则表示我们修改的代码没启任何作用,废代码一行。
如果输出是文正大厦,则表示我们程序内存的数据可能和数据库表中的不一致了,那就是脏数据。
思考:
有没有可能输出的是文正大厦,并且数据库的数据也变成了文正大厦呢?
如果真的发生了这种情况,是如何做到的呢?
答案:

2.2对象的三种状态
2.2.1对象的状态说明:
了解了主键的生成策略之后,我们可以进一步来了解持久化类了。Hibernate为了更好的来管理持久化类,特将持久化类分成了三种状态。在Hibernate中持久化的对象可以划分为三种状态,分别是瞬时态、持久态和脱管态,一个持久化类的实例可能处于三种不同状态中的某一种,三种状态的详细介绍如下。
1、瞬时态(transient)
瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建、开辟内存空间的对象,不存在持久化标识OID(相当于主键值),尚未与Hibernate Session关联,在数据库中也没有记录,失去引用后将被JVM回收。瞬时状态的对象在内存中是孤立存在的,与数据库中的数据无任何关联,仅是一个信息携带的载体。
2、持久态(persistent)
持久态的对象存在持久化标识OID ,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象,需要注意的是,持久态对象是在事务还未提交前变成持久态的。
3、脱管态(detached)
脱管态也称离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭时就变成了脱管态。脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。
2.2.2学习对象状态我们要明确的:
a、是为了更好的掌握hibernate中操作的方法。
b、区分状态只有两个标识
一是否有OID
二是否和Session建立的关系
临时状态:
没有OID,和Session没有关系。
持久化状态:
有OID,和Session有关系。
脱管状态:
有OID,和Session没有关系。
第3章Hibernate的事务控制
3.1配置Session和线程绑定
在Hibernate中,可以通过代码来操作管理事务,如通过“Transaction tx = session.beginTransaction();”开启一个事务;持久化操作后,通过“tx.commit();”提交事务;如果事务出现异常,又通过“tx.rollback();”操作来撤销事务(事务回滚)。
除了在代码中对事务开启,提交和回滚操作外,还可以在Hibernate的配置文件中对事务进行配置。配置文件中,可以设置事务的隔离级别。其具体的配置方法是在hibernate.cfg.xml文件中的标签元素中进行的。配置方法如下所示。
这里写图片描述

hibernate.connection.isolation = 4 
1Read uncommitted isolation
2Read committed isolation
4—Repeatable read isolation
8—Serializable isolation

–>
4
到这我们已经设置了事务的隔离级别,那么我们在真正进行事务管理的时候,需要考虑事务的应用的场景,也就是说我们的事务控制不应该是在DAO层实现的,应该在Service层实现,并且在Service中调用多个DAO实现一个业务逻辑的操作。具体操作如下显示:

其实最主要的是如何保证在Service中开启的事务时使用的Session对象和DAO中多个操作使用的是同一个Session对象。
其实有两种办法可以实现:
可以在业务层获取到Session,并将Session作为参数传递给DAO。
可以使用ThreadLocal将业务层获取的Session绑定到当前线程中,然后在DAO中获取Session的时候,都从当前线程中获取。

其实使用第二种方式肯定是最优方案,那么具体的实现已经不用我们来完成了,Hibernate的内部已经将这个事情做完了。我们只需要完成一段配置即可。
Hibernate5中自身提供了三种管理 Session 对象的方法
Session 对象的生命周期与本地线程绑定
Session 对象的生命周期与 JTA 事务绑定
Hibernate 委托程序管理 Session 对象的生命周期

在 Hibernate 的配置文件中, hibernate.current_session_context_class 属性用于指定 Session 管理方式, 可选值包括
thread:Session 对象的生命周期与本地线程绑定
jta:Session 对象的生命周期与 JTA 事务绑定
managed:Hibernate 委托程序来管理 Session 对象的生命周期

配置步骤:
    1、在hibernate.cfg.xml文件中配置


thread
2、获取Session时使用的方法:
/**
* 每次都是从当前线程上获取Session
* @return
*/
public static Session getCurrentSession(){
return factory.getCurrentSession();
}
细节:
当我们把Session绑定到当前线程之后,关闭session就是hibernate来做的,我们就不用关了。
到这里我们已经对Hibernate的事务管理有了基本的了解,但是之前我们所做的CRUD的操作其实还没有查询多条记录。那如果我们需要查询多条记录要如何完成呢,我们接下来去学习一下Hibernate的其他的相关的API。

第4章Hibernate查询对象的API
4.1Query:(掌握)
4.1.1概述
Query代表面向对象的一个Hibernate查询操作。在Hibernate中,通常使用session.createQuery()方法接受一个HQL语句,然后调用Query的list()或uniqueResult()方法执行查询。所谓的HQL是Hibernate Query Language缩写,其语法很像SQL语法,但它是完全面向对象的。
在Hibernate中使用Query对象的步骤,具体所示:
(1)获得Hibernate的Session对象。
(2)编写HQL语句。
(3)调用session.createQuery 创建查询对象。
(4)如果HQL语句包含参数,则调用Query的setXxx设置参数。
(5)调用Query对象的方法执行查询。
HQL的说明:
把表的名称换成实体类名称。把表字段名称换成实体类属性名称。
例如:
SQL:select * from cst_customer where cust_name like ?
HQL:select * from Customer where custName = ?
其中select * 可以省略,写为:from Customer where custName = ?
了解了使用Query对象的步骤后,接下来,通过具体示例来演示Query对象的查询操作。
4.1.2常用查询:
4.1.2.1基本查询
/**
* 查询所有
*/

@Test
    public void test1(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.获取Query对象
        Query query = s.createQuery("from Customer");
        //2.执行对象的方法,获取结果集
        List list = query.list();
        for(Object o : list){
            System.out.println(o);
        }
        tx.commit();
    }   

4.1.2.2条件查询
/**
* 条件查询
* hibernate的参数占位符索引是从0开始的
*/

@Test
    public void test2(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.获取Query对象
        Query query = s.createQuery("from Customer where custName like ? and custLevel = ?");
        //2.给参数占位符赋值
        query.setString(0, "%集%");
        query.setString(1, "普通客户");
        //3.执行对象的方法,获取结果集
        List list = query.list();
        for(Object o : list){
            System.out.println(o);
        }
        tx.commit();
    }
/**
 * 条件查询
 *  给参数占位符提供一个具体的名称
 *  参数占位符的写法:
 *      :名称
 *  赋值的时候不需要写冒号,直接写名称
 */
@Test
    public void test3(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.获取Query对象
        Query query = s.createQuery("from Customer where custName like :custName and custLevel = :custLevel");
        //2.给参数占位符赋值
        query.setString("custName", "%集%");
        query.setString("custLevel", "普通客户");
        //3.执行对象的方法,获取结果集
        List list = query.list();
        for(Object o : list){
            System.out.println(o);
        }
        tx.commit();
    }       

4.1.2.3分页查询
/**
* mysql的分页关键字
* limit
* limit的参数含义
* 第一个:查询的开始记录索引
* 第二个:每次查询的条数
* hibernate中针对分页提供了两个方法
* setFirstResult(int firstResult);设置开始记录索引
* setMaxResults(int maxResults);设置每次查询的记录条数
*/

@Test
    public void test4(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.获取Query对象
        Query query = s.createQuery("from Customer");
        //2.设置分页的方法
        query.setFirstResult(2);
        query.setMaxResults(2);
        //3.执行对象的方法,获取结果集
        List list = query.list();
        for(Object o : list){
            System.out.println(o);
        }
        tx.commit();
    }       

4.1.2.4排序查询
/**
* 排序查询
* 使用的关键字:
* order by
* 升序:
* asc 默认值
* 降序:
* desc
*/

@Test
    public void test2(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        Query query = s.createQuery("from LinkMan order by lkmId desc ");
        List list = query.list();
        for(Object o : list){;
            System.out.println(o);
        }
        tx.commit();
    }           

4.1.2.5统计查询
/**
* HQL使用聚合函数:
* 统计查询
* 聚合函数:
* count sum max min avg
*
* sql语句使用聚合函数时,在不使用group by子句的情况下,返回的结果,永远只有一行一列的情况。
*
* 在SQL语句时:
* select count(*) from table 它是统计所有字段,效率没有只统计主键字段高
* select count(主键) from table 它和第一个的结果是一样的,但是效率更高
* select count(非主键) from table 只统计不为null的字段
*/

@Test
    public void test1(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        Query query = s.createQuery("select count(lkmId) from LinkMan");//它最终仍然换转成SQL语句
//      List list = query.list();
//      for(Object o : list){;
//          System.out.println(o);
//      }
    Long total = (Long)query.uniqueResult();//返回的是一个唯一的结果集。 只有确定结果集唯一时,才能使用
    System.out.println(total);
    tx.commit();
}               

4.1.2.6投影查询
/**
* 投影查询:
* 投影:使用一个实体的部分字段信息,来构建实体类对象,叫做对象的投影(在hibernate中的叫法)
* 使用HQL的方式查询实体类的部分字段信息,并且封装到实体类中。(QBC也能实现投影查询,但是不如hql的好用,所以使用投影查询,一般都用HQL)
* HQL语句的写法:
* select new Customer() from Customer
* 如果工程只有一个唯一的类,可以不写全限定类名,否则必须写全限定类名。
* 实体类要求:
* 必须提供一个相同参数列表的构造函数
*/

@Test
public void test3(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    Query query = s.createQuery("select new Customer(custId,custName) from Customer ");
    List<Object[]> list = query.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}               

/**
* 客户的实体类
*/

public class Customer implements Serializable {

    private Long custId;
    private String custName;
    private String custSource;
    private String custIndustry;
    private String custLevel;
    private String custAddress;
    private String custPhone;

    public Customer(){

    }
//提供对应参数列表的构造函数
public Customer(Long custId, String custName) {
        this.custId = custId;
        this.custName = custName;
    }

    public Long getCustId() {
        return custId;
    }
    public void setCustId(Long custId) {
        this.custId = custId;
    }
    public String getCustName() {
        return custName;
    }
    public void setCustName(String custName) {
        this.custName = custName;
    }
    public String getCustSource() {
        return custSource;
    }
    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }
    public String getCustIndustry() {
        return custIndustry;
    }
    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }
    public String getCustLevel() {
        return custLevel;
    }
    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }
    public String getCustAddress() {
        return custAddress;
    }
    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }
    public String getCustPhone() {
        return custPhone;
    }
    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }
    public Set<LinkMan> getLinkmans() {
        return linkmans;
    }
    public void setLinkmans(Set<LinkMan> linkmans) {
        this.linkmans = linkmans;
    }
    @Override
    public String toString() {
        return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource
                + ", custIndustry=" + custIndustry + ", custLevel=" + custLevel + ", custAddress=" + custAddress
                + ", custPhone=" + custPhone + "]";
    }   
}

4.1.3Query中的方法说明:
list方法:该方法用于查询语句,返回的结果是一个list集合。
uniqueResult方法:该方法用于查询,返回的结果是一个Object对象。
setter方法:Query接口中提供了一系列的setter方法用于设置查询语句中的参数,针对不同的数据类型,需要用到不同的setter方法。
uniqueResult()方法:该方法用于返回唯一的结果,在确保只有一条记录的查询时可以使用该方法。
setFirstResult()方法:该方法可以设置获取第一个记录的位置,也就是它表示从第几条记录开始查询,默认从0开始计算。
setMaxResult()方法:该方法用于设置结果集的最大记录数,通常与setFirstResult()方法结合使用,用于限制结果集的范围,以实现分页功能。

4.2Criteria:
4.2.1概述
Criteria是一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何实现,以及SQL语句如何编写,它是Hibernate框架的核心查询对象。Criteria 查询,又称为QBC查询(Query By Criteria),它是Hibernate的另一种对象检索方式。
org.hibernate.criterion.Criterion是Hibernate提供的一个面向对象查询条件接口,一个单独的查询就是Criterion接口的一个实例,用于限制Criteria对象的查询,在Hibernate中Criterion对象的创建通常是通过Restrictions 工厂类完成的,它提供了条件查询方法。
通常,使用Criteria对象查询数据的主要步骤,具体如下:
(1)获得Hibernate的Session对象。
(2)通过Session获得Criteria对象。
(3)使用Restrictions的静态方法创建Criterion条件对象。Restrictions类中提供了一系列用于设定查询条件的静态方法,这些静态方法都返回Criterion实例,每个Criterion实例代表一个查询条件。
(4)向Criteria对象中添加Criterion 查询条件。Criteria的add()方法用于加入查询条件。
(5)执行Criterita的 list() 或uniqueResult() 获得结果。
细节:
HQL能查的,QBC都能查,反之亦然。
了解了Criteria对象的使用步骤后,接下来,通过具体示例来演示Criteria对象的查询操作。
4.2.2常用查询:
4.2.2.1基本查询
/**
* 查询所有
*/

@Test
public void test1(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.获取Criteria对象
    Criteria c = s.createCriteria(Customer.class);//它就相当于HQL的from Customer
    //2.执行对象的方法获取结果集
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}   

4.2.2.2条件查询
/**
* 条件查询
*/

@Test
public void test2(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.获取Criteria对象
    Criteria c = s.createCriteria(Customer.class);//它就相当于HQL的from Customer
    //2.设置查询条件
    c.add(Restrictions.like("custName", "%集%"));//from Customer where custName  like "%集%"
    c.add(Restrictions.eq("custLevel", "普通客户"));
    //3.执行对象的方法获取结果集
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}   

4.2.2.3分页查询
/**
* 分页查询
* 和HQL是一模一样的
*/

@Test
public void test3(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.获取Criteria对象
    Criteria c = s.createCriteria(Customer.class);//它就相当于HQL的from Customer
    //2.设置分页
    c.setFirstResult(2);
    c.setMaxResults(2);
    //3.执行对象的方法获取结果集
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}       

4.2.2.4排序查询
/**
* 排序查询
*/

@Test
public void test1(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.获取对象
    Criteria c = s.createCriteria(Customer.class);
    //2.设置排序
    c.addOrder(Order.desc("custId"));
    //3.获取结果集
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}           

4.2.2.5统计查询
/**
* QBC使用聚合函数
* 统计查询
* 涉及的对象:
* Criteria
* 涉及的方法:
* setProjection(Projection p);
* 参数的含义
* Projection:要添加的查询投影
*/

@Test
public void test2(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.获取对象
    Criteria c = s.createCriteria(Customer.class);//from Customer | select * from cst_customer
    //2.想办法把select * 变成 select count(*)
//  c.setProjection(Projections.rowCount());//select count(*)
    c.setProjection(Projections.count("custId"));//select count(cust_id)
    //3.获取结果集
//  List list = c.list();
//  for(Object o : list){
//      System.out.println(o);
//  }
    Long total = (Long)c.uniqueResult();
    System.out.println(total);
    tx.commit();
}           

4.2.2.6离线查询
/**
* 离线条件查询
* 离线:
* 它是和在线对应的。
* Criteria对象是一个在线对象,它是由一个可用的(活动的)Session对象获取的出来的。
* 当session失效时,就无法再获取该对象了。
* 有一个对象,它也可以用于设置条件,但是获取的时候并不需要Session对象。
* 该对象就叫做离线对象:
* DetachedCriteria对象
* 使用该对象进行的查询就叫做:离线查询
*
* 如何获取该对象
* DetachedCriteria dCriteria = DetachedCriteria.forClass(要查询的实体类字节码);
*
*/

@Test
public void test3(){
    //模拟一次web操作: 浏览器发送请求——调用servlet——调用service——调用dao——拿到结果到jsp上展示
    List list = servletFindAllCustomer();
    for(Object o : list){
        System.out.println(o);
    }
}

//模拟servlet

public List<Customer> servletFindAllCustomer(){
    //离线对象
    DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);
    //设置条件:和Criteria是一样的
    dCriteria.add(Restrictions.like("custName","%集%"));
    return serviceFindAllCustomer(dCriteria);
}
public List<Customer> serviceFindAllCustomer(DetachedCriteria dCriteria) {
     return daoFindAllCustomer(dCriteria);
}
public List<Customer> daoFindAllCustomer(DetachedCriteria dCriteria) {
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //把离线对象使用可用Session激活
    Criteria c = dCriteria.getExecutableCriteria(s);
    List<Customer> list = c.list();
    tx.commit();
    return list;
}               

第5章附录:QBC常用查询条件说明
短语 含义
Restrictions.eq 等于=
Restrictions.allEq 使用Map,使用key/value进行多个等于的判断
Restrictions.gt 大于>
Restrictions.ge 大于等于>=
Restrictions.lt 小于<
Restrictions.le 小于等于<=
Restrictions.between 对应sql的between子句
Restrictions.like 对应sql的like子句
Restrictions.in 对应sql的in子句
Restrictions.and and 关系
Restrictions.or or关系
Restrictions.sqlRestriction Sql限定查询
Restrictions.asc() 根据传入的字段进行升序排序
Restrictions.desc() 根据传入的字段进行降序排序

运算类型 HQL运算符 QBC运算方法
比较运算 = Restrictions.eq()
<> Restrictions.not(Restrictions.eq())

= Restrictions.ge()
< Restrictions.lt()
<= Restrictions.le()
is null Restrictions.isNull()
is not null Restrictions.isNotNull()
范围运算符 in Restrictions.in()
not in Restrictions.not(Restrictions.in())
between Restrictions.between()
not between Restrictions.not(Restrictions.between())

运算类型 HQL运算符 QBC运算方法
字符串模式匹配 like Restrictions.like()
逻辑 and Restrictions.and()|
Restrictions.conjunction()
or Restrictions.or()|
Restrictions.disjunction()
not Restrictions.not()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值