非本人总结的笔记,抄点笔记复习复习。感谢传智博客及黑马程序猿
Hibernate的查询操作
Hibernate的查询方式概述
(1)导航对象图检索方式
根据已经加载的对象导航到其他对象
以用户和订单为例:查询出一个用户,查询这个用户的所有订单,直接得到用户的订单集合
(2)OID检索方式
按照对象的OID来检索对象
User user = (User) session.get(User.class, 2);
(3)HQL检索方式
使用面向对象的HQL查询语言
(4)QBC检索方式
使用QBC(Query By Criterial)API来检索对象,这种API封装了基于字符串形式的查询语言,提供了更加面向对象的查询语言。
(5)本地SQL检索方式
使用本地数据库的SQL查询语句
导航对象图检索方式
查询出一个用户,查询这个用户的所有订单,直接得到用户的订单集合
Customer customer = (Customer) session.get(Customer.class, 1);
Set<Orders> sets = customer.getSetOrders();
System.out.println(sets);
☆HQL检索方式(查询数据库数据--重点)
HQL VS SQL
HQL查询语句(操作实体类)
是面向对象的,Hibernate负责解析HQL语句,然后根据对象-关系映射文件中的映射信息,把HQL查询语句翻译成相应的SQL语句。HQL查询语句中的主体是域对象中的类及类的属性。
SQL查询语句
是关系数据库绑定在一起的,SQL查询语句中主体是数据库表及表的字段
HQL语句创建Query对象
调用session里面的方法 createQuery(“HQL语句”)
package cn.itcast.hibernate.test;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.itcast.entity.User;
import cn.itcast.utils.HibernateUtils;
/**
* 实现hibernate的crud的操作
*/
public class TestDemo2 {
//hql查询
@Test
public void testHQL() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
//创建query对象
Query query = session.createQuery("from User");
//调用query里面list方法返回list集合
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
}catch(Exception e) {
tx.rollback();
}finally {
session.close();
}
}
}
简单查询
查询表中所有记录
//使用Session创建Query对象
Query query = session.createQuery("from Customer");
//调用query里面的list方法
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
hql支持方法链编程
别名查询
//使用Session创建Query对象
//c.cid 不是表字段名称,而是实体类属性名称
Query query = session.createQuery("from Customer c where c.cid = 1");
排序查询
asc 升序 desc降序
//对Customer表里面的数据,按照cid进行升序排序
Query query = session.createQuery("from Customer c order by c.cid asc");
Query query = session.createQuery("from Customer c order by c.cid desc");
分页查询
查询表里的几条数据
select * from orders limit 0, 3;
0:记录开始位置
3:获取记录数
开始位置 = (当前页 - 1) * 每页记录数
//查询orders表里面的前四条记录数
Query query = session.createQuery("from orders");
//设置开始位置
query.setFirstResult(0);
//设置获取几条记录
query.setMaxResults(4);
唯一对象查询
根据对象查询这条记录。
比如根据cid查询记录,调用get方法实现,返回一条记录,应该是对象形式,使用对象接收数据
Query query = session.createQuery("from Customer c where c.cid = 2");
//使用对象接收返回数据
Customer customer = query.uniqueResult();
条件查询
第一种方式:根据参数位置传递参数值
Query query = session.createQuery("from Customer c where c.cid = ? and c.cname = ?");
//设置参数
//setParameter设置参数
//第一个参数:?位置,从0开始
//第二个参数:参数值
query.setParameter(0, 1);
query.setParameter(1, "杨过");
第二种方式:根据参数的名称传递参数值
Query query = session.createQuery("from Customer c where c.cid = :ccid and c.cname = :ccname");
//setParameter设置参数
//第一个参数:后面的名称
//第二个参数:值
query.setParameter("ccid", 2);
query.setParameter("ccname", "郭靖");
代码实现
package cn.itcast.hibernate.test;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.itcast.onetomany.Customer;
import cn.itcast.onetomany.Orders;
import cn.itcast.utils.HibernateUtils;
/**
* 演示hql操作
*/
public class HibernateHQLDemo1 {
//6.(2)根据参数名称传递参数值
@Test
public void testSelect7() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//查询cid=2并且cname=尹志平的记录
Query query =
session.createQuery("from Customer c where c.cid=:ccid and c.cname=:ccname");
//设置参数值
//setParameter有两个参数
//第一个参数 冒号:后面的名称
//第二个参数 表里具体的值
query.setParameter("ccid", 2);
query.setParameter("ccname", "尹志平");
List<Customer> list = query.list();
System.out.println(list);
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//6.(1)根据参数的位置传递参数值
@Test
public void testSelect6() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//查询cid=1 并且cname=杨过的记录
Query query =
session.createQuery("from Customer c where c.cid=? and c.cname=?");
//设置参数值
//类型通用setParameter两个参数
//******第一个参数:?位置,开始位置从 0 开始
//第二个参数:具体的参数值 表里数据值
query.setParameter(0, 1);
query.setParameter(1, "杨过");
List<Customer> list = query.list();
System.out.println(list);
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//5.唯一对象查询
@Test
public void testSelect5() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//查询cid=2的记录
Query query = session.createQuery("from Customer c where c.cid=2");
//使用对象接收返回数据
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//4.分页查询
@Test
public void testSelect4() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//查询orders表里面前四条记录
Query query = session.createQuery("from Orders");
//设置开始位置
query.setFirstResult(4);
//设置获取几条记录
query.setMaxResults(4);
List<Orders> list = query.list();
for (Orders orders : list) {
System.out.println(orders);
}
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//3.排序查询
@Test
public void testSelect3() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//对customer表里面的数据,按照cid进行升序排列
//Query query = session.createQuery("from Customer c order by c.cid asc");
//对customer表里面的数据,按照cid进行降序排列
Query query = session.createQuery("from Customer c order by c.cid desc");
//调用query里面list方法
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//2.演示别名查询
@Test
public void testSelect2() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//使用session创建query对象 c是别名
//c.cid : 不是表字段名称,而是实体类属性名称
//建议实体类属性名称与表字段名一致
Query query = session.createQuery("from Customer c where c.cid=1");
//调用query里面list方法
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//1.简单查询
//查询customer表里面的所有数据
@Test
public void testSelect1() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//使用session创建query对象 from后面是实体类名称
Query query = session.createQuery("from Customer");
//方法链编程
List<Customer> list1 = session.createQuery("from Customer").list();
//调用query里面list方法
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
}
QBC查询方式(会用)
简单查询
Criteria criteria = session.createCriteria(Customer.class);
//调用criteria的list方法
List<Customer> list = criteria.list();
排序查询
//升序
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(Order.asc("cid"));
//Order类里面的方法asc,asc里面参数是实体类属性名称
//降序
criteria.addOrder(Order.desc("cid"));
分页查询
Criteria criteria = session.createCriteria(Customer.class);
//设置开始位置
criteria.setFirstResult(0);
//设置查询记录数
criteria.setMaxResults(3);
条件查询
Criteria criteria = session.createCriteria(Customer.class);
//设置条件
criteria.add(Restrictions.gt("price", 3));
本地sql查询
SQLQuery sqlQuery = session.createSQLQuery("select * from customer");
List<Object[]> list = sqlQuery.list();
for(Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
☆HQL的多表查询
多表查询
内连接:两个表关联的数据
范例:Select * from A inner joinB on A.id=B.id;Select * from A,B whereA.id=B.id
左外连接:左边表所有的数据,右边表查关联数据
范例:Select * from A left outer join B on A.id=B.id
右外连接:右边表所有的数据,左边表查关联数据
范例:Select * from A right outer join B on A.id=B.id
Hibernate中使用HQL多表操作
内连接:inner join
迫切内连接:inner join fetch
左外连接:left outer join
迫切左外连接:left outer join fetch
右外连接 : right outer join
内连接
查询两个表关联数据,返回是list集合数组
Query query = session.createQuery("from Customer c inner join c.setOrders");
List<Object[]> list = query.list();
for(Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
返回list集合,每部分是数组的形式
迫切内连接
Query query = session.createQuery("from Customer c inner join fetch c.setOrders");
List<Customer> list = query.list();
返回list集合每部分是对象形式
左外连接
左边所有和关联数据,返回是list集合数组
Query query = session.createQuery("from Customer c left outer join c.setOrders");
List<Object[]> list = query.list();
返回list集合中,每部分是数组形式
迫切左外连接
左边所有和关联数据,返回是list集合对象
Query query = session.createQuery("from Customer c left outer join fetch c.setOrders");
List<Customer> list = query.list();
返回list集合中,每部分是对象形式
右外连接
右边所有和关联数据,返回是list集合数组
Query query = session.createQuery("from Customer c right outer join c.setOrders");
List<Cusomter[]> list = query.list();
HQL的投影查询和聚合函数
投影查询
查询一部分数据,字段下所有
第一个操作
Query query = session.createQuery("select cname from Customer");
List<Object> list = query.list();
第二个操作
Query query = session.createQuery("select cname, title from Customer");
List<Object[]> list = session.list();
for(Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
聚合函数
Query query = session.createQuery("select count(*) from Customer");
Object obj = session.uniqueResult();
Long count = (Long) obj;
int sum = count.intValue();
代码实现
package cn.itcast.hibernate.test;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;
import cn.itcast.onetomany.Customer;
import cn.itcast.onetomany.Orders;
import cn.itcast.utils.HibernateUtils;
/**
* 演示hql多表查询操作
*/
public class HibernateManyTable {
//6.(2)聚集函数使用
@Test
public void testSQL8() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//count函数
// count记录 sum 求和 avg平均数 min最小值 max最大值
Query query = session.createQuery("select count(*) from Customer");
Object obj = query.uniqueResult();
//可以获取不同类型
//变成long类型
Long count = (Long) obj;
//变成int类型
int sum = count.intValue();
System.out.println(sum);
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//6.(1)投影查询
//查询customer表里面所有cname和address的值
@Test
public void testSQL7() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//可以查询一个字段也可以查询多个字段,多个字段逗号隔开
Query query = session.createQuery("select cname,address from Customer");
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//投影查询
//查询customer表里面所有cname的值
@Test
public void testSQL6() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
Query query = session.createQuery("select cname from Customer");
List<Object> list = query.list();
System.out.println(list);
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//5.右外连接查询
@Test
public void testSQL5() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
Query query = session.createQuery("from Customer c right outer join c.setOrders");
List<Object[]> list = query.list();
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//4.迫切左外连接查询
@Test
public void testSQL4() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
Query query = session.createQuery("from Customer c left outer join fetch c.setOrders");
//加入fetch 返回list集合每部分结构是对象
List list = query.list();
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//3.左外连接查询
@Test
public void testSQL3() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
Query query = session.createQuery("from Customer c left outer join c.setOrders");
//返回list集合每部分结构是数组
List<Object[]> list = query.list();
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//2.迫切内连接查询
@Test
public void testSQL2() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//只是在代码中加入fetch
Query query = session.createQuery("from Customer c inner join fetch c.setOrders");
List<Customer> list = query.list();
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//1.内连接查询
@Test
public void testSQL1() {
Session session = null;
Transaction tx = null;
try {
//获取到session
session = HibernateUtils.getSession();
//开启事务
tx = session.beginTransaction();
//from Customer c inner join c.setOrders
//Customer表与orders表关联部分 后面是写的Customer表的set集合名称
Query query = session.createQuery("from Customer c inner join c.setOrders");
//返回list集合每部分是数组
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
}
Hibernate的检索策略
概念
Hibernate的检索策略分为两部分
立即检索
调用方法的时候马上发送语句查询数据库 get
延迟检索
调用方法的时候不会马上发送语句查询数据库,得到返回对象中的值时候才会查询数据库 load
Hibernate中延迟检索分为两部分
类级别延迟
如果根据oid查询对象,使用get方法立即查询,但是load方法不会马上查询数据
Customer customer = (Customer) session.load(Customer.class, 1);//不会发送语句
System.out.println(customer.getCid());//不发送语句
System.out.println(customer.getCname());//发送语句
让load方法执行之后,也会立刻发送语句查询数据库,实现和ge相同的效果,class标签上面,属性lazy默认值是true
<class name="cn.xxx.Customer" table="Customer" lazy="false">
</class>
关联级别延迟
比如查询出一个用户,再查询这个用户的所有的订单
以用户和订单为例,演示关联级别的延迟
在用户那一端,有set标签
在订单那一端,有many-to-one标签
在set标签配置--关联级别延迟
在set标签上面有两个属性fetch和lazy
fetch的取值:控制sql语句的生成格式
值 | 说明 |
---|---|
select | 默认发送查询语句 |
join | 连接查询,发送的是一条迫切左外连接,配置了join,lazy就失效了 |
subselect | 子查询,发送一条子查询查询其关联对象,(必须使用list方法进行测试) |
lazy的取值:查找关联对象的时候是否采用延迟
取值 | 说明 |
---|---|
true | 默认延迟 |
false | 不延迟 |
extra | 极其懒惰 |
fetch和lazy的值使用不同的组合实现不同的优化方式
默认值fetch是select,lazy是true
第一种情况:fetch值是join,lazy值是true、false、extra
如果fetch值是join,lazy无论值是什么,做的都是左外连接操作
<set name="setOrders" cascade="save-update" fetch="join" lazy="true"></set>
第二种情况:fetch值是select,lazy值是true、false、extra
<set name="setOrders" cascade="save-update" fetch="select" lazy="true"></set>
要进行延迟
Customer customer = (Customer) session.get(Customer.class, 1);
Set<Orders> sets = customer.getSetOrders();
System.out.println(sets.size());
获取到set集合的时候,不会马上发送sql语句,而得到集合的内容时候才会发送sql语句
<set name="setOrders" cascade="save-update" fetch="select" lazy="false"></set>
一次性把所有的查询操作都执行,不进行延迟
<set name="setOrders" cascade="save-update" fetch="select" lazy="extra"></set>
把需要的数据返回,不需要的不给
第三种情况:fetch值是subselect,lazy值是true、false、extra
<set name="setOrders" cascade="save-update" fetch="subselect" lazy="true"></set>
进行延迟
<set name="setOrders" cascade="save-update" fetch="subselect" lazy="false"></set>
不进行延迟
<set name="setOrders" cascade="save-update" fetch="subselect" lazy="extra"></set>
极其延迟
在many-to-one配置--关联级别延迟
有两个属性fetch和lazy
fetch有两个值join、select
lazy常用两个值false、proxy
默认值fetch是select、lazy是proxy
第一种情况:fetch值是join,lazy值是false和proxy
做左外连接操作
第二种情况:fetch值是select,lazy值是false和proxy
一次性把所有数据都查出来
和对端配置有关联,配置是否要延迟
<class name="cn.xx.Customer" table="Customer" lazy="false"></class>
Hibernate的事物
概念
- Hibernate事务默认不是自动提交的
- 事务四个特性:原子性、一致性、隔离性、持久性
- 不考虑事务隔离性产生三个都问题
- 脏读:一个事务读到另一个事物没有提交的数据
- 不可重复读:一个事务读到另一个事务update操作
- 虚读:一个事务读到另一个事务insert操作
- 解决都问题:设置隔离级别
- mysql默认隔离级别:repeatable read
- 不考虑事务隔离性产生一类问题,写问题(丢失更新)
Hibernate配置事务隔离级别
在Hibernate核心配置文件中配置
hibernate.connection.isolation = 4
name属性值 | 数字值 |
---|---|
Readuncommitted isolation | 1 |
Readcommitted isolation | 2 |
Repeatableread isolation | 4 |
�Serializable isolation | 8 |
<!-- 配置事务隔离级别 -->
<property name="hibernate.connection.isolation">4</property>
丢失更新
什么是丢失更新
如果不考虑事务隔离性,产生一类写问题,这类写的问题成为丢失更新
有两个事务同时对一个记录进行操作
第一种情况:
第一个事务修改了内容之后提交了,第二个事务回滚操作。一个事务回滚了另一个事务内容
第二种情况:
第一个事务修改内容提交了,第二个事务修改内容,也提交了。一个事务覆盖另一个事务内容
解决丢失更新
第一种方式:使用悲观锁
一个事务在操作事务的时候,对这条记录加锁,其他事务不能操作这条记录了,只有当前事务提交之后,其他事务才可以操作,效率低下。
第二种方式:使用乐观锁
使用版本号控制,有两个事务同时操作同一条记录。在记录里面添加版本号信息,默认是0。
如果a事务,修改数据,提交事务,提交之前把记录的版本号修改为1,完成提交
如果b事务,修改数据,提交事务之前,比较当前数据的版本号和数据库里面的最新的版本号是否一致,如果不相同不更新数据库
Hibernate解决丢失更新
实现步骤:
第一步:
在实体类中添加属性,作为版本号的属性
public class Customer {
private Integer cid;
private String cname;
private String address;
private Integer version;
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
}
第二步:
在实体类的映射文件中配置
<id name="cid" column="CID">
<generator class="native"></generator>
</id>
<!-- 版本号 -->
<version name="version"></version>
version标签要在id标签下面