Hibernate的运行流程 单元测试

单元测试:
   当一个项目中我们完成了某个小功能,如果在早期我们需要测试该功能,大部分需要启动整个项目,测试完有问题,需要更改,之后又需要启动整个项目.这种测试手段比较麻烦,我们就可以将需要测试的功能,在单元测试中完成,确定没有问题,在启动项目.
   

@Before:每个测试方法之前执行的方法 

@Before
    public void Before() {      
/*
 * configure()方法没参数时,默认加载src下hibernate.cfg.xml文件;
 * 如果该配置文件的路径或名称没有使用默认的,就需要给configure()方法加参数,
 * 指定路径或新名称.
 */
  //(1)读取并解析hibernate.cfg.xml配置文件
 Configuration config = new Configuration().configure();
  /*(2)由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>读取并解析映射信息*/
  // (3)创建会话SessionFactory对象
 SessionFactory sf = config.buildSessionFactory();
    // (4)加载Session对象
  Session session = sf.openSession();
    }

@Test:
   该方法就是测试方法,把需要测试的功能在该方法中完成测试,测试方法不能有返回值和参数.

@Test
public void testAdd() {
  //(5)开启事务Transation
  //hibernate不会自动提交事务,session对数据的所有操作需要在事务中进行 
       Transaction ts = session.beginTransaction();
 try{
  //(6)持久化操作
  //(7)提交事务
            ts.commit();
       } catch (Exception e) {
  //(8)回滚
            ts.rollback();
        e.printStackTrace();
        }               
    }

@After:每个测试方法之后执行的方法 

@After
public void After() {
    if (session != null) {  
        session.clear();
//(9) 关闭session对象
        session.close();
/*
 *关闭session工厂,清空资源.由于sessionFactory对象持有整个持久化操作的资源,
 *关闭之后,下次在使用又需要创建,太耗内存,通过监听器application servletContext对象,
 *当服务器关闭或Web应用被移除时,ServletContext对象跟着销毁,
 *当停止进程时,再清理sessionFactory资源
 */
  //(10) 关闭sessionFactory对象
       sessionFactory.close();
        }
    }

hibernate.cfg.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
      <!-- 对session工厂的设置 -->
    <session-factory>   
      <!-- 四本一言的设置 --> 
             <!--数据库地址-->
      <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernatem?characterEncoding=utf8</property>
             <!-- 数据库用户名 -->
      <property name="hibernate.connection.username">root</property>
             <!-- 数据库密码 -->
      <property name="hibernate.connection.password">12345678</property>
             <!-- 数据库驱动 -->
      <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
             <!-- 数据库方言 -->
      <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>

      <!-- 控制台是否显示sql语句 -->
           <!--show_sql: 是否把Hibernate运行时的SQL语句输出到控制台 -->
      <property name="show_sql">true</property>
          <!--format_sql  输出到控制台的SQL语句是否进行排版,便于阅读 -->
      <property name="format_sql">true</property>

<!--hbm2ddl.auto 自动建表: 可以帮助由java代码生成数据库脚本,进而生成具体的表结构  -->      
      <property name="hbm2ddl.auto">update</property>

<!-- 二级缓存配置 -->
       <!-- 默认是不使用二级缓存,设置使用二级缓存 -->
   <property name="hibernate.cache.use_second_level_cache">true</property>       
     <!-- 开启查询缓存,如果不开启,每次查询完只存主键,开启后可以存其它字段,拿到一条完整的记录 -->
   <property name="hibernate.cache.use_query_cache">true</property>  
      <!-- 配置谁来支撑 -->
  <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
      <!--引入映射文件-->
    <mapping resource="com/xalo/model/ClassRoom.hbm.xml"/>
    <mapping resource="com/xalo/model/Student.hbm.xml"/>

    <!-- 设置使用二级缓存的对象并指定并发策略-->
 <class-cache usage="read-only" class="com.xalo.model.ClassRoom"></class-cache>
    </session-factory>
</hibernate-configuration>

 <!-- 数据库方言 hibernate.dialect:配置Hibernate数据库方言 
     1、org.hibernate.dialect.MySQLDialect;
     2、org.hibernate.dialect.MySQL5InnoDBDialect;
     3、org.hibernate.dialect.MySQLMyISAMDialect -->

<!-- hbm2ddl.auto: 的值有一下四种:
    1. create:每次加载hibernate时,都会删除上一个的生成的表,
              然后根据你的model类,再重新生成新表,数据库表数据容易丢失
    2. create-drop: 每次加载hibernate时根据model类生成类,但是sessionFactory一关闭,表就自动删除
    3. update: 第一次加载hibernate时根据model类会自动建立起表结构,
               以后加载hibernate时,根据model类自动更新表结构
               当部署到服务器后,表结构不会被马上建立起来的,要等第一次运行起来后才会
    4. validate:每次加载hibernate时,验证创建数据库表结构,
                只会和数据库中的表进行比较,不会创建新表,但是会插入新值 -->

<!-- 开启查询缓存(一般配合二级缓存使用,两个都设置为true)
     如果没有开启二级缓存,只开启了查询缓存,此时缓存中只存储查询出来的数据的id
     如果后续再查询相同的数据,根据缓存中的id分条查询数据   -->  

XXXX.hbm.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
  <!--将实体类和数据库表建立映射关系, name:要建立映射的类  table:表中 的字段名-->
    <class name = "com.xalo.model.ClassRoom" table="room">
   <!--主键配置-->
     <id name = "roomId" column ="rid">
   <!--主键生成策略-->
      <generator class = "native"></generator>
     </id>
   <!-- 字段映射 -->
       <property name="roomName" column="name"></property>
    </class>
</hibernate-mapping>

<!--主键配置 name:类中成员变量 column:表中的字段名
              length:当前类的长度,默认数据库对于类型最大长度
              type:当前类的类型,默认自动检测类型-->

<!--主键生成策略: 
 increment:先查询表中主键最大值,加1作为子女的主键值(其中最少有一条数据) 
 identity:依赖与数据库的主键自增  
 sequence:使用数据库中的列名 
 hilo: hibernate自己用于高低位算法完成主键自增 
 native: 相当于 auto_increment 自动递增 自动根据数据库三选一(identity/sequence/hilo)  
 uuid:生成随机字符串(长度应大于32位) 
 assigned: 自然主键,hibernate不生成主键,有开发人员自己设置主键值 -->

<!--字段映射
    配置其它属性 name:类中成员变量 
               column:表中的字段名
               length:当前列的长度,默认数据库对于类型最大长度
               type:当前列的类型,默认自动检测属性
               not-null:设置非空
               unique:设置唯一-->

持久化操作:

Add:

    Student student = new Student();
        student.setName("碧瑶");
        student.setAge(18);     
        student.setScore(86.9);
        session.save(student);

Delete:

/*删除数据:
 *delete方法只能按照id删除  session.delete(deleteStu);
 *如果要批量删除(删除多条记录)
 * 用HQL查询出要删除的数据
 */

        Student deleteStu = new Student();
   //第一种方式: 根据sid删除学生
String hql = "select sid from Student where name = ?0";
Query query = session.createQuery(hql).setParameter(0, "张小凡");
         //将查询结果放在一个list集合中
        List<Integer> deleteSid = query.list();
        for (Integer sid : deleteSid) {
                deleteStu.setSid(sid);
               session.delete(deleteStu);
        }   

   //第二种方式: 找出年龄是23的人,删除
   String hql = "from Student where age = ?0";
Query query = session.createQuery(hql).setParameter(0, 23);
      //将查询结果放在一个list集合中
     List<Student> students = query.list();
        for (Student student : students) {
             session.delete(student);
        }       

query:

<!--查询数据:
 *(1)查询单条记录:
 *   1.get: 单条查询 通过get方式,只能通过主键(sid)查询.
 *          第一个参数:类的class对象
 *          第二个参数: 主键值
 *   2.load:会延时查询,在查询时并没有直接去通过sql语句查询结果,
 *          而是只得到要查询记录的sid,当我们要使用查询记录中的
 *          其它字段的值,这时才会去表中查询
 *  如果查询的数据不存在,报异常.get方法会返回一个null
 * 
 * (2)查询多条记录:
 *    HQL语言:
 *  hibernate的查询语言,表名对应类名,字段名对应成员变量
 * 与SQL相似,SQL中的语法基本上都可以直接使用.
 * SQL查询的是表和表中的列,HQL查询的是对象和对象的属性.
 * HQL的关键字不区分大小写,类名与属性名区分大小写
 *
 * select可以省略
 * 直接from查询出来的是一个映射对象,即:查询的整个映射对象的字段 
  -->

   <!--查询单条记录-->
   Student student = session.get(Student.class, new Integer(2));
   Student student = session.load(Student.class, new Integer(2));
           System.out.println(student);

   <!--查询多条记录-->   
   String hql = "from Student where name = ?0";
Query<Student> query = session.createQuery(hql).setParameter(0, "曾书书");
<!--将查询到的结果放到一个list集合中,需要在model层里面重写toString()方法,不然遍历出来的是内存地址-->
       List<Student> list = query.list();
        for (Student student2 : list) {
              System.out.println(student2);
            }  

   <!--查询其中某个字段-->
  String hql = "select name from Student where name = ?0";
 Query<String> query = session.createQuery(hql).setParameter(0, "曾书书"); 
            //默认查询出来的list里存放的是一个Object数组
              List<String> list = query.list();
               for (String student2 : list) {
                    System.out.println(student2);
            } 

   <!--查询其中某几个字段-->      
  String hql = "select name,age from Student where name = ?0";
Query<Object[]> query = session.createQuery(hql).setParameter(0, "曾书书"); 
    //默认查询出来的list里存放的是一个Object数组
      List<Object[]> list = query.list();
       for (Object[] student2 : list) {
          System.out.println(Arrays.toString(student2));
    }        

update:

<!--第一种方式:将所有的属性个必须写全才能修改-->
  Student updateStu = new Student();
       updateStu.setSid(9);
       updateStu.setName("张小凡");
       updateStu.setAge(20);
       updateStu.setScore(86.0);
<!--第二种方式:根据sid取出一条信息,然后可以随意修改里面的任意属性-->
Student updateStu = session.get(Student.class, 7);
      if (updateStu != null) {
             updateStu.setName("毕燕");
             session.update(updateStu);
                 }

Hibernate运行流程:
这里写图片描述

Hibernate五大核心接口:

Configuration接口:
加载配置文件,创建sessionFactory对象
SessionFactory接口:
  初始化Hibernate,充当数据库存储源的代理,创建Session对象
SessionFactory特点:
  1.它是线程安全的,同一个实例可以被应用的多个线程共享.
  2.它是重量级的,不能随意创建或销毁它的实例.
  3.如果应用只访问一个数据库,只需创建一个SessionFactory实例,
               在应用初始化的时候创建该实例.
   如果应用同时访问多个数据库,则需要为每一个数据库创建一个单独的                    SessionFactory实例
  4.SessionFactory需要一个很大的缓存,用来存放预定义的SQL语句以能映射元数据等.
  Hibernate的第二级缓存: 用户可以为SessionFactory配置一个缓存插件,该缓存用来存放被工作单元过的数据,将来其它工作单元可能会重用这些数据,因此这个缓存中的数据能够被所有的工作单元共享.一个工作单元通常对应一个数据库事务.

SessionFactory的作用 :
1. 创建session对象
(1) openSession
(2)getCurrentSession,将session和线程绑定,需要在cfg的配置文件中将session和线程绑定
2. 在内置缓存中缓存了cfg hbm等配置文件
3. 外置缓存就是二级缓存
4. 会话工厂对象中缓存的hibernate运行了大部分资源,所以使用hibernate期间不要轻易的关闭会话工厂,因为每次加载太耗资源,当项目关闭之后,再关闭会话对象清空资源.

Session接口:
  Session被称为持久化管理器,它提供了和持久化相关的操作,如:添加 删除 加载 查询对象.
Session特点:
  1.不是线程安全的,因此在设计软件架构时,应该避免多个线程共享同一个Session实例.
  2.Session实例时轻量级的,它的创建和销毁不需要消耗太多的资源.
在程序中可以经常创建和销毁Session对象
  3.Hibernate的第一级缓存:存放被当前工作单元加载的对象.
每个Session实例都有自己的缓存,每个Session实例的缓存只能被当前工作单元访问.

Transaction接口:
1.Transaction接口是Hibernate数据库事务接口,它对底层的事务接口做了封装,
2.hibernate大大部分操作需要在事务中进行
3.开启事务,提交/回滚

Query和Criteria接口:
  1.Hibernate的查询接口,用于向数据库查询对象,以及控制查询的过程.
  2.Query实例包装了一个HQL查询语句,HQL查询语句是面向对象的,它引用类句及类的属性句,而不是表句及表的字段句.
  3.Criteria接口完全的封装了基于字符串的查询语句,比Query接口更加面向对象,Criteria接口擅长执行动态查询.
  
  Session接口的find()方法也具有数据查询功能,但它只是执行一些简单的HQL查询语句的快捷方法,它的功能远没有Query接口强大.

猜你喜欢

转载自blog.csdn.net/zs1342084776/article/details/81138402