hibernate04

*一)hibernate的检索方式【HQL查询】
   (1)已学过的查询方式及其特点
       A)根据id查询客户订单信息,分别使用get()和load()二种方式 
   get:
  1)如果找到了,返回该对象;如果找不到,返回null 
         2)session.get(Customer.class,1)
  3)有产生SQL,即立刻检索 
         4)返回的对象是一个真实对象,即该对象中的每个属性都有值
  
   load:
  1)如果找到了,返回该对象;如果找不到,抛出异常,ObjectNotFoundException  
         2)session.load(Customer.class,1)
  3)无产生SQL,延迟检索 
         4)返回的对象是一个代理对象,即该对象中除id之外,都无值,
    该id值,不是查询数据库得到的,而是hibernate为其分配的OID值。
    只有当查询非ID属性时,才会返回真实对象
  
       B)通过对象导航方式查询所需要的对象
   Customer c = get();
   for(Order o : c.getOrders){
  .. .. ..
   }

   (2)HQL与SQL的区别 
        HQL:(Hibernate专用查询语言):在Java程序员,使用HQL语句,发送到hibernate框架,框架再根据你配置的
         方言,将其自动转成与底层数据库一致的SQL,从而间接操作数据库。 
                select id,name from Customer where name like '小%'; 
         HQL只能出现属性名,类名,以及条件
 
        SQL:(结构化查询语言),只争对关系型数据库而言,通过SQL,能够在数据库中查询出你需要一切内容
                 select id,name from customers where name like '小%';
          SQL只能出现字段名,表名,以及条件  
      
   (3)使有HQL
        A)查询姓名为“XX”的客户订单信息

       

public void test2() {
		Session session = sessionFactory.openSession();
		String hql = "from Customer where name='小雪'";
		Query query = session.createQuery(hql);
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer.getName() + "的订单");
			for (Order order : customer.getOrders()) {
				System.out.println(order.getOrderno() + ":" + order.getPrice());
			}
		}
	}

 
        B)使用别名,查询姓名为“XX”的客户订单信息 

	public void test3() {
		Session session = sessionFactory.openSession();
		String hql = "from Customer c where c.name='小雪'";
		Query query = session.createQuery(hql);
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer.getName() + "的订单");
			for (Order order : customer.getOrders()) {
				System.out.println(order.getOrderno() + ":" + order.getPrice());
			}
		}
	}

 
        C)共有几个对象,共有几个客户,共有几个订单,多态查询(是指查询出当前类或所有子类的实例)

	public void test4() {
		Session session = sessionFactory.openSession();
		String hql = "from java.lang.Object";
		Query query = session.createQuery(hql);
		List<Object> objlist = query.list();
		System.out.println(objlist.size());
	}

 
        D)查询所有订单,按价格降序排列[ASC,DESC]

public void test5() {
		Session session = sessionFactory.openSession();
		String hql = "from Order as o order by o.price asc";
		Query query = session.createQuery(hql);
		List<Order> list = query.list();
		for (Order order : list) {
			System.out.println(order.getOrderno() + ":" + order.getPrice());
		}
	}

 
        E)分页查询订单,每页显示X条记录【动手练习】

	@Test
	public void test6() {
		Session session = sessionFactory.openSession();
		String hql = "from Order as o order by o.price asc";
		Query query = session.createQuery(hql);
		query.setFirstResult(0);
		query.setMaxResults(3);
		List<Order> list = query.list();
		for (Order order : list) {
			System.out.println(order.getOrderno() + ":" + order.getPrice());
		}
	}

 
        F)查询价格最贵的一个订单

	public void test7() {
		Session session = sessionFactory.openSession();
		String hql = "from Order as o order by o.price desc";
		Query query = session.createQuery(hql);
		query.setMaxResults(1);
		Order order = (Order) query.uniqueResult();
		System.out.println(order.getOrderno() + ":" + order.getPrice());
	}

 
        G)动态绑定参数,方式一:通过名字绑定,名字以:开头        

     

	public void test8() {
		Session session = sessionFactory.openSession();
		String hql = "from Customer c where c.name=:cname";
		Query query = session.createQuery(hql);
		query.setString("cname", "小民");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer.getName() + ":" + customer.getDes());
		}
	}

 
        H)动态绑定参数,方式二:通过占位符绑定,下标多0开始

public void test9() {
		Session session = sessionFactory.openSession();
		String hql = "from Customer c where c.name=?";
		Query query = session.createQuery(hql);
		query.setString(0, "小民");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer.getName() + ":" + customer.getDes());
		}
	}

 
        I)在映射文件中定义命名HQL查询语句
        J)查询姓"X"的,且年龄不介于20-30岁之间的客户
        K)使用投影查询,查询“XX”客户姓名,年龄,描述
        L)查询订单总数,订单总价格,最便宜订单,最昂贵订单,订单平均价格
        M)按客户分组,查询订单总价【后面oracle重点】
    SQL: 
    select     sum(price)
    from       orders
           group by   customers_id;
 
    HQL: 
    select sum(o.price) from Order o group by o.customer.id
        N)使用主查询/子查询,查询姓名为“XX”客户的订单【后面oracle重点】
    SQL: 
  select  orderno,price
  from    orders
  where   customers_id = (select id from customers where name='司马懿');
    
    HQL: 
  select  o.orderno,o.price
  from Order o
  where   o.customer.id = (select c.id from Customer c where c.name='司马懿');
    ... ...
   (4)总结常用API
 A)获取Query的方法:
    Query query = session.createQuery()
    Query query = session.getNamedQuery("findCustomerByDes");

 B)Query常用的方法,以及返回值:
    query.list(),返回List
    query.uniqueResult(),返回Object
         
*二)hibernate最常用的检索策略【立刻检索 vs 延迟检索,只争对load()方法】
   (1)根据id查询客户----get()有产生SQL  【默认检索策略是立即检索】 
   (2)根据id查询客户----hql()有产生SQL  【默认检索策略是立即检索】
   (3)根据id查询客户----load()无产生SQL 【默认检索策略是延迟检索】
    当使用load()方法时,查询id属性,也没有直正查询数据库
    当使用load()方法时,查询非id属性,这才直正查询数据库
 注意:get()/hql()只能立刻检索
       load()才有延迟检索  
       项目中,多用load()方法 
   (4)当get()/hql()
        A)使用<class lazy="false"/>检索策略是:立刻检索
        B)使用<class lazy="true(默认值)"/>检索策略是:立刻检索
   (5)当load(),测试并填表   
        参见<<load()类策略.JPG>>
        参见<<load()集合策略.JPG>>
   (6)立即检索 vs 延迟检索
        参见<<PPT第30页>>
   (7)什么情况下使用立即检索,什么情况下使用延迟检索
     A)类: 
        >>当你只需查询某个对象的引用变量,或id值的时候,其它属性暂不需要:延迟检索
        >>当你需查询某个对象的引用变量,或id值的时候,或其它非id属性:延迟检索立即检索  
     B)集合:采用延迟检索,特点是:一对多,多对多。

三)hibernate管理session一级缓存的方式
   (1)传统方式下,从SessionFactory中取出的Session,每次都不一样
   (2)session关闭后,不能再用该session操作数据库了,只能再次获取新的session对象
   (3)hibernate委托当前线程管理session对象的好处
 这样,同一条线程,只能操作惟一的一个session对象,可以节约session,提高session的利用率。
   (4)如何让hibernate委托当前线程管理session对象
         current_session_context_class=thread
   (5)如何在代码中获取当前线程所管理的session对象
  sessionFactory.getCurrentSession()
   (6) 一旦事务提交,sessionFactory.getCurrentSession()会获取新的session对象
    注意:一个方法,只做一件事;在这个方法中,只获取一个session对象即可。
   
*四)hibernate管理sessionFactory二级缓存的方式
   (1)在默认情况下,session.get(),每执行一次,都要查询数据库,效率低
   (2)启用sessionFactory二级缓存,使其能存对象,以及二级缓存的结构图
 参见<<sessionFactory结构图.JPG>>
 在默认情况下,sessionFactory二级缓存只能存储配置文件和映射文件的相关信息,
 不能存对象
        hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
   (3)将Customer类存入二级缓存
  Customer.hbm.xml文件
         <class name="Customer" table="CUSTOMERS">
    <cache usage="read-only(只读,属性值变化)或read-write(读写,属性值常变化)"/>
         </class>
   (4)将Customer类和Order集合存入二级缓存
  Customer.hbml.xml文件
         <set name="ordetSet" table="ORDERS">
    <cache usage="read-only"/>
         </set>
         Order.hbm.xml文件
         <class name="Order" table="ORDERS">
    <cache usage="read-only"/>
         </class>
   (5)get()/load()使用二级缓存中的普通缓存区
   (6)HQL使用查询缓存区,即list()/uniqueResult()使用二级缓存中的查询缓存区
         hibernate.cache.use_query_cache=true
         session.createQuery("FROM Customer c WHERE c.id=1").setCacheable(true).list();
         session.createQuery("FROM Customer c WHERE c.id=1").setCacheable(true).uniqueResult();
   (7)session.update()也会同步更新二级缓存,必须让SessionFactory中存的对象,具有write权限
 目的:用空间,去换时间,提高效率

五)hibernate使用C3P0连接池
   (1)在默认情况下,hibernate使用内置连接池,无第三方连接池使用,可以能过log4j.properties运行时显示信息查看
        Using Hibernate built-in connection pool (not for production use!)
   (2)如何使用第三方连接池C3P0呢
        hibernate.connection.provider_class=org.hibernate.connection.C3P0ConnectionProvider
        hibernate.c3p0.max_size=100,这里的连接是Connection对象
        hibernate.c3p0.min_size=10
        当连接池中的某个连接处于空闲状态的时间超过了timeout秒指定的时间,就会从连接池中清除
        hibernate.c3p0.timeout=5000
        hibernate.c3p0.max_statements=30,最多创建30个Statement对象 
 每1000秒检查所有连接池中的空闲连接
        hibernate.c3p0.idle_test_period=1000
        hibernate.c3p0.acquire_increment=5,每次找数据库要5个连接对象
   (3)当使用C3P0连接池后,hibernate就不再使用自定义的内置连接池上

六)hibernate使用事务
   (1)事务的ACID特点
 A:原子性,子操作是一个不可分割的整体,例如:转帐
        C:一致性,转帐前后,总额是一样的
 I:隔离性
 D:持久性
 
   (2)违背隔离性后,三个缺点
 A)脏读
 B)不可重复读
 C)幻读

   (3)设置事件隔离级别
        hibernate.connection.isolation=4

   (4)hibernate中隔离级别的设置,最终需要底层数据库的支持
 如果hibernate框架中,没有设置隔离级别,那么hibernate会采用数据库本身默认的隔离级别
 MySQL:repeatable read
 Oracle:read committed

七)动手练习
   【需求】
    基于hibernate框架,写一个WEB版本的分页应用
    以Customer-Order为例
    第二天讲答案

    提示:
 //从第几条记录-1开始显示
 query.setFirstResult(2);//写成变量
 //设置【最多】显示几条记录
 query.setMaxResults(2);

 对象导航的时候如果是多对一查找的话需要设置立即检索

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Hibernate)