Hibernate基础知识(三)

Hibernate_day03总结

今日内容

Hibernate的检索方式

Hibernate的抓取策略

Hibernate批量检索

事务的并发问题

Hibernate的二级缓存

Hibernate的查询缓存

1.1 上次课内容回顾:

1.Hibernate一级缓存:

* 缓存:优化手段.

* Hibernate中两个基本缓存:

* 一级缓存:session的生命周期一致.

* 二级缓存:sessionFactory的生命周期一致.

* 证明一级缓存的存在:

* session的生命周期开始

* 查询了一下Book.//发送SQL去查询

* 查询了一个Book.//不发送SQL.

* session的生命周期结束

 

* 一级缓存的管理:

* clear();

* evict(Object obj);

* flush();

* refresh(Object obj);

 

* 一级缓存的刷出时机:

* ALWAYS:

* AUTO:默认值

* COMMIT:事务提交/session.flush()时候

* MANUAL:手动调用session.flush()刷出缓存

 

* 持久化对象的操作的常用方法:

2.Hibernate为了管理持久化对象:

* 将持久化对象分成三种状态:

* 瞬时态:

* 没有唯一标识OID,且没有与session关联.

* 持久态:

* 有唯一的标识OID,且与session关联.

* 脱管态:

* 有唯一的标识OID,没有与session关联.

 

* 瞬时态对象:

* Book book = new Book();

* 瞬时-->持久:

* save()/saveOrUpdate();

* 瞬时-->脱管:

* book.setBid(1);

* 持久态对象:

* get()/load()/find()/lock();

* 持久态-->瞬时:

* delete();

* 持久态-->脱管:

* close()/clear()/evict();

* 脱管态对象:

* Book book = new Book();

* book.setBid(1);

* 脱管-->瞬时:

* book.setBid(null);

* 脱管-->持久:

* update();/saveOrUpdate();

 

3.Hibernate的关联关系配置:

* 一对多:

* 多对多:

* 一对一:

 

一对多:

* 实体:

private class Customer{

private Set<Order> orders = new HashSet<Order>;

}

 

private class Order{

private Customer customer;

}

* 映射文件:

* 在多的一方Order.hbm.xml

<many-to-one />

 

* 在一的一方Customer.hbm.xml

<set>

<key />

<one-to-many />

</set>

 

* cascade:级联操作:

* save-update:

* delete

* all

* delete-orphan

* all-delete-orphan

* inverse:放弃外键维护权

* 通常在一的一方放弃.

 

多对多:

实体:

private class Student{

private Set<Course> courses = new HashSet<Course>();

}

 

private class Course{

private Set<Student> students = new HashSet<Student>();

}

 

映射文件:

在多对多的双方需要配置:

<set>

<key />

<many-to-many />

</set>

***** 保存多对多双方的时候,需要有一方放弃外键维护权.

 

1.2 Hibernate的检索方式:

1.2.1 Hibernate的检索方式:

检索方式:查询的方式:

导航对象图检索方式:  根据已经加载的对象导航到其他对象

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

* customer.getOrders();// 获得到客户的订单

OID 检索方式:  按照对象的 OID 来检索对象

* get()/load();方法进行检索.

HQL 检索方式: 使用面向对象的 HQL 查询语言

* Query query = session.createQuery(HQL);

QBC 检索方式: 使用 QBC(Query By Criteria) API 来检索对象. 这种 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口.

* Criteria criteria = session.createCriteria(Customer.class);

本地 SQL 检索方式: 使用本地数据库的 SQL 查询语句

* SQLQuery query = session.createSQLQuery(SQL);

1.2.2 HQL:

HQL:Hibernate Query Language:

* 特点:

* 面向对象的查询:

* 支持方法链编程:

* 使用:

1.创建Query接口.

 

1.查询所有记录:

List<Customer> list = session.createQuery("from Customer").list();

for (Customer customer : list) {

System.out.println(customer);

}

 

2.查询使用别名:

// 使用别名

// 别名as可以省略

/*  List<Customer> list =

  session.createQuery("from Customer  c").list();

  System.out.println(list);*/

 

 

// 使用别名:带参数

/*List<Customer> list = session

.createQuery("from Customer as c where c.cname = ?")

.setString(0, "小沈").list();

System.out.println(list);*/

// 不支持 select * from Customer写法.可以写成 select 别名 from Customer as 别名;

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

System.out.println(list);

 

3.排序:

List<Customer> list = session.createQuery(

"from Customer c order by c.id desc").list();

for (Customer customer : list) {

System.out.println(customer);

}

 

4.分页查询:

Query query = session.createQuery("from Order");

query.setFirstResult(20);

query.setMaxResults(10);

List<Order> list = query.list();

for (Order order : list) {

System.out.println(order);

}

 

5.单个对象查询:

Customer customer = (Customer) session

.createQuery("from Customer where cname = ?")

.setString(0, "小明").uniqueResult();

System.out.println(customer);

 

6.参数绑定:

// 1.使用?号方式绑定

/*Query query = session.createQuery("from Customer where cname = ?");

query.setString(0, "小沈");

List<Customer> list = query.list();

System.out.println(list);*/

/*Query query = session.createQuery("from Customer where cname = ? and cid =?");

query.setString(0, "小沈");

query.setInteger(1,3);

List<Customer> list = query.list();

System.out.println(list);*/

// 2.使用名称的方式绑定

Query query = session.createQuery("from Customer where cname=:name and cid=:id");

query.setString("name", "小沈");

query.setInteger("id", 3);

List<Customer> list = query.list();

System.out.println(list);

 

// 3.绑定实体

List<Order> list = session

.createQuery("from Order o where o.customer = ?")

.setEntity(0, customer).list();

for (Order order : list) {

System.out.println(order);

}

 

7.投影操作:

// 查询客户的名称:

/*

 * List<Object> list = session.createQuery(

 * "select c.cname from Customer c").list(); System.out.println(list);

 */

 

/*

 * List<Object[]> list = session.createQuery(

 * "select c.cid,c.cname from Customer c").list(); for (Object[] objects

 * : list) { System.out.println(Arrays.toString(objects)); }

 */

 

List<Customer> list = session.createQuery(

"select new Customer(cname) from Customer").list();

System.out.println(list);

 

8.模糊查询:

Query query = session.createQuery("from Customer where cname like ?");

query.setParameter(0, "%");

List<Customer> list = query.list();

System.out.println(list);

 

SQL多表查询:

* 连接:

* 交叉连接:

* select * from A,B;

* 内连接:查询的是两个表的交集!

* select * from A inner join B on A.字段 = B.字段;

* 隐式内连接:

* select * from A,B where A.字段 = B.字段;

* 外连接:

* 左外连接:

* select * from A left outer join B on  A.字段 = B.字段;

* 右外连接:

* select * from A right outer join B on A.字段 = B.字段;

 

HQL多表的查询:

* 连接:

* 交叉连接:

* 内连接:

* 隐式内连接:

* 迫切内连接:

* 左外连接:

* 迫切左外连接:

* 右外连接:

 

* HQL的内连接和迫切内连接区别:

* 内连接查询 :将数据封装一个List<Object[]>.

* 迫切内连接 :将数据封装一个List<Customer>.但是迫切内连接,得到会有重复记录 ,需要使用distinct排重.

1.2.3 QBC:

1.查询所有记录:

List<Customer> list = session.createCriteria(Customer.class).list();

for (Customer customer : list) {

System.out.println(customer);

}

 

2.排序:

List<Customer> list = session.createCriteria(Customer.class)

.addOrder(org.hibernate.criterion.Order.desc("id")).list();

for (Customer customer : list) {

System.out.println(customer);

}

 

3.分页:

Criteria criteria = session.createCriteria(Order.class);

criteria.setFirstResult(10);

criteria.setMaxResults(10);

List<Order> list = criteria.list();

for (Order order : list) {

System.out.println(order);

}

 

4.获取单个对象:

Customer customer = (Customer) session.createCriteria(Customer.class)

.add(Restrictions.eq("cname", "小明")).uniqueResult();

System.out.println(customer);

 

5.带参数的查询:

/*

 * List<Customer> list = session.createCriteria(Customer.class)

 * .add(Restrictions.eq("cname", "小明")).list();

 * System.out.println(list);

 */

 

List<Customer> list = session.createCriteria(Customer.class)

.add(Restrictions.eq("cname", "小明"))

.add(Restrictions.eq("cid", 2)).list();

System.out.println(list);

 

6.模糊查询:

Criteria criteria = session.createCriteria(Customer.class);

criteria.add(Restrictions.like("cname", "%"));

List<Customer> list = criteria.list();

System.out.println(list);

 

 

1.2.4 SQL:

1.SQL语句查询所有记录:

List<Object[]> list = session.createSQLQuery("select * from customer").list();

for (Object[] objects : list) {

System.out.println(Arrays.toString(objects));

}

 

List<Customer> list = session.createSQLQuery("select * from customer")

.addEntity(Customer.class).list();

for (Customer customer : list) {

System.out.println(customer);

}

 

1.3 Hibernate的抓取策略

1.3.1 区分延迟和立即检索:

立即检索:

* 当执行某行代码的时候,马上发出SQL语句进行查询.

* get()

延迟检索:

* 当执行某行代码的时候,不会马上发出SQL语句进行查询.当真正使用这个对象的时候才会发送SQL语句.

* load();

 

 

类级别检索和关联级别检索:

* 类级别的检索:

* class>标签上配置lazy

* 关联级别的检索:

* <set>/<many-to-one>上面的lazy.

 

* 查询某个对象的时候,是否需要查询关联对象?

* 查询关联对象的时候是否采用延迟检索?

 

从一的一方关联多的一方:

* <set>

* fetch:控制sql语句的类型

* join:发送迫切左外连接的SQL查询关联对象.fetch=join那么lazy被忽略了.

* select:默认值,发送多条SQL查询关联对象.

* subselect:发送子查询查询关联对象.(需要使用Query接口测试)

 

* lazy:控制关联对象的检索是否采用延迟.

* true:默认值, 查询关联对象的时候使用延迟检索

* false:查询关联对象的时候不使用延迟检索.

* extra:及其懒惰.

 

***** 如果fetchjoin的情况,lazy属性将会忽略.

 

在多的一方关联一的一方:

* <many-to-one>

* fetch:控制SQL语句发送格式

* join:发送一个迫切左外连接查询关联对象.fetch=join,lay属性会被忽略.

* select:发送多条SQL检索关联对象.

* lazy:关联对象检索的时候,是否采用延迟

* false:不延迟

* proxy:使用代理.检索订单额时候,是否马上检索客户 由Customer对象的映射文件中<class>lazy属性来决定.

* no-proxy:不使用代理

 

1.4 Hibernate的事务处理:

事务:

* 事务就是逻辑上的一组操作,要么全都成功,要么全都失败!!!

 

事务特性:

* 原子性:事务一组操作不可分割.

* 一致性:事务的执行前后,数据完整性要保持一致.

* 隔离性:一个事务在执行的过程中不应该受到其他事务的干扰.

* 持久性:一旦事务结束,数据就永久保存数据库.

 

如果不考虑事务的隔离性引发一些安全性问题:

* 5大类问题:3类读问题 2类写问题.

* 读问题:

* 脏读:一个事务读到另一个事务未提交数据.

* 不可重复读:一个事务读到另一个事务已经提交数据(update),导致查询结果不一致.

* 虚读:一个事务读到另一个事务已经提交的数据(insert),导致查询结果不一致

 

* 避免三种读的问题:

* 设置事务的隔离级别:

* 未提交读:以上三种读问题 都有可能发生.

* 已提交读:避免脏读,但是不可重复读和虚读有可能发生.

* 重复读:避免脏读和不可重复读,但是虚读是有可能发生.

* 串行的:可以避免以上三种读问题.

 

* Hibernate中设置事务的隔离级别:

* 在核心配置文件中:

<property name="hibernate.connection.isolation">4</property>

 

* 写问题:丢失更新

* 解决;

* 悲观锁:

*

* 乐观锁;

*

 

线程绑定的session:

* Hibernate.cfg.xml中配置一个:

<property name="hibernate.current_session_context_class">thread</property>

* 使用SessionFactory中的getCurrentSession();方法.

* 底层就是ThreadLocal.

 

***** 当前线程中的session不需要进行关闭,线程结束后自动关闭!!!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章