Java学习笔记Java学习笔记

Hibernate框架(第二天笔记)

2018-03-06  本文已影响15人  04999b3feda6

第一天重点回顾

  1. HIbernate的开发环境的搭建

    1. 建包
    2. 导入jar包
    3. 编写JavaBean实体类
  2. 创建类与表结构的映射文件

    1. 在JavaBean所在包下创建xml映射文件 (命名规范:实体类.hbm.xml)
    2. 引入约束
    3. 配置
      • 设置实体类的全路径名和对应的数据库表名(class)
      • 设置主键id,class属性一般选择native(Mysql自增长 orcale序列化)
      • 设置其余属性的映射(property)
  3. 编写hibernate的核心配置文件

    1. 在src目录下创建核心配置文件 hibernate.cfg.xml

    2. 引入约束

    3. 配置

      • 配置数据库连接信息
      • 配置方言
      • 配置数据库连接池(hibernate的连接池性能不好)
      • 配置其他项
        (1) 显示sql语句
        (2) 格式化
        (3) hibernate.hbm2ddl.auto (4个值 一般用update)
      • 指定映射文件
    4. session的几个常用方法(增删改查)


Hibernate框架(第二天)

Hibernate 的持久化类和对象标识符

  1. 持久化类:可以永久的存储到数据库中的类(一个java类与数据库表建立了映射关系)

  2. 持久化类的编写规范

    • 要有无参构造(hibernate底层需要使用反射生成类的实例)
    • 持久化类的属性需要私有,对私有属性提供get和set方法(hibernate底层会对查询到的数据进行封装)
    • 持久化的类属性尽量使用包装类的类型
    • 尽量不要使用final进行修饰
    • 一般都需要实现Serializable接口
  3. Hibernate 中的对象标识符OID

OID是hibernate用于的是区分两个对象是否是同一个对象的标记
虚拟机内存区分两个对象看的是内存地址是否一致。数据库区分两个对象,靠的是主键。hibernate负责把内存中的对象持久化到数据库中靠的就是对象标识符来区分两个对象是否是同一个。实体类中映射主键的字段就是OID.

    /** 测试OID的作用 
      * 准备工作:去掉主键生成策略,我们自己来指定主键 
      */
     @Test
      public void test(){
    //创建两个实体类对象,并且设置相同的id和name属性
    Customer customer1 = new Customer();
    customer1.setCustId(9L);
    customer1.setCustName("阿里巴巴");      
    Customer customer2 = new Customer();
    customer2.setCustId(9L);
    customer2.setCustName("阿里巴巴");
    Session session = HibernateUtils.openSession();
    //开启事务
    Transaction tx = session.beginTransaction();
    //调用方法
    session.save(customer1);
    session.save(customer2);
    //提交事务
    tx.commit();
    //释放资源
    session.close();    
      }
    }

运行时后台会报异常,原因是:在Hibernate内存里不允许出现两个不一致的对象有着相同的OID

  1. Hibernate 的主键生成策略

(1). 当主键生成策略为native时,我们创建对象时不需要指定对象的OID的值,就可以保存,因为可以采用自增或者序列化的方式来维护主键
(2).当主键生成策略为identity时,表示采用自增的方式来维护主键。适合MySql、SqlServer数据库。同样的,我们在创建实体类时也不需要指定OID的值。
(3).当主键生成策略为sequence时,表示采用序列的方式来维护主键。适合Oracle数据库。同样的,我们在创建实体类时也不需要指定OID的值。
(4).当主键生成策略为assigned时,表示由我们程序员自己来维护主键。在创建对象时,需要我们手动的为OID设置一个值。当没有为id标签指定generator时,默认就是assigned.
(5).当主键生成策略为increment时,Hibernate会在插入数据之前,先查询表中主键的最大值,然后把主键的最大值+1,作为这一次的主键插入到表中。不适合集群的情况。increment和identity的区别是:increment是由Hibernate框架来为维护主键,每次查询主键的最大值,再加1作为这一次插入的主键;而identity是由数据库自身来维护,mysql自身就具备自增的能力。
(6).当主键生成策略为uuid时,表示采用UUID算法来随机生成一个32位的字符串作为主键。一般不用,因为字符串类型的主键比整数类型的主键占用更多的空间。

Hibernate 的一级缓存和对象状态

  1. HIbernate的一级缓存

hibernate的一级缓存就是指session缓存.
hibernate的一级缓存的作用就是减少对数据库的访问次数

hibernate的一级缓存特点:
- 当应用程序调用Session接口的save()、update()、saveOrUpdate时,如果Session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。
- 当调用Session接口的load()、get()方法,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。
- 当调用Session的close()方法时,Session缓存会被清空。

  1. 测试Hibernate的一级缓存

下面通过代码来验证Hibernate的一级缓存确实是存在的:先查询OID为2的客户,再查询OID为2的客户,测试发现只会打印一条sql语句,并且前后两次查询得到的对象是一致的。

     /**
      * 测试hibernate一级缓存
     */
    @Test
    public void test2(){
    Session session = HibernateUtils.openSession();
    //开启事务
    Transaction tx = session.beginTransaction();
    //根据id查询出对象的,并放入一级缓存中
    Customer customer = session.get(Customer.class, 3L);
    //第二次查询id为2的对象,发现一级缓存中有id为3的对象,就直接从一级缓存中取,不查询数据库
    Customer customer2 = session.get(Customer.class, 3L);
    System.out.println(customer == customer2);
    //提交事务
    tx.commit();
    session.close();

    }


  下面测试session的生命周期:创建session,查询一个对象,提交事务,关闭session;再创建一个session,查询同一个对象,会发出第二条select语句:测试发现会打印两条sql语句,并且前后两次查询得到的对象是不一致的。

   /**
   * sesssion缓存是有生命周期的:
   * 当session关闭时,缓存失效
   */
    @Test
    public void test3(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
    Customer customer1 = session.get(Customer.class, 3L);
    tx.commit();
    session.close();

    session = HibernateUtils.openSession();
    tx = session.beginTransaction();
    Customer customer2 = session.get(Customer.class, 3L);
    System.out.println(customer1 == customer2);
    tx.commit();
    session.close();
    }
  1. 快照机制

Hibernate 向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。
测试代码如下:

   /**
   * 测试快照机制
   */
    @Test
    public void test4(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
    //查询id为3的客户,放到一级缓存中,同时复制一份数据放到hibernate快照中
    Customer customer = session.get(Customer.class, 3L);
    //打印出来的是:小米
    System.out.println(customer.getCustName());
    //修改客户的姓名为:苹果,没有更新,直接提交事务,发现会发送update语句更新数据库中的数据
    customer.setCustName("苹果");
    tx.commit();
    session.close();
    }

4.Hibernate 中的对象的三种状态

Hibernate的事务的管理

1.事务的相关知识(面试常考)

  1. Hibernate中设置事务隔离级别

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

3.Hibernate中设置session与当前线程绑定

<!-- 把session与当前线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>

4.openSession()和getCurrentSession()的区别:

getCurrentSession()获取的时同一个session,而openSession()在任何情况下,始终创建新的session

Hibernate 的查询API

Query:HQL查询

1.概述

  1. 常用的查询方法

    查询所有

     /**
    * 查询所有
    * sql语句的写法: select * from 表名
    * hql语句的写法: from 类名
    */
     @Test
     public void test(){
     Session session = HibernateUtils.getCurrentSession();
     Transaction tx = session.beginTransaction();
     
     //获取query对象
     Query query = session.createQuery("from Customer");
     
     //执行query
     
     List<Customer> list = query.list();
     //遍历
     for (Customer customer : list) {
         System.out.println(customer);   
     }
     tx.commit();
    }
    

    条件查询

    /**
    *条件查询
    */
     @Test
     public void test1(){
     Session session = HibernateUtils.getCurrentSession();
     Transaction tx = session.beginTransaction();
     
     //获取query对象
     Query query = session.createQuery("from Customer where custName like ?");
     
     //设置参数
     //一个参数表示第几个?  从0开始数起
     query.setString(0, "%百%");
     
     //执行query
     List<Customer> list = query.list();
     
     //遍历
     for (Customer customer : list) {
         System.out.println(customer);   
     }
     tx.commit();        
    }
    

    分页查询

    /**
    *分页查询
    */
     @Test
     public void test2(){
     Session session = HibernateUtils.getCurrentSession();
     Transaction tx = session.beginTransaction();
     
     //获取query对象
     Query query = session.createQuery("from Customer");
     //设置分页信息
     //设置开始查询的位置
     query.setFirstResult(0);
     //设置查询的最大记录数
     query.setMaxResults(3);
     //执行query
     List<Customer> list = query.list();
     for (Customer customer : list) {
         System.out.println(customer);
         
     }
     tx.commit();    
    }
    

    排序查询

    /**
    *排序查询
    *使用order by关键字
    *asc 默认升序
    *desc 降序
    */
     @Test
     public void test3(){
     Session session = HibernateUtils.getCurrentSession();
     Transaction tx = session.beginTransaction();
     //获取确认样对象
     Query query = session.createQuery("from Customer order by custId desc");
     
     //执行query
     List<Customer> list = query.list();
     for (Customer customer : list) {
         System.out.println(customer);   
     }
             tx.commit();    
    }
    

    统计查询

     /**
    * 统计查询
    */
     @Test
     public void test4(){
     Session session = HibernateUtils.getCurrentSession();
     Transaction tx = session.beginTransaction();
     
     //创建query对象
     Query query = session.createQuery("select count(*) from Customer");
     
     //执行query
     //当确定结果集只有一行数据时,才能使用uniqueResult
     //count函数查询到值是long型
     long total = (long) query.uniqueResult();
     System.out.println(total);
             tx.commit();    
     }
    

    投影查询

     /**
    * 投影查询:使用一个实体的部分字段信息,来构建实体类对象,叫做对象的投影
    *select  new Customer() from Customer  
    * 实体类要求:
    *    必须提供一个相同参数列表的构造函数
        *public Customer(Long custId,String custName) {...}
    */
     @Test
     public void test5(){
     Session session = HibernateUtils.getCurrentSession();
     Transaction tx = session.beginTransaction();
     
     //创建query对象
     Query query = session.createQuery("select new Customer(custId,custName) from Customer");
     
     //执行query
     List<Customer> list = query.list();
     for (Customer customer : list) {
         System.out.println(customer);
     }
               tx.commit();  
    }
    

3.query中的方法说明

Query:QBC查询

1.概述

2.常用查询

查询所有

/**
 *查询所有
 */
@Test
public void test(){
    Session session = HibernateUtils.getCurrentSession();
    Transaction tx = session.beginTransaction();
    
    //获取Criteria对象
    Criteria criteria = session.createCriteria(Customer.class);
    
    //执行查询
    
    List<Customer> list = criteria.list();
    for (Customer customer : list) {
        System.out.println(customer);
    }
    tx.commit();
}

条件查询

/**
 *条件查询(and 和 or)
 */
@Test
public void test1(){
    Session session = HibernateUtils.getCurrentSession();
    Transaction tx = session.beginTransaction();
    
    //获取criteria对象
    Criteria criteria = session.createCriteria(Customer.class);
    //设置查询条件
    //1. or 连接(满足一个即可)
    //criteria.add(Restrictions.or(Restrictions.like("custName", "%百%"),Restrictions.eq("custLevel", "VIP")));
    //2.and 连接(必须同时满足)
    criteria.add(Restrictions.like("custName", "%百%"));
    criteria.add(Restrictions.eq("custLevel", "VIP"));
    
    //执行查询
    List<Customer> list = criteria.list();
    //遍历
    for (Customer customer : list) {
        System.out.println(customer);
        
    }
    tx.commit();
}

用到的类、方法说明:
Restrictions是用来构造条件的工具类,通过该类中的一系列静态方法可以构造各种条件,例如:
Restrictions.eq(property_name,value)表示=条件,property_name是属性名,value是=号后边的值;
Restrictions.like(property_name,value)表示like条件,property_name是属性名,value是like后边的值;

分页查询

/**
 *分页查询
 */
@Test
public void test2(){
    Session session = HibernateUtils.getCurrentSession();
    Transaction tx = session.beginTransaction();
    Criteria criteria = session.createCriteria(Customer.class);
    //设置分页信息
    //设置开始索引
    criteria.setFirstResult(0);
    //设置查询的最大记录数
    criteria.setMaxResults(3);
    
    //执行查询结果
    List<Customer> list = criteria.list();
    for (int i = 0; i < list.size(); i++) {
        Customer customer = list.get(i);
        System.out.println(customer);
        
    }
    tx.commit();

}

排序查询

/**
 *排序查询
 */
@Test
public void test3(){
    Session session = HibernateUtils.getCurrentSession();
    Transaction tx = session.beginTransaction();
    Criteria criteria = session.createCriteria(Customer.class);
    //按照cust_id降序排序
    criteria.addOrder(Order.desc("custId"));
    
    //执行查询
    List<Customer> list = criteria.list();
    for (Customer customer : list) {
        System.out.println(customer);
        
    }
    tx.commit();
}

统计查询

/**
 *统计查询
 */
@Test
public void test4(){
    Session session = HibernateUtils.getCurrentSession();
    Transaction tx = session.beginTransaction();
    Criteria criteria = session.createCriteria(Customer.class);
    
    //调用统计方法
    //select count(*)
    criteria.setProjection(Projections.rowCount());
    
    //执行查询
    long total = (long) criteria.uniqueResult();
    System.out.println(total);
    tx.commit();
}

离线查询
使用场景:页面上有个搜索表单,提交搜索表单后,发送多个搜索参数到servlet,在servlet里用离线查询对象DetachedCriteria拼接sql条件,再把拼接好条件的DetachedCriteria对象依次传递给service、dao,在dao层直接执行DetachedCriteria,不用拼接sql条件了。

public class QBCDemo2 {
/**
 * 离线查询
 * 模拟三层架构
 */
@Test
public void test(){
    List<Customer> list = servletFindAllCustomer();
    for (Customer customer : list) {
        System.out.println(customer);
        
    }
}

/**
 * 
 *模拟查询所有用户的servlet
 */
public List<Customer> servletFindAllCustomer(){
    //获取DetachedCriteria对象
    DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
    detachedCriteria.add(Restrictions.like("custName", "%百%"));
    detachedCriteria.add(Restrictions.eq("custLevel", "VIP"));
    List<Customer> list = serviceFindAllCustomer(detachedCriteria);
    return list;
}

/**
 * 
 * 模拟查询所有用户的service
 */
public List<Customer> serviceFindAllCustomer(DetachedCriteria detachedCriteria){
    List<Customer> list = daoFindAllCustomer(detachedCriteria);
    return list;
    
}
/**
 * 
 * 模拟查询所有用户的dao
 */
public List<Customer> daoFindAllCustomer(DetachedCriteria detachedCriteria){
    Session session = HibernateUtils.getCurrentSession();
    Transaction tx = session.beginTransaction();
    //把离线查询对象DetachedCriteria转变成在线查询Criteria
    Criteria criteria = detachedCriteria.getExecutableCriteria(session);
    List<Customer> list = criteria.list();
    return list;
}
}
上一篇 下一篇

猜你喜欢

热点阅读