hibernate的查询方式和抓取策略

hibernate的查询方式

hibernate提供了5种查询方式,我们最主要的是用到HQL检索QBC检索

OID检索

通过id来检索数据

使用get方法

Customer customer = session.get(Customer.class,1L);

使用load方法

Customer customer = session.get(Customer.class,1L);

对象导航检索

对象导航检索:hibernate根据一个已经查询到的对象,获取其关联的对象的一种查询方法(即通过获取到的对象,利用其实体类中关联的对象属性,获取其关联的对象)

根据获取到的联系人对象获取客户对象

LinkMan linkMan = session.get(LinkMan.class,1L);

Customer customer = linkMan.getCustrmer();

根据获取到的客户对象,获取其所有联系人对象的集合

Customer customer = session.get(Customer.class,1L);

Set<LinkMan> linkMans = customer.getLinkMans();

HQL检索

HQL查询:(hibernate query language),hibernate的查询语言,是一种面向对象的方式的查询语言,语法类似SQL,通过session.createQuery()(用于接收一个HQL语句的查询语句)
初始化数据

public void demo1() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();

		// 创建一个客户
		Customer customer = new Customer();
		customer.setCust_name("李向文");

		for (int i = 1; i <= 10; i++) {
			LinkMan linkMan = new LinkMan();
			linkMan.setLkm_name("王东" + i);
			linkMan.setCustomer(customer);

			customer.getLinkMans().add(linkMan);

			session.save(linkMan);
		}
		session.save(customer);

		tx.commit();
	}

HQL简单查询

public void demo2() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// 简单的查询
		Query query = session.createQuery("from Customer");
		List<Customer> list = query.list();

		// sql中支持*号的写法:select * from cst_customer; 但是在HQL中不支持*号的写法。
		/*
		 * Query query = session.createQuery("select * from Customer");// 报错
		 * List<Customer> list = query.list();
		 */

		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

别名查询 

public void demo3() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// 别名的查询
		/*
		 * Query query = session.createQuery("from Customer c"); List<Customer>
		 * list = query.list();
		 */

		Query query = session.createQuery("select c from Customer c");
		List<Customer> list = query.list();

		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

 排序查询

/**
	 * 排序查询
	 */
	public void demo4() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// 排序的查询
		// 默认情况
		// List<Customer> list = session.createQuery("from Customer order by
		// cust_id").list();
		// 设置降序排序 升序使用asc 降序使用desc
		List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();

		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

 条件查询

public void demo5() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// 条件的查询
		// 一、按位置绑定:根据参数的位置进行绑定。
		// 一个条件
		/*
		 * Query query = session.createQuery("from Customer where cust_name = ?"
		 * ); query.setParameter(0, "李兵"); List<Customer> list = query.list();
		 */

		// 多个条件
		/*
		 * Query query = session.createQuery(
		 * "from Customer where cust_source = ? and cust_name like ?");
		 * query.setParameter(0, "小广告"); query.setParameter(1, "李%");
		 * List<Customer> list = query.list();
		 */

		// 二、按名称绑定
		Query query = session.createQuery("from Customer where cust_source = :aaa and cust_name like :bbb");
		// 设置参数:
		query.setParameter("aaa", "朋友推荐");
		query.setParameter("bbb", "李%");
		List<Customer> list = query.list();

		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

投影查询

public void demo6() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();

		// 投影查询
		// 单个属性
		/*
		 * List<Object> list = session.createQuery(
		 * "select c.cust_name from Customer c").list(); for (Object object :
		 * list) { System.out.println(object); }
		 */

		// 多个属性:
		/*
		 * List<Object[]> list = session.createQuery(
		 * "select c.cust_name,c.cust_source from Customer c").list(); for
		 * (Object[] objects : list) {
		 * System.out.println(Arrays.toString(objects)); }
		 */

		// 查询多个属性,但是我想封装到对象中。需要在实体类中添加相应构造方法
		List<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

分页查询

public void demo7() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();

		// 分页查询
		Query query = session.createQuery("from LinkMan");
		query.setFirstResult(20);
		query.setMaxResults(10);
		List<LinkMan> list = query.list();

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

分组统计查询

public void demo8() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();

		// 聚合函数的使用:count(),max(),min(),avg(),sum()
		Object object = session.createQuery("select count(*) from Customer").uniqueResult();
		System.out.println(object);
		// 分组统计:
		List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source")
				.list();
		for (Object[] objects : list) {
			System.out.println(Arrays.toString(objects));
		}
		tx.commit();
	}

多表查询

SQL的多表查询

      连接查询

          交叉连接:笛卡尔积

          select * from A,B;

          内连接 :inner join (inner 可以省略)

                  隐式内连接:

                  select * from A,B where A.id = B.aid;

                 显示内连接:

                  select * from A inner join B on A.id = B.aid;

           外连接 :

                  左外连接:left outer join(outer 可以省略)

                   select * from A left outer join B on A.id= B.aid;

                 右外连接:right outer join(outer 可以省略)

                   select * from A right outer join B on A.id = B.aid;

          子查询

HQL的多表查询

       连接查询

           交叉连接  

           内连接:普通内连接,得到的是一个一个的Object[]对象,即List<Object[]>,将Customer对象和LinkMan对象分开来

                           迫切内连接,得到的是一个一个的Customer对象,即List<Customer>,将LinkMan对象封装到了Customer对象的List<LinkMan>中

              迫切内连接

               隐式内连接

               显示内连接

          外连接:外连接与内连接一样一样的

               迫切左外连接

               右外连接

               左外连接

public void demo9() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		// SQL:SELECT * FROM cst_customer c INNER JOIN cst_linkman l ON
		// c.cust_id = l.lkm_cust_id;
		// HQL:内连接 from Customer c inner join c.linkMans
		/*
		 * List<Object[]> list = session.createQuery(
		 * "from Customer c inner join c.linkMans").list(); for (Object[]
		 * objects : list) { System.out.println(Arrays.toString(objects)); }
		 */

		// HQL:迫切内连接 其实就在普通的内连接inner join后添加一个关键字fetch. from Customer c inner
		// join fetch c.linkMans
		List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans")
				.list();// 通知hibernate,将另一个对象的数据封装到该对象中

		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

运行结果     所有的LinkMan对象都封装在了其customer中

QBC检索

QBC查询(query by criteria)条件查询,更加面向对象的查询方式

简单的查询

public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		// 获得Criteria的对象
		Criteria criteria = session.createCriteria(Customer.class);
		List<Customer> list = criteria.list();
		
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

排序查询

public void demo2(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		// 排序查询
		Criteria criteria = session.createCriteria(Customer.class);
//		criteria.addOrder(Order.asc("cust_id")); // 升序
		criteria.addOrder(Order.desc("cust_id")); // 降序
		List<Customer> list = criteria.list();
		
		for (Customer customer : list) {
			System.out.println(customer);
		}

分页查询

public void demo3(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		// 分页查询
		Criteria criteria = session.createCriteria(LinkMan.class);
		criteria.setFirstResult(10);
		criteria.setMaxResults(10);
		List<LinkMan> list = criteria.list();
		
		for (LinkMan linkMan : list) {
			System.out.println(linkMan);
		}
		tx.commit();
	}

条件查询

public void demo4(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		// 条件查询
		Criteria criteria = session.createCriteria(Customer.class);
		// 设置条件:
		/**
		 * =   eq
		 * >   gt
		 * >=  ge
		 * <   lt
		 * <=  le
		 * <>  ne
		 * like
		 * in
		 * and
		 * or
		 */
		criteria.add(Restrictions.eq("cust_source", "小广告"));
//		criteria.add(Restrictions.or(Restrictions.like("cust_name", "李%")));
		criteria.add(Restrictions.like("cust_name", "李%"));
		List<Customer> list = criteria.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

统计查询

public void demo5(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		Criteria criteria = session.createCriteria(Customer.class);
		/**
		 * add				:普通的条件。where后面条件
		 * addOrder			:排序
		 * setProjection	:聚合函数 和 group by having
		 */
		criteria.setProjection(Projections.rowCount());
		Long num = (Long) criteria.uniqueResult();
		System.out.println(num);
		tx.commit();
	}

离线条件查询(DetachedCriteria)

适合查询带条件还带分页的查询,比如查询某一类的商品,并要求分页(SSH整合是经常要用到的查询方法)更适合多条件联合查询

public void demo6(){
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
		detachedCriteria.add(Restrictions.like("cust_name", "李%"));
		
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		Criteria criteria = detachedCriteria.getExecutableCriteria(session);
		List<Customer> list = criteria.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		transaction.commit();
	}

SQL检索

通过SQL语句进行查询

public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		/*SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
		List<Object[]> list = sqlQuery.list();
		for (Object[] objects : list) {
			System.out.println(Arrays.toString(objects));
		}*/
		
		SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
		sqlQuery.addEntity(Customer.class);
		List<Customer> list = sqlQuery.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

hibernate的抓取策略

hibernate的效率有可能是比较低的,因此hibernate中我们需要学习抓取策略

抓取策略:查询关联对象的优化

hibernate的效率不是特别高,因此hibernate提供了几种优化手段,如hibernate的缓存机制,hibernate的抓取策略

抓取策略一般不单独用,一般与延迟加载一起使用

延迟加载的概述

延迟加载:lazy(懒加载)执行到该行代码时,不会发送语句去进行查询,而在真正使用这个对象的属性是才会发送SQL语句进行查询

延迟加载的分类

类级别的延迟加载

指的是通过load方法查询某个类对象时,是否采用延迟      session.load(Customer.class,1L);

类级别延迟加载通过在类的映射文件中的<class>标签的lazy属性进行配置,默认lazy=“true”表示采用延迟加载,所以我们采用load方法去获取类对象时会延迟加载

<class name="com.itheima.hibernate.domain.Customer" lazy="true">

如何让lazy失效:

        将lazy设置成false

        将持久化类使用final修饰

        Hibernate.Initialize();//相当于将类对象初始化,使用一下类对象

/**
	 * 类级别的延迟加载
	 * * 在<class>的标签上配置的lazy
	 */
	public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		Customer customer = session.load(Customer.class, 1l);
		Hibernate.initialize(customer);
		System.out.println(customer);
		
		tx.commit();
	}

 

再讲lazy改为false

关联级别的延迟加载

指的是在查询某个对象时,查询其关联对象时,是否采用延迟     

Customer customer = session.get(Customer.class,1L);

customer.getLinkMans();                通过客户获得联系人时,联系人对象是否采用了延迟

需要在<set><many-to-one>这些标签中设置lazy

抓取策略一般与关联级别的延迟加载一起使用,以达到优化SQL语句的作用

抓取策略

抓取策略的概述

通过一个对象可以抓取到其关联对象,需要发送SQL语句的,但是这些语句发送成什么样的格式,需要通过策略进行配置

        通过在<set>或<many-to-one>上通过fetch属性进行设置

         通过设置fetch(有很多的值)和这些标签上的lazy(也有很多值)的值配合使用,来优化发送的SQL语句

(前面的    迫切内连接    也用到了fetch)

<set>上的fetch和lazy

fetch     抓取策略:控制SQL语句格式

           select                :默认值,发送普通的SQL语句   查询其关联对象

           join                     :发送一条迫切左外连接查询关联对象

           subselect           :发送一条子查询查询其关联对象

lazy      延迟加载:控制查询关联对象的时候是否采用延迟

          true                     :默认值,查询关联对象的时候,采用延迟加载

          false                    :查询关联对象的时候,不采用延迟加载

          extra                    :极其懒惰,用什么样的语句就发什么样的语句,不会多发一点点

默认情况,即fetch = "select"  lazy = "true"

/**
	 * 默认情况:
	 */
	public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		// 查询1号客户
		Customer customer = session.get(Customer.class, 1l);// 发送一条查询客户的SQL
		System.out.println(customer.getCust_name());
		// 查看1号客户的每个联系人的信息
		for (LinkMan linkMan : customer.getLinkMans()) {// 发送一条根据客户ID查询联系人的SQL
			System.out.println(linkMan.getLkm_name());
		}
		tx.commit();
	}

配置set标签的   fetch = "select"  lazy = "false"

/**
	 * 设置	fetch="select" lazy="false"
	 */
	public void demo3(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		// 查询1号客户
		Customer customer = session.get(Customer.class, 3l);
		// 发送两条SQL语句:查询客户的名称,查询客户关联联系人
		System.out.println(customer.getCust_name());
		/*// 查看1号客户的每个联系人的信息
		for (LinkMan linkMan : customer.getLinkMans()) {// 
			System.out.println(linkMan.getLkm_name());
		}*/
		
		System.out.println(customer.getLinkMans().size());
		tx.commit();
	}

打印结果

配置set标签的   fetch = "select"  lazy = "extra"

/**
	 * 设置fetch="select" lazy="extra"
	 */
	public void demo4(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		// 查询1号客户
		Customer customer = session.get(Customer.class, 1l);// 发送一条查询1号客户的SQL语句
		System.out.println(customer.getCust_name());
		
		System.out.println(customer.getLinkMans().size());// 发送一条select count() from ...;
		tx.commit();
	}

配置set标签的   fetch = "join"  lazy = "true"    

fetch = "join"表示将使用迫切左外连接查询数据库,会将当前对象和其关联对象一起一次性查出,而lazy控制的是延迟加载,在这种情况下相当于失效了

 * 设置fetch="join" lazy=失效
	 */
	public void demo5(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		// 查询1号客户
		Customer customer = session.get(Customer.class, 3l);// 发送一条迫切左外连接查询记录
		System.out.println(customer.getCust_name());
		
		System.out.println(customer.getLinkMans().size());// 不发送
		tx.commit();
	}

配置set标签的   fetch = "subselect"  lazy = "true"

子查询      必须要查询多个对象才行    如果不查询多个,hibernate会直接将子查询   in语句   变成    =  (对于只查询一个对象   =   符号肯定比    in语句   效率更高)  从而无法体现子查询

 配置set标签的   fetch = "subselect"  lazy = "false"

/**
	 * 设置fetch="subselect" lazy="false"
	 */
	public void demo7(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		List<Customer> list = session.createQuery("from Customer").list();
		 /*发送查询所有客户的SQL,发送一条子查询,延迟失效,
		hibernate会在这里直接将当前查询的类对象及其关联类对象全部查出*/
		for (Customer customer : list) {
			System.out.println(customer.getCust_name());
			System.out.println(customer.getLinkMans().size());// 
		}
		
		tx.commit();
	}

 在我们开发过程中,一般将fetch和lazy设置成默认的

<many-to-one>这类标签上的fetch和lazy

fetch:抓取策略,控制SQL语句的格式

            select          默认值,发送普通的SQL语句

            join               发送一条迫切左外连接

lazy :延迟加载,控制查询关联对象是否采用延迟

           proxy             默认值,proxy具体的取值,取决于另一端的<class>上的lazy值

           false              不采用延迟

           no-proxy        (不会使用)

在我们开发过程中,一般将fetch和lazy设置成默认的

批量抓取

/**
	 * 获取客户的时候,批量抓取联系人
	 * 在Customer.hbm.xml中set上配置batch-size
	 */
	public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		List<Customer> list = session.createQuery("from Customer").list();
		for (Customer customer : list) {
			System.out.println(customer.getCust_name());
			for (LinkMan linkMan : customer.getLinkMans()) {
				System.out.println(linkMan.getLkm_name());
			}
		}
		tx.commit();
	}
/**
	 * 获取联系人的时候,批量抓取客户
	 * * 在Customer.hbm.xml中<class>上配置
	 */
	public void demo2(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		List<LinkMan> list = session.createQuery("from LinkMan").list();
		for (LinkMan linkMan : list) {
			System.out.println(linkMan.getLkm_name());
			System.out.println(linkMan.getCustomer().getCust_name());
		}
		tx.commit();
	}

猜你喜欢

转载自blog.csdn.net/bright_light12345/article/details/83339602