Hibernate 事物
Hibernate是对JDBC的轻量封装,主要功能是操作数据库。
Hibernate中的事物管理
在Hibernate中,可以通过API接口来操作管理事物。可以通过session.beginTransaction()开启一个事物,持久化操作后,通过commit()提交事物。如果事物异常,通过rollback()来进行事物的回滚。
除了在代码中对事物开启,提交和回滚操作外,还可以在Hibernate的配置文件中对事物进行配置。配置文件中,可以设置事物的隔离级别。
- 在hibernate.cfg.xml文件中的<session-factory>标签元素中进行配置
<!--配置数据库隔离级别
0001 1 读未提交
0010 2 读已提交
0100 4 可重复读
1000 8 串行
-->
<property name="hibernate.connection.isolation ">4</property>
基本点:在项目中如何管理事物:
在项目中,通过经验我们有一个基本的认识:
在业务开始之前打开事物,在业务执行之后提交事物,执行过程中如果出现异常,则回滚事物
- 在dao层操作数据库的时候需要用到session对象,在service控制事物也是使用session对象完成,所以我们要确保dao层和service层使用的是同一个session对象
注意1:调用getCurrentSession方法必须配合主配置中的一段配置
<!--指定session与当前线程绑定-->
<property name="current_session_context_class">thread</property>
注意2:通过getCurrentSession方法获得的Session对象,当事物提交时,session会自动关闭,不需要手动调用close关闭,session会自动被回收
Hibernate 查询API
HQL查询
HQL(Hibernate Query Language) 是面向对象的查询语言。使用的是类、对象和属性的概念。没有表和字段的概念。Hibernate提供的Query接口是专门的HQL查询接口,能够执行各种复杂的HQL查询语句。
由于HQL是面向对象的,所以不会出现和表名列名有关的语句。应该使用的是对象名 属性名
- 完整的HQL语句
select...from...where...group...by...having...order by...asc/desc
当检索数据表中的所有记录时,查询语句中可以省略select关键字
获得Hibernate的Session对象
编写HQL语句
调用session.createQuery 创建查询对象
通过Query的setXxx设置参数
调用Query对象的list()或uniqueResult()执行查询
查询所有记录
//编写HQL语句
String hql = "from cn.probuing.domain.Customer";
//根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//根据查询对象获得
List<Customer> list = query.list();//返回list
排序查询
/**
* 排序语法
*/
@Test
public void HQLSort(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
String hql = "from cn.probuing.domain.Customer order by cust_id desc";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
System.out.println(list);
tx.commit();
session.close();
}
根据条件进行查询
/**
* 条件查询
*/
@Test
public void HQLCondition(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// String hql = "from cn.probuing.domain.Customer order where cust_id=?";
String hql2 = "from cn.probuing.domain.Customer order where cust_id=:id";//另一种写法
Query query = session.createQuery(hql2);
//设置占位符
// query.setParameter(0,2);
//另一种占位符写法
query.setParameter("id",2);
List<Customer> list = query.list();
System.out.println(list);
tx.commit();
session.close();
}
分页查询
/**
* 分页查询
*/
@Test
public void HQLPage(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// String hql = "from cn.probuing.domain.Customer order where cust_id=?";
String hql2 = "from cn.probuing.domain.Customer";//另一种写法
Query query = session.createQuery(hql2);
//表示从0条开始
query.setFirstResult(0);
//表示查找2条
query.setMaxResults(2);
List<Customer> list = query.list();
System.out.println(list);
tx.commit();
session.close();
}
聚合函数
/**
* 聚合函数
*/
@Test
public void HQLCount() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// String hql = "from cn.probuing.domain.Customer order where cust_id=?";
String hql2 = "select count(*) from cn.probuing.domain.Customer";
//求和 指定列名
String hql3 = "select sum(cust_id) from cn.probuing.domain.Customer";
String hql4 = "select avg(cust_id) from cn.probuing.domain.Customer";
String hql5 = "select max(cust_id) from cn.probuing.domain.Customer";
String hql6 = "select min(cust_id) from cn.probuing.domain.Customer";
Query query = session.createQuery(hql4);
Number number = (Number) query.uniqueResult();
System.out.println(number);
tx.commit();
session.close();
}
投影查询
查询对象的某一个属性
@Test
public void testHQLDemo2() {
Session session = HibernateUtils.openSession();
//开启事物
Transaction transaction = session.beginTransaction();
//编写HQL语句
// String hql = "from cn.probuing.domain.Customer where cust_id =? ";
String hql = "from cn.probuing.domain.Customer where cust_id = :cust_id ";
//根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数 指定类型
// query.setLong(0,1l);
//设置参数 不指定参数
// query.setParameter(0,1l);
//根据参数名设置参数
query.setParameter("cust_id", 1l);
//根据查询对象获得
Customer customer = (Customer) query.uniqueResult();//接收唯一的查询结果
System.out.println(customer.toString());
//提交事物,关闭资源
transaction.commit();
session.close();
}
在指定条件时有以下几个方法:
- 指定参数需要使用setXxx()指定类型
- 不指定参数需要使用setParameter(占位符索引,值)
- 根据名称指定条件值 setparameter(名称,值)
分页查询
hql语句中没有limit(?,?)这样的语句,需要使用API方法来实现分页的功能
- setFirstResult() 设置起始的位置
- setMaxResult() 设置最大的条数
public void testHQLDemo3() {
Session session = HibernateUtils.openSession();
//开启事物
Transaction transaction = session.beginTransaction();
String hql = "from cn.probuing.domain.Customer ";
//根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置起始信息
query.setFirstResult(0);
//设置最大条数
query.setMaxResults(2);
//根据查询对象获得
List<Customer> list = query.list();
System.out.println(list.toString());
//提交事物,关闭资源
transaction.commit();
session.close();
}
Criteria查询
Criteria是一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何实现,以及SQL语句如何编写。Criteria查询又称为QBC查询。它是Hibernate的另一种对象检索方式
org.hibernate.criterion.Criterion是Hibernate提供的一个面向对象查询条件接口。一个单独的查询就是Criterion接口的一个实例。用于限制Criteria对象的查询。在Hibernate中Criterion对象的创建时通过Restriction工厂类完成
主要步骤:
(1) 获得Hibernate的Session对象
(2) 通过Session获得Criteria对象
(3) 使用Restriction的静态方法创建Criterion条件对象。Restrictions类中提供了一系列用于设定查询条件的静态方法
(4) 向Criteria对象中添加Criterion查询条件
基本查询
//获得session
Session session = HibernateUtils.openSession();
//通过session获得Criteria对象 参数表示指定查询所有的Customer对象
Criteria criteria = session.createCriteria(Customer.class);
//使用Restrictions对象进行查询 返回集合
List<Customer> list = criteria.list();
//返回单个结果
// Customer customer = (Customer) criteria.uniqueResult();
System.out.println(list.toString());
条件查询
@Test
public void testHQLDemo4() {
//获得session
Session session = HibernateUtils.openSession();
//通过session获得Criteria对象 参数表示指定查询所有的Customer对象
Criteria criteria = session.createCriteria(Customer.class);
//调用add方法添加参数 => 查询cust_id 为1的Customer对象
criteria.add(Restrictions.eq("cust_id", 1l));
// 条件:>
//使用Restrictions对象进行查询 返回集合
// List<Customer> list = criteria.list();
//返回单个结果
Customer customer = (Customer) criteria.uniqueResult();
System.out.println(customer.toString());
session.close();
}
对应条件API:
分页查询
/**
* Criteria 查询
*/
@Test
public void testHQLDemo4() {
//获得session
Session session = HibernateUtils.openSession();
//通过session获得Criteria对象 参数表示指定查询所有的Customer对象
Criteria criteria = session.createCriteria(Customer.class);
//指定起始
criteria.setFirstResult(0);
criteria.setMaxResults(2);
// 使用Restrictions对象进行查询 返回集合
List<Customer> list = criteria.list();
System.out.println(list.toString());
session.close();
}
查询总记录数
@Test
public void testHQLDemo4() {
//获得session
Session session = HibernateUtils.openSession();
//通过session获得Criteria对象 参数表示指定查询所有的Customer对象
Criteria criteria = session.createCriteria(Customer.class);
//设置查询的聚合函数
criteria.setProjection(Projections.rowCount());
Long result = (Long) criteria.uniqueResult();
System.out.println(result);
session.close();
}
排序查询
@Test
public void BaseCriteriaOrder() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//操作数据
//创建criteria
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(Order.asc("cust_id"));
// criteria.addOrder(Order.desc("cust_id"));
List list = criteria.list();
System.out.println(list);
tx.commit();
session.close();
}
原生SQL查询
普通查询
@Test
public void sqlQuery() {
Session session = HibernateUtils.openSession();
//开启事物
Transaction tx = session.beginTransaction();
//书写SQL语句
String sql = "select * from cst_customer";
//创建查询对象
SQLQuery query = session.createSQLQuery(sql);
//封装对象:将结果集指定封装对象
query.addEntity(Customer.class);
//查询结果 接收封装对象集合
// List<Customer> list = query.list();
//查询结果 未指定封装对象
List<Object[]> list = query.list();
System.out.println(list.toString());
tx.commit();
session.close();
}
条件查询
@Test
public void sqlQuery() {
Session session = HibernateUtils.openSession();
//开启事物
Transaction tx = session.beginTransaction();
//书写SQL语句
String sql = "select * from cst_customer where cust_id = ?";
//创建查询对象
SQLQuery query = session.createSQLQuery(sql);
//设置参数
query.setParameter(0, 1);
//指定封装对象
query.addEntity(Customer.class);
List<Customer> list = query.list();
System.out.println(list.toString());
tx.commit();
session.close();
}
分页查询
public void sqlQuery() {
Session session = HibernateUtils.openSession();
//开启事物
Transaction tx = session.beginTransaction();
//书写SQL语句
String sql = "select * from cst_customer limit ?,? ";
//创建查询对象
SQLQuery query = session.createSQLQuery(sql);
//设置条件参数
query.setParameter(0, 0);
query.setParameter(1,1);
//封装对象:将结果集指定封装对象
query.addEntity(Customer.class);
//查询结果 接收封装对象集合
List<Customer> list = query.list();
//查询结果 未指定封装对象
// List<Object[]> list = query.list();
System.out.println(list.toString());
tx.commit();
session.close();
}
离线查询
DetachedCriteria翻译为离线条件查询,它可以脱离session来使用的一种条件查询对象
-
传统的查询方式过于依赖session对象。减少参数的传递。
使用离线查询思路为:
在web层或者service层不依赖session创建查询对象Criteria。并设置好条件等相关参数
传递Criteria对象到Dao层
Dao层将离线的Criteria对象与session关联。关联后会将离线的Criteria对象转换为普通的Criteria对象。
通过普通的Criteria对象执行数据操作
实例代码
@Test
public void fun1() {
//模拟service层或web层
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
//拼装好条件
detachedCriteria.add(Restrictions.idEq(2l));
//dao层
Session session = HibernateUtils.openSession();
//离线对象关联session 关联session后 就会由离线的Criteria对象变为普通的Criteria对象
Criteria c = detachedCriteria.getExecutableCriteria(session);
//执行查询
List<Customer> list = c.list();
System.out.println(list);
}
查询优化
类级别查询优化
延迟加载
类级别的延迟指的是查询某个对象的时候,是否采用有延迟。通常在<class>标签上配置lazy属性,lazy属性的默认值是true
- lazy:true 加载时,不查询,使用时才查询
- lazy:false 加载时立即查询
<class name="Customer" table="cst_customer" lazy="true">
- load方法 在执行时不发送任何sql语句,返回一个对象,使用该对象时,才执行查询
Customer c = session.load(Customer.class,2l);
原理解释
在加载时,返回的是代理对象 代理对象会在使用对象属性时,根据关联的session查询数据库,加载数据
注意 使用懒加载时要确保,调用属性加载数据时,session是打开的 还没有关闭。否则会抛出异常
关联级别查询优化
关联级别查询优化
关联级别就是指对象的关联属性,分为两种:集合级别的关联。对象级别的关联
集合级别的关联策略
- lazy:延迟加载
lazy属性:延迟加载
true:默认值 延迟加载
false:立即加载
extra:极其懒惰 与懒加载效果基本一致,如果只获得集合的size,只查询集合的size(count语句) -
fetch:抓取策略
fetch属性:决定加载策略,使用什么类型的sql语句加载集合数据
select:单表查询加载
join:使用多表查询加载集合 此种情况下 lazy属性失效 相当于立即加载 多表数据会直接全部加载
subselect:使用子查询加载集合
对象属性级别的关联策略
主要作用于<many-to-one>
- lazy
- false: 立即加载
- proxy: 代理加载 由指定的代理决定加载策略
- fetch
- select: 使用单表查询
-
join: 使用多表查询
我们总结来说就是:fetch主要控制抓取关联对象的时候发送SQL语句的格式的lazy主要控制查询其关联对象的时候是否采用延迟加载的
为了提高效率:fetch的选择应该选择select lazy的取值应该选择true
批量抓取
<!--
batch-size:抓取集合的数量为3
-->
<set name="linkMens" inverse="true" batch-size="3">