*一)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);
对象导航的时候如果是多对一查找的话需要设置立即检索