Hibernate查询方式



OID查询


     它就是根据id查询一个实体


     涉及的方法:


          get(Class clazz,Serializable id):参数1是要查询的实体字节码,参数2:是要查询的id。


          load(Class clazz,Serializable id):参数1是要查询的实体字节码,参数2:是要查询的id。


Hibernate的检索策略


     类级别检索策略:


          get方法:


               它永远都是立即加载。返回的对象是实体类类型。


               立即加载的含义:不管用不用,都马上发起查询。


          load方法:


               它默认是延迟加载。返回的是实体类对象的代理对象。


               它可以通过配置的方式改为立即加载。配置的位置是映射文件的class标签。


               涉及的属性是:lazy。含义就是是否延迟加载。 取值true延迟加载(默认值) false不是延迟加载


               延迟加载的含义:什么时候用,什么时候真正发起查询。



测试OID检索方式



package com.pc.hibernate.test.querymethod;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.pc.hibernate.domain.Customer;
import com.pc.hibernate.utils.HibernateUtils;

/**
 * Hibernate中的查询方式:
 *         OID查询:
 *             它就是根据id查询一个实体
 *         涉及的方法:
 *             get(Class clazz,Serializable id):参数1是要查询的实体字节码,参数2:是要查询的id。
 *            load(Class clazz,Serializable id):参数1是要查询的实体字节码,参数2:是要查询的id。
 *
 * Hibernate的检索策略
 *       类级别检索策略:
 *          get方法:
 *             它永远都是立即加载。返回的对象是实体类类型。
 *             立即加载的含义:不管用不用,都马上发起查询。
 *         load方法:
 *             它默认是延迟加载。返回的是实体类对象的代理对象。
 *             它可以通过配置的方式改为立即加载。配置的位置是映射文件的class标签。
 *             涉及的属性是:lazy。含义就是是否延迟加载。 取值true延迟加载(默认值) false不是延迟加载
 *             延迟加载的含义:什么时候用,什么时候真正发起查询。
 * @author Switch
 *
 */
public class TestOIDQuery {
    /**
     * 需求:
     *     查询id为1的客户
     */
    @Test
    public void test1() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Customer customer = session.get(Customer.class, 1L);
        transaction.commit();
        // 输出1和客户信息
        System.out.println(customer.getCustId());
        System.out.println(customer);
    }

    /**
     * 需求:
     *     查询id为1的客户
     */
    @Test
    public void test2() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Customer customer = session.load(Customer.class, 1L);
        transaction.commit();
        // 输出1和报错could not initialize proxy - no Session
        // 当<class name="Customer" table="cst_customer" lazy="false">时
        // 该方法正确,因为这时候已经不延迟加载了
        System.out.println(customer.getCustId());
        System.out.println(customer);
    }
}





对象导航查询


     对象图导航检索方式是根据己经加载的对象,导航到他的关联对象 。它利用类与类之间的关系来检索对象 。譬如要查找一个联系人对应的客户,就可以由联系人对象自动导航找到联系人所属的客户对象。当然,前提是必须在对象关系映射文件上配置了多对一的关系。




     当我们两个实体类有关联关系时(一对多,多对一等等),在获取一个实体时,可以根据对象的方法,获取该实体关联对象的数据。


     customer.getLinkMans();获取当前客户下的所有联系人


     linkman.getCustomer();获取当前联系人所属客户。

package com.pc.hibernate.test.querymethod;

import java.util.List;
import java.util.Set;

import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.pc.hibernate.domain.Customer;
import com.pc.hibernate.domain.LinkMan;
import com.pc.hibernate.utils.HibernateUtils;

/**
 *
 * Hibernate中的查询方式:
 *         对象导航查询
 *             当我们两个实体类有关联关系时(一对多,多对一等等),在获取一个实体时,可以根据对象的方法,获取该实体关联对象的数据。
 *             customer.getLinkMans();获取当前客户下的所有联系人
 *             linkman.getCustomer();获取当前联系人所属客户。
 *
 * @author Switch
 */
public class TestObjectNavigationQuery {
    /**
     * 一般情况下我们都会有一个这样的方法:根据id查询一个实体。
     * 任何实体都应该有这么个方法
     */
    public Customer findById(Long custId){
        Session s = HibernateUtils.getCurrentSession();
        Transaction tx = s.beginTransaction();
        Customer c1 = s.get(Customer.class, custId);
        tx.commit();
        return c1;
    }

    /**
     * 根据客户id查询联系人信息
     * @param custId
     * @return
     */
    public List<LinkMan> findLinkManByCid(Long custId){
        Session s = HibernateUtils.getCurrentSession();
        Transaction tx = s.beginTransaction();
        SQLQuery query = s.createSQLQuery("select * from cst_linkman where lkm_cust_id = ? ");
        query.setLong(0, custId);
        query.addEntity(LinkMan.class);
        @SuppressWarnings("unchecked")
        List<LinkMan> mans = query.list();
        tx.commit();
        return mans;
    }

    /**
     * 需求:
     *     查询id为1的客户下的所有联系人
     */
    @Test
    public void test1(){
        // 传统的使用方式
        List<LinkMan> list = findLinkManByCid(1L);
        System.out.println(list);

        Customer c = findById(1L);
        //对象导航查询
        // 需要将Customer上对应于LinkMan的关系检索策略的懒加载关闭
        Set<LinkMan> linkmans = c.getLinkMans();
        for(LinkMan linkMan : linkmans){
            System.out.println(linkMan);
        }
    }


    /**
     * 需求:
     *     查询id为5的联系人所属客户
     */
    @Test
    public void test2() {
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        LinkMan linkMan = session.get(LinkMan.class, 5L);
        // 对象导航查询
        System.out.println(linkMan.getCustomer());
        transaction.commit();

    }

}





HQL查询


     HQL (Hibernate Query Language ) 是面向对象的查询语言,它和 SQL 查询语言有些相似 ,但它使用的是类、对象和属性的概念 ,而没有表和字段的概念 。在Hibernate提供的各种检索方式中 ,HQL是官方推荐的查询语言,也是使用最广泛的一种检索 方式。


     涉及的对象:


          Query


     如何获取Query:


          session.createQuery(String hql);


     HQL语句写法:


          表名用实体类名称替代


          字段名用实体类属性名称(get/set方法后面的部分,并且把首字母转小写)


     Hibernate 进行 多表查询与 SQL 其实是很相似的 ,但是 HQL 会在原来 SQL 分类的基础上又多出来一些操作 。





HQL  的多表连接查询的分类如下 :



  • 交叉连接
  • 内连接
  • 显式内连接
  • 隐式内连接
  • 迫切内连接
  • 外连接
  • 左外连接
  • 迫切左外连接



     其实这些连接查询语法大致都是一致的,就是HQL查询的是对象而SQL查询的是表。那么我们来比较一下SQL和HQL的连接查询。





SQL  连接查询



SELECT  * FROM  cst_customer c INNER JOIN cst_linkman 1 ON c.cust_id = l.lkm_cust_id;


HQL 连接的查询



from Customer c inner join c.linkMans



     在HQL中,我们不用写关联宇段了,因为客户中的联系人的集合其实对应的就是外键,所以我们在inner join的后面直接可以写 c.linkMans。



     迫切内连接其实就是在内连接的inner join后添加一个fetch关键字。



from Customer c inner join fetch c.linkMans





     内连接或是迫切内连接发送的底层SQL都是一样的,而且在生成的SQL语句中也没有fetch关键字,当然fetch本身就不是SQL语句的关键字。所以一定要注意,fetch只能在HQL中使用的,生成了SQL语句以后,fetch就消失了 。



     其实HQL内连接查询的和SQL的内连接查询到的结果集是一样的 ,都是两个表的交集部分的数据。



     然后在封装数据的时候,普通内连接会将属于客户的数据封装到Customer对象中,会将属于联系人的数据封装到LinkMan对象中,所以每条记录都会是装有两个对象的集合,所以封装以后的数据是 List<Object[ ]>,在Object[ ]中有两个对象一个是 Customer另一个是 LinkMan 。



     那么加了fetch以后,虽然查询到的数据是一样的,但是Hibernate发现HQL中有fetch就会将数据封装到一个对象中,把属于客户的数据封装到Customer对象中,将属于联系人的部分封装到Customer中的联系人的集合中,这样最后封装完成以后是一个 List<Customer> 中。





测试HQL方式



package com.pc.hibernate.test.querymethod;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.pc.hibernate.domain.Customer;
import com.pc.hibernate.domain.LinkMan;
import com.pc.hibernate.utils.HibernateUtils;

/**
 * Hibernate中的查询方式:
 *         HQL查询:
 *             它是使用HQL语句进行查询的。 HQL:Hiberante Query Language
 *         涉及的对象:
 *             Query
 *         如何获取Query:
 *             session.createQuery(String hql);
 *         HQL语句写法:
 *             表名用实体类名称替代
 *             字段名用实体类属性名称(get/set方法后面的部分,并且把首字母转小写)
 *
 * @author Switch
 */
public class TestHQLQuery {
    /**
     * 查询所有
     * 需求:查询所有客户
     */
    @Test
    public void test1() {
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        // 查询所有客户
        Query query = session.createQuery("from Customer");
        @SuppressWarnings("unchecked")
        List<Customer> customers = query.list();
        transaction.commit();
        for (Customer customer : customers) {
            System.out.println(customer);
        }
    }

    /**
     * 条件查询:
     *     需求:
     *         查询客户级别是23的,客户名称带有 集 字的
     *  给HQL语句加条件用where
     *  HQL语句的参数占位符也可以使用?
     *  hibernate中,参数占位符是从0开始的。
     */
    @Test
    public void test2(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        // 查询客户级别是23的,客户名称带有 集 字的
        Query query = session.createQuery("from Customer where custLevel = ? and custName like ?");
        query.setString(0, "23");
        query.setString(1, "%集%");
        @SuppressWarnings("unchecked")
        List<Customer> customers = query.list();
        transaction.commit();
        for (Customer customer : customers) {
            System.out.println(customer);
        }
    }

    /**
     * 具名查询:
     *     给参数占位符提供一个具体的名称
     * HQL语句中的写法:
     *         需要使用    :参数名称
     *         例如:        :custLevel    :custName
     * 参数站位符赋值的写法:
     *         需要注意:此处不能写冒号,直接写冒号后面的部分
     */
    @Test
    public void test3(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        // 查询客户级别是23的,客户名称带有 集 字的
        // 给参数占位符提供一个具体的名称
        Query query = session.createQuery("from Customer where custLevel = :custLevel and custName like :custName");
        query.setString("custLevel", "23");
        query.setString("custName", "%集%");
        @SuppressWarnings("unchecked")
        List<Customer> customers = query.list();
        transaction.commit();
        for (Customer customer : customers) {
            System.out.println(customer);
        }
    }


    /**
     * 排序查询:
     *      使用HQL语句,给查询结果排序
     *
     * HQL语句中的排序:
     *         order by
     *         asc:升序(默认值)
     *         desc:降序
     */
    @Test
    public void test4(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        // 按联系人ID降序排序联系人
        Query query = session.createQuery("from LinkMan order by lkmId desc");
        @SuppressWarnings("unchecked")
        List<LinkMan> linkMans = query.list();
        transaction.commit();
        for (LinkMan linkMan : linkMans) {
            System.out.println(linkMan);
        }
    }

    /**
     * 分页查询
     * MySQL中分页关键字:
     *         Limit
     * limit的两个参数: 第一个参数:查询的开始记录索引。(它是从0开始的)
     *                    第二个参数:每次查询多少条记录。(它是固定的)
     * Hibernate中涉及的方法
     *         setFirstResult(int firstResult):查询的开始记录索引
     *         setMaxResults(int maxResults):每次查询多少条记录
     */
    @Test
    public void test5(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //1.获取Query对象
        Query query = session.createQuery("from LinkMan");
        //2.使用Hibernate提供的方法来设置分页条件
        Integer firstResult = 0;
        Integer maxResults = 2;
        query.setFirstResult(firstResult);
        query.setMaxResults(maxResults);
        //3.执行query对象的方法
        @SuppressWarnings("unchecked")
        List<LinkMan> list = query.list();
        transaction.commit();
        for (LinkMan linkMan : list) {
            System.out.println(linkMan);
        }
    }

    /**
     * 统计查询
     *       其实就是在HQL语句中使用聚合函数
     *         count() sum() avg() max() min()
     *      使用聚合函数查询时,如果没有group by,返回的结果集是一行一列的
     *
     *  聚合函数都不会计算为null的字段。
     * 
     *  count(*)和count(主键)是一样的。
     */
    @Test
    public void test6(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 查询一共有多少个联系人
        Query query = session.createQuery("select count(lkmId) from LinkMan");
        Long count = (Long) query.uniqueResult();
        transaction.commit();
        System.out.println(count);
    }

    /**
     * 投影查询:
     *      当我们查询实体对象时,并不需要所有字段信息,只查询部分,但是还想让他成为一个实体对象。其实就是用部分字段来投影出整个实体对象。
     * 使用要求:
     *     HQL语句:
     *         写法必须是  new 实体类名称(查询的字段)
     *         select new Customer(custId,custName) from Customer
     *         注意:如果你的实体类在工程中唯一,则可以直接写类名。如果实体类在工程中不唯一,需要写全限定类名。
     *  实体类要求:
     *      必须在实体类中提供一个相同参数列表的构造函数。
     *         
     */
    @Test
    public void test71(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 只获取客户的ID和名字,并封装成客户对象
        Query query = session.createQuery("select new Customer(custId, custName) from Customer");
        @SuppressWarnings("unchecked")
        List<Customer> customers = query.list();
        transaction.commit();
        for (Customer customer : customers) {
            System.out.println(customer.getCustId() + " " + customer.getCustName());
        }
    }

    @Test
    public void test72(){
        Session s = HibernateUtils.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.获取Query对象
        Query query = s.createQuery("select custId,custName from Customer ");
        //2.执行query对象的方法
        @SuppressWarnings("unchecked")
        List<Object[]> list = query.list();
        tx.commit();
        for(Object[] os : list){
            System.out.println("----------每个数组中的内容------------");
            for(Object o : os){
                System.out.println(o);
            }
        }
    }

    /**
     * 左外连接查询和迫切左外连接查询的区别
     * 区别:
     *     返回的结果集不一样。在实际开发中用的不多,此处讲解就是为了说明他们之间的区别
     * 注意:
     *     Hibernate中没有右外连接
     *
     * Hibernate左外连接返回的数据:   
     *         返回的是一个有Object数组组成的List集合,该数组中有两个对象。一个是主表实体,一个是从表实体。
     *         主表实体有可能重复
     */
    //左外连接查询
    @Test
    public void test81(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //1.获取Query对象
        //sql语句的左外:select * from cst_customer c left outer join cst_linkman l on c.cust_id = l.lkm_cust_id;
        Query query = session.createQuery("from Customer c left join c.linkMans");
        //2.执行query对象的方法
        @SuppressWarnings("unchecked")
        List<Object[]> list = query.list();
        transaction.commit();
        for (Object[] objects : list) {
            System.out.println("------一组对象-------");
            for (Object object : objects) {
                System.out.println(object);
            }
        }
    }

    /**
     * 迫切左外连接查询:
     *         要想使用迫切,需要在查询HQL语句中加入一个关键字:fetch
     * Hibernate迫切左外连接返回的数据:
     *         返回的是左表实体对象的List集合,并且左表中对应右表的字段已经被填充
     */
    @Test
    public void test82(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //1.获取Query对象
        Query query = session.createQuery("from Customer c left join fetch c.linkMans");
        //2.执行query对象的方法
        @SuppressWarnings("unchecked")
        List<Customer> customers = query.list();
        transaction.commit();
        for (Customer customer : customers) {
            System.out.println("------一组对象-------");
            System.out.println(customer);
            for (LinkMan linkMan : customer.getLinkMans()) {
                System.out.println(linkMan);
            }
            System.out.println("");
        }
    }

    /**
     * 使用HQL进行更新操作
     */
    @Test
    public void test9(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //1.获取Query对象
        Query query = session.createQuery("update Customer set custName = ? where custId = ?");
        query.setString(0, "XX公司");
        query.setString(1, "1");
        //2.执行query对象的方法
        int result = query.executeUpdate();
        transaction.commit();
        System.out.println(result);
    }
}





QBC查询


     QBC(Query By Criteria)是Hibernate提供的另一种检索对象的方式,它主要由Criteria 接口、Criterion接口和Expression类组成 。Criteria接口是Hibernate API中的一个查询接口,它需要由session进行创建。Criterion是Criteria的查询条件,在Criteria中提供了add(Criterion criterion)方法来添加查询条件。


     涉及的对象:


          Criteria


          DetachedCriteria


     获取的方式:


          session.createCriteria(Class clazz);参数指的是要查询的字节码


     添加条件的方法:


          Criteria的add方法


     添加条件涉及的对象:


          Restrictions



Restrictions类提供的方法


方法名

说明

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 限定查询



离线条件检索


     DetachedCriteria 翻译为离线条件查询,因为它是可以脱离Session来使用的一种条件查询对象,我们都知道Criteria对象必须由Session对象来创建。那么也就是说必须先有Session才可以生成Criteria对象。而DetachedCriteria对象可以在其他层对条件进行封装。


     这个对象也是比较有用的,尤其在SSH整合以后这个对象经常会使用 。它的主要优点是做一些特别复杂的条件查询的时候,往往会在WEB层向业务层传递很多的参数,业务层又会将这些参数传递给DAO层。最后在DAO中拼接SQL完成查询。有了离线条件查询对象后,那么这些工作都可以不用关心了,我们可以在WEB层将数据封装好,传递到业务层,再由业务层传递给DAO完成查询。



测试QBC检索方式

package com.pc.hibernate.test.querymethod;


import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;

import com.pc.hibernate.domain.Customer;
import com.pc.hibernate.domain.LinkMan;
import com.pc.hibernate.utils.HibernateUtils;

/**
 * Hibernate中的查询方式:
 *         QBC查询:
 *             Query By Criteria  它是一种更加面向对象的查询方式。
 *             它把查询条件都用方法封装了。里面的参数全都需要使用实体类的属性名称。
 *         涉及的对象:
 *             Criteria
 *             DetachedCriteria
 *         获取的方式:
 *             session.createCriteria(Class clazz);参数指的是要查询的字节码
 *         添加条件的方法:
 *              Criteria的add方法。
 *         添加条件涉及的对象:
 *             Restrictions
 *
 * @author Switch
 */
public class TestQBCQuery {
    /**
     * 基本查询:查询所有
     *
     * 需求:
     *     查询所有客户
     */
    @Test
    public void test1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        //1.获取Criteria对象
        Criteria criteria = session.createCriteria(Customer.class);
        //2.执行list方法,得到结果集
        @SuppressWarnings("unchecked")
        List<Customer> customers = criteria.list();
        tx.commit();
        for (Customer customer : customers) {
            System.out.println(customer);
        }
    }

    /**
     * 条件查询
     *     需求:查询客户级别是23的,客户名称带有集字的
     */
    @Test
    public void test2(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        //1.获取Criteria对象
        Criteria criteria = session.createCriteria(Customer.class);
        // 添加条件
        criteria.add(Restrictions.eq("custLevel", "23"));
        criteria.add(Restrictions.like("custName", "%集%"));
        //2.执行list方法,得到结果集
        @SuppressWarnings("unchecked")
        List<Customer> customers = criteria.list();
        tx.commit();
        for (Customer customer : customers) {
            System.out.println(customer);
        }
    }

    /**
     * 分页查询
     *
     * 涉及的方法:
     *         setFirstResult(int firstResult);
     *         setMaxResults(int maxResults);
     * 含义和HQL是一模一样的
     */
    @Test
    public void test3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        //1.获取Criteria对象
        Criteria criteria = session.createCriteria(Customer.class);
        criteria.setFirstResult(0);
        criteria.setMaxResults(2);
        //2.执行list方法,得到结果集
        @SuppressWarnings("unchecked")
        List<Customer> customers = criteria.list();
        tx.commit();
        for (Customer customer : customers) {
            System.out.println(customer);
        }
    }

    /**
     * 统计查询:
     *      使用QBC来添加聚合函数
     *
     * count() avg() min() max() sum()
     *
     * 涉及的方法:
     *         setProjections(Projection p ); 它可以加查询语句的结构。
     * 涉及的类:
     *         Projections
     *         该类中提供了一些静态方法
     */
    @Test
    public void test4(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        //1.获取Criteria对象
        Criteria criteria = session.createCriteria(Customer.class);
        criteria.setProjection(Projections.count("custId"));

        //2.执行uniqueResult方法,得到结果
        Long result = (Long) criteria.uniqueResult();
        tx.commit();

        System.out.println(result);
    }

    /**
     * 排序查询
     *
     * 涉及方法:
     *       Criteria的addOrder方法。该方法需要一个Order对象作为参数
     * Order对象有两个方法:
     *         desc(String propertyName):按照指定的属性名称,倒序排序。
     *         asc(String propertyName):按照自顶的属性名称,正序排序。
     */
    @Test
    public void test5(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        //1.获取Criteria对象
        Criteria criteria = session.createCriteria(LinkMan.class);
        criteria.addOrder(Order.desc("lkmId"));

        //2.执行list方法,得到结果集
        @SuppressWarnings("unchecked")
        List<LinkMan> linkMans = criteria.list();

        tx.commit();
        for (LinkMan linkMan : linkMans) {
            System.out.println(linkMan);
        }
    }


    /**
     * 离线查询:
     *      在线对象:
     *         Criteria对象。它的获取必须要一个可用的Session来创建。如果Session不能用,则不能创建Criteria。
     *         我们使用Criteria进行的查询就是在线查询。
     *      离线对象:
     *         创建DetachedCriteria不需要一个可用的Session。
     *         用DetachedCriteria进行的查询就叫做离线查询
     * 涉及的对象
     *         DetachedCriteria
     * 如何获取
     *         DetachedCriteria.forClass(Class clazz);参数的含义:要查询的实体类
     * 如何设置查询条件:
     *         和Criteria是一样的
     *
     * 在实际开发中:多条件查询用此种方式
     */

    //Servlet的方法
    @Test
    public void doGet(){
        //1.获取请求参数
        String custLevel = "23";
        String custName = "集";
        //2.查询所有客户
        DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);
        dCriteria.add(Restrictions.eq("custLevel", custLevel));
        dCriteria.add(Restrictions.like("custName", "%"+custName+"%"));

        List<Customer> cs = servicefindAllCustomer(dCriteria);

        for(Customer c : cs){
            //3.存入请求域中
            //4.转向列表页面
            System.out.println(c);
        }
    }

    //Service的方法
    public List<Customer> servicefindAllCustomer(DetachedCriteria dCriteria){
        return daofindAllCustomer(dCriteria);
    }

    //Dao中的方法
    public List<Customer> daofindAllCustomer(DetachedCriteria dCriteria){
        Session s = HibernateUtils.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.把离线对象激活
        Criteria c = dCriteria.getExecutableCriteria(s);
        //3.执行list方法,得到结果集
        @SuppressWarnings("unchecked")
        List<Customer> list = c.list();
        tx.commit();
        return list;
    }
}





原生SQL查询


     采用HQL或QBC检索方式时,Hibernate生成标准的SQL查询语句,适用于所有的数据库平台,因此这两种检索方式都是跨平台的。但有的应用程序可能需要根据底层数据库的SQL方言,来生成一些特殊的查询语句。在这种情况下,可以利用Hibemate提供的原生SQL检索方式 。


     原生SQL查询时通过SQLQuery sqlQuery = session.createSQLQuery(String sql)来实现的,因为操作方式就是SQL语句,故不再介绍。

/**
     * SQLQuery 它使用的是原始的SQL语句查询
     */
    @Test
    public void test3() {
        Session s = HibernateUtils.getCurrentSession();
        Transaction tx = s.beginTransaction();
        // 1.获取SQLQuery对象
        SQLQuery sqlquery = s.createSQLQuery("select * from cst_customer");// 参数是SQL语句
        // 2.执行sqlquery的方法,返回结果集
        /*
         * List<Object[]> list = sqlquery.list(); for(Object[] os : list){
         * System.out.println(
         * "-------------每出现一行分割线,表示外层循环执行了一次-------------------"); <br/>
         * for(Object o : os){ System.out.println(o); } }
         */
        // 添加实体类字节码,把查询结果转成实体类对象
        sqlquery.addEntity(Customer.class);
        List<Customer> cs = sqlquery.list();
        for (Customer c : cs) {
            System.out.println(c);
        }
        tx.commit();
    }




该博文使用的Hibernate配置文件和映射文件




Customer.hbm.xml



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
1、导入dtd约束
     在Hibernate的核心jar包中:hibernate-mapping-3.0.dtd
2、编写配置文件
          实体类和数据库表的对应关系
          实体类中属性和表的字段的对应关系
 -->
<hibernate-mapping package="com.pc.hibernate.domain">
     <!-- class标签:
              作用:用于配置实体类和表之间的对应关系
              属性:
                   name:实体类的名称。它应该写全限定类名
                   table:数据库表的名称
     -->
     <class name="Customer" table="cst_customer" lazy="true" batch-size="3">
          <!-- id标签:
                   作用:映射主键
                   属性:
                        name:实体类的属性名称
                        column:数据库表的字段名称
                        type:主键的类型
          -->
          <id name="custId" column="cust_id" type="java.lang.Long">
              <!-- generator标签:
                        作用:主键的生成方式
                        属性:
                             class:指定方式
                             取值:native
                                  含义:使用本地数据库的自动增长能力。
              -->

              <generator class="native"/>
          </id>
          <!-- property标签:
                   作用:映射其他字段
                   属性:
                        name:实体类的属性名称
                        column:数据库表的字段名称
                        type:字段的类型
                        length:数据库中对应列的长度
          -->
          <property name="custName" column="cust_name" type="java.lang.String" length="32"/>
          <property name="custSource" column="cust_source" type="java.lang.String" length="32"/>
          <property name="custIndustry" column="cust_industry" type="java.lang.String" length="32"/>
          <property name="custLevel" column="cust_level" type="java.lang.String" length="32"/>
          <property name="custAddress" column="cust_address" type="java.lang.String" length="128"/>
          <property name="custPhone" column="cust_phone" type="java.lang.String" length="64"/>

          <!-- 配置一对多 -->
          <set name="linkMans" inverse="false" cascade="save-update" batch-size="4" lazy="true" fetch="select">
              <key column="lkm_cust_id" />
              <one-to-many class="LinkMan"/>
          </set>
     </class>
</hibernate-mapping>







LinkMan.hbm.xml



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.pc.hibernate.domain">
     <class name="LinkMan" table="cst_linkman">
          <id name="lkmId" column="lkm_id" type="java.lang.Long">
              <generator class="native" />
          </id>
          <property name="lkmName" column="lkm_name" type="java.lang.String" length="16"/>
          <property name="lkmGender" column="lkm_gender" type="java.lang.String" length="10"/>
          <property name="lkmPhone" column="lkm_phone" type="java.lang.String" length="16"/>
          <property name="lkmMobile" column="lkm_mobile" type="java.lang.String" length="16"/>
          <property name="lkmEmail" column="lkm_email" type="java.lang.String" length="64"/>
          <property name="lkmPosition" column="lkm_position" type="java.lang.String" length="16"/>
          <property name="lkmMemo" column="lkm_memo" type="java.lang.String" length="512"/>

          <!-- 配置多对一 -->
          <many-to-one name="customer" class="Customer" column="lkm_cust_id" cascade="save-update" lazy="proxy" fetch="select"/>
     </class>
</hibernate-mapping>





hibernate.cfg.xml



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
     "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- 1、导入dtd约束 在hibernate核心jar包中:hibernate-configuration-3.0.dtd 2、编写配置文件 -->
<hibernate-configuration>
     <!-- 配置SessionFactory -->
     <!-- 创建SessionFactory需要3部分信息。 而配置文件中要写哪些配置,我们可以翻阅资料。 -->
     <!-- 第一部分:连接数据库的基本信息,第二部分:hibernate的基本配置,第三部分:映射文件的位置 -->
     <session-factory>
          <!-- 1、连接数据库的基本信息 -->
          <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
          <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mycrm</property>
          <property name="hibernate.connection.username">root</property>
          <property name="hibernate.connection.password">123456</property>

          <!-- 数据库的方言 -->
          <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

          <!-- 2、hibernate的基本配置 -->
          <!-- 是否显示SQL语句 -->
          <property name="hibernate.show_sql">true</property>
          <!-- 是否格式化显示SQL语句 -->
          <!-- <property name="hibernate.format_sql">true</property> -->
          <!-- 采用何种策略来创建表结构: -->
          <!-- update:检查表结构和实体类映射文件的变化,如果发现映射文件和表结构不一致,更新表结构。 -->
          <!-- 注意:hibernate不能创建数据库,只能在有数据库的情况下创建表结构。 -->
          <property name="hibernate.hbm2ddl.auto">update</property>

          <!-- 配置hibernate使用连接池:告知Hibernate使用连接池的厂商 -->
          <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

          <!-- 配置把Session绑定到当前线程上,从而保证一个线程只有一个Session -->
          <property name="hibernate.current_session_context_class">thread</property>

          <!-- 3、映射文件的位置 -->
          <mapping resource="com/pc/hibernate/domain/Customer.hbm.xml" />
          <mapping resource="com/pc/hibernate/domain/LinkMan.hbm.xml" />
     </session-factory>
</hibernate-configuration>