Hibernate--day03

非本人总结的笔记,抄点笔记复习复习。感谢传智博客及黑马程序猿


记笔记啊记笔记

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>
SQL语句

第二种情况: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>

把需要的数据返回,不需要的不给

sql语句

第三种情况: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的事物

概念

  1. Hibernate事务默认不是自动提交的
  2. 事务四个特性:原子性、一致性、隔离性、持久性
  3. 不考虑事务隔离性产生三个都问题
    1. 脏读:一个事务读到另一个事物没有提交的数据
    2. 不可重复读:一个事务读到另一个事务update操作
    3. 虚读:一个事务读到另一个事务insert操作
  4. 解决都问题:设置隔离级别
  5. mysql默认隔离级别:repeatable read
  6. 不考虑事务隔离性产生一类问题,写问题(丢失更新)

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标签下面

推荐阅读更多精彩内容