hibernate-基础部分

hibernate-基础部分
1、jdbc的缺点:
1、代码比较麻烦
2、不是面向对象编程
3、如果碰到一个很复杂的需求分析,需要很次很数据库交互,这样效率比较低
4、jdbc技术没有做到数据的缓存
2、hibenrnate
1、面向对象的编程
2、缓存
一级缓存    二级缓存     查询缓存
3、代码操作比较简单
4、如果该项目对sql的优化要求特别高,不适合用hibernate
  如果数据库的数据量特别大,也不适合用hibernate
3、hibernate的三大要素
1、配置文件
1、数据库的链接信息
<property name="hibernate.connection.username">root</property> 
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/privatesecretary</hibernate>
2、动态生成表
<property name="hbm2ddl.auto">update</property>
3、引入映射文件
<mapping resource="com/voole/vo/Role.hbm.xml" /> 
4、输出SQL语句
<property name="show_sql">true</property>
5、格式化SQL语句
<property name="format_sql">true</property>
6、方言
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
6、关于二级缓存的配置
<property name="cache.use_second_level_cache">true</property>
<property name="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
7、关于查询缓存的配置
<property name="cache.use_query_cache">true</property>
8、统计机制
<property name="hibernate.generate_statistics">true</property>
9、从当前线程中产生session
<property name="current_session_context_class">thread</property>
2、持久化类
1、必须有默认的构造函数
2、标示符属性为基本类型的包装类或者String类型
3、一般属性
4、集合属性
3、映射文件
1、类与表的对应关系
2、类中的属性名称和表中的字段名称的对应关系
3、类中的属性类型和表中的字段类型的对应关系
4、一对多和多对多的对应关系
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- 
        class元素描述的就是持久化类
          name     类的全名
          table    表名  默认值为person
          catalog  数据库的名称(最好不写,因为前面的配置文件已设置)
     -->
    <class name="com.itheima05.hibernate.domain.Person" table="person">
        <!-- 
            id  标示符
            name     标示符的名称
            length   在数据库中该字段的长度(最好要写)
            type     类型(可以不写)
            column   在表中的列的名字  默认就是name的名称(可以不写)
         -->
        <id name="pid" length="5" type="java.lang.Long" column="pid">
            <!-- 
                主键的生成器
             -->
            <generator class="increment"></generator>
        </id>
        <!-- 
            property代表一般属性
         -->
        <property name="name" length="20" type="java.lang.String" column="name"></property>
        <property name="sex" length="20" type="java.lang.String" column="sex"></property>
    </class>
</hibernate-mapping>
3、执行过程:
1、创建Configuration对象
2、利用Configuration对象的config方法加载配置文件
3、config.buildSessionFactory方法产生SessionFactory
sessionFactory
1、包含了数据库的链接信息
2、配置文件的信息
3、映射文件的信息
4、持久化类的信息
5、一个sessionFactory表明链接了一个数据库
6、sessionFactory是一个单例的对象
4、sessionFactory产生session
session
1、创建一次session,就打开数据库的链路一次
2、session的打开和关闭的次数越多,效率越低
3、session中的一级缓存缓存了数据
5、由session创建事务
6、进行crud的操作
7、提交事务
8、关闭session
3、主键的产生机制
1、uuid
1、必须是varchar类型
2、是由hibernate内部产生的
2、assigned
1、主键可以是任何类型
2、必须在程序中手动赋值
3、一般不推荐使用
3、increment
1、主键必须是数字类型
2、由hibernate操作数据库
1、先获取主键的最大值
2、最大值加1
3、效率不是很高,会发出max语句
4、identity
1、主键 必须是数字类型
2、表支持自动增长
3、主键是由数据库生成的
4、效率比较高,但是数字不是很连贯
        5、sequence
                Oracle的序列化主键
4、类型
hibernate类型
java类型
一般用java类型
根据数据库中的表生成持久化类和映射文件
第一步编程hibernate工程
1.

2.

3.

4.

5. 选择 模式
6. 建立一个数据库连接 
7.设置数据库信息

8.

5、对象的状态
在hibernate中,对象的状态分为几种:
临时状态
刚刚创建的对象
持久化状态
经过session. load,session. get,session. save,session. update方法都可以把一个对象变成持久化状态
脱管状态
经过session. clear,session. evict,session. close方法可以把一个对象变成脱管状态
例子:
1、临时状态的对象通过save方法变成持久化状态的对象
2、步骤
1、临时状态的对象先通过save方法变成持久化状态的对象
2、把该对象的属性值改变
3、调用update方法进行更新  //没有发出任何sql语句,所以这步可以不写
说明:
1、save方法可以把一个对象变成持久化对象
2、这个时候调用session.update方法不起作用,因为已经是持久化对象了
3、步骤
1、执行session.get方法,把一个持久化对象提取出来
2、执行session.evict方法把一个持久化状态的对象变成托管状态的对象(这个时候,该对象脱离session的管理)
3、执行session.update方法把处于脱离状态的session变成持久化状态
说明:
1、session.evict方法可以把一个对象变成托管对象
2、session.update方法可以把已经是托管状态的对象变成持久化状态的对象
4、步骤
1、执行session.get方法,把一个持久化对象提取出来
2、执行session.clear方法,把session中所有的对象变成托管状态的对象(这个时候,session中已经没有对象了)
3、执行session.update方法把处于托管状态的对象再次变成持久化状态的对象

说明:
session.clear方法可以把session中的所有的对象变成托管状态的对象
5、步骤
1、执行session.get方法,把一个持久化对象提取出来
2、执行session.close方法,关闭session
3、调用sessionFactory.openSession方法重新打开一个session
4、执行session.update方法,让该对象对于新的session变成持久化对象
说明:
一个对象是不是持久化状态的对象有参照物,该参照物就是session
6、步骤
1、新创建一个对象,利用session.save方法把该对象变成持久化状态的对象
2、再创建一个对象,利用session.save方法把该对象变成持久化状态的对象
3、利用session.get方法把从数据库提取出一行数据,封装到一个对象中
4、改变第三步产生对象的属性
5、事务提交
6、session关闭
说明:
1、现象
执行了两个save语句,一个update语句
2、原理
在执行事务提交的时候,hibernate容器会去检查session中所有的持久化对象的状态
如果没有ID值,则进行save操作,如果有ID值,进行update操作


hibernate最常用的关系分为两种
一对多
1、关系的表示
1、从类的角度说明
1、在Classes类中声明一个Set集合Student  (类与集合的关系)
2、在Student类中声明一个Classes类 (类与类之间的关系)
2、从映射文件的角度
在Classes.hbm.xml文件中
<!-- 
            set集合
               cascade
                   save-update
                   delete
                   all
               inverse
                  default/false  维护关系
                  false          维护关系
                  true           不维护关系
         -->
        <set name="students" cascade="save-update" inverse="true" batch-size="2">
            <cache usage="read-only"/>
            <!-- 
                外键
                    hibernate可以通过该外键建立classes表和student表之间的关联
             -->
            <key>
                <column name="cid"></column>
            </key>
            <!-- 
                建立类与类之间的关联
             -->
            <one-to-many class="com.itheima05.hibernate.domain.Student"/>
        </set>
<set name="students">
//从数据库的角度建立两张表的关联(通过外键关联)
<key>
<column name="外键">
</key>
//建立类与类之间的关联
<one-to-many class="">
</set>
在Student.hbm.xml文件中
<many-to-one name="classes" column="外键" class="">
2、涉及到的操作
一对多的操作
一般操作
1、保存班级
2、保存学生
3、保存班级,保存学生

级联操作
4、保存班级级联保存学生
5、保存班级级联更新学生
6、更新班级级联保存学生
7、更新班级级联更新学生
8、删除班级级联删除学生
9、在班级有级联save-update的情况下,从关联得到学生,并且删除学生?

关系操作
8、已经存在一个班级,新建一个学生,把该学生加入到该班级(建立关系操作)
9、已经存在一个学生,新建一个班级,把该学生加入到该班级(建立关系操作)
10、已经存在一个学生,已经存在一个班级,把该学生加入到该班级
11、已经存在一个学生,把一个学生从一个班级转移到另外一个班级

级联和关系的混合:
12、在删除班级的时候,解除班级和学生之间的关系
多对多的操作
一般操作
1、保存学生
2、保存课程
3、保存学生、保存课程
级联操作
4、保存学生级联保存课程
5、保存学生级联更新课程
6、保存课程级联保存学生
7、保存课程级联更新学生
8、更新课程级联操作学生
9、更新学生级联操作课程
  级联删除
关系操作
10、把一个学生加入到一个课程(建立关系)
11、把一个学生从一个课程转移到另外一个课程(重新建立关系)
12、把一个学生从某一个课程中移除(解除关系)
多对多
3、重点关注
1、因为一对多和多对多一般情况下是双向的
1、关系操作
通过谁建立关系,看谁的映射文件
2、cud的操作
       session.save/update/delete()参数中的对象是谁,看谁的映射文件
2、在set集合中有一个属性inverse,维护关系
一对多的情况下,多的一方维护效率比较高
多对多,谁维护效率都一样
3、一般情况下,使用多的一方维护效率
4、针对一对多的情况,维护关系就是对外键执行update语句
1、建立关系
给外键设置一个值
2、解除关系
把相应的外键设置为null
3、重新建立关系
把相对应的外键由一个值变成另外一个值
5、针对多对多的情况,维护关系
1、建立关系
在第三张表中增加一行记录
2、解除关系
在第三张表中删除一行记录
3、重新建立关系
先删除一行记录,再增加一行记录
6、执行crud的操作和关系的操作是分开的
例如下面的代码:
classes.setStudents(students); //关系操作
session.save(student);  //对象的操作
当执行classes.setStudents的时候,是通过classes建立classes与student之间的关系,所以应该看classes.hbm.xml
当执行session.save(student)的时候,是保存student,这个时候应该看student.hbm.xml
7、一对多的时候,如果是一端维护,那么会另外发出维护外键的update语句,所以效率不高
8、级联的用法
save-update delete all
说明
1、级联解决的问题:
使客户端的代码变得简单了
性能优化

延迟加载( lazy):当需要的时候加载,控制sql语句的发出时间来提高性能
1、session.load方法产生的是代理对象
2、session.load方法产生的对象只不过是一个空壳子
当真正加载属性的时候才要发出sql语句
   1、类的延迟加载
       只针对一般属性,不针对(标示符、集合、引用)
   2、集合的延迟加载
       在one-to-many,many-to-many的情况下的类与集合的关联中的集合
       1、是set元素的延迟加载
       2、 true
               当迭代集合的时候,加载集合中的数据(默认值)
          false
               当加载对象的时候,直接把关联的集合对象加载出来了
          extra
               当加载集合的大小的时候,没有必要把集合中的数据加载出来,这个时候用该加载策略比较合适
   3、单端关联(many-to-one)的延迟加载:对性能的影响有限
          many-to-one的 lazy 延迟加载: false/no-proxy(true)/proxy(true) 
     只不过是hibernate提供的一种提高性能的方式,需要映射文件中进行配置,只能配置一次  

抓取策略( fetch):
    针对set集合
       set元素中有一个属性 fetch:
            " select"
               1、默认的
               2、会导致n+1条查询
            " subselect"
                 当经过需求分析翻译成sql语句,含有子查询,这个时候,用这个策略效率最高
            " join"
               1、左外链接
               2、一次性把classes与student全部加载出来
               3、如果需求分析中含有子查询,该策略将失效
     fetch= select + batch-size="2" 相当于subselect


延迟加载( lazy)和抓取策略( fetch):针对set集合
   1、延迟加载:通过什么时候发出sql语句加载集合
   2、抓取策略:通过什么样的sql语句加载集合
    lazy               fetch                     说明
    true               select          当迭代集合的时候发出sql语句,通过每一个cid查询student
    true/false       join             如果需要分析中没有子查询,
                        subselect        一条语句加载classes和student,这个时候lazy可以忽略 

一级缓存:session的缓存
          存放的是私有数据
          因为数据放在了threadlocal中,所以是安全的
   操作一级缓存
       1、一级缓存的生命周期
           等同于session的生命周期
       2、通过什么样的方法把对象放入到一级缓存中
          session.get,save,update方法都可以把对象放入到一级缓存中
       3、通过什么样的方法客户端从一级缓存中把对象提取出来
            session.get方法
       4、什么样把一个对象从一级缓存中清除
           session.evict
       5、怎么样把所有的对象从一级缓存中清除
           session.clear
       6、怎么样把缓存中的对象同步到数据库中
           session.flush
       7、怎么样把数据库中的数据同步到缓存中
           session.reflesh
  一级缓存的意义:
     在操作的过程中,减少和数据库的交互次数,从而提高效率
     快照和副本也是为了减少数据库的交互次数,提高效率的

二级缓存:
   1、数据不能经常更新
   2、公共的,不经常改变的
   3、私有数据,绝密的数据不能存放
   4、是sessionFactory缓存
   5、hibernate没有针对二级缓存的解决方案,是借助第三方类库实现的(jar包)
         ehcache      
         oscache
         jbosscache   分布式缓存
         memorycache  不支持的   分布式缓存
   6、实现步骤
        1、在配置文件中
            1、开启二级缓存
    <property name="cache.use_second_level_cache">true</property>
            2、提供二级缓存的供应商
    <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
使用的二级缓存实现是ehcache,需要配置ehcache.xml
<Cache
   name="com.itheima05.hibernate.domain.Classes"
   maxElementsInMemory="5" 
   eternal="false"<!-- true表示缓存是不是永远不超时 -->
   timeToIdleSeconds="120"<!-- 如果没设置下面的项目,此项才有用 -->
   timeToLiveSeconds="120"<!-- 缓存中每个元素的超时时间 -->
   overflowToDisk="true"<!-- 当往缓存里面put的元素超过maxElementsInMemory的值时,把部分数据保存到硬盘上 -->
   maxElementsOnDisk="10000000"<!-- 设定磁盘缓存大小磁盘缓存大小 -->
   diskPersistent="false"<!-- 如果配置为false,缓存管理器停止后会清楚磁盘缓存。true则保存 -->
   diskExpiryThreadIntervalSeconds="120"<!-- 设置失效监测以及清除工作间隔时间 -->
   memoryStoreEvictionPolicy="LRU"<!-- 默认就好 -->
   />

        2、可以针对类、集合开启二级缓存
           1、类
               1、在配置文件中(没试验过)
                  <class-cache usage="read-only" class="com.itheima05.hibernate.domain.Classes"/>
               2、在映射文件中加入以下标签
                         <cache usage="read-only"/>
           2、集合
               1、先开启集合针对类的二级缓存
               2、再开启集合的二级缓存
        3、使用
              session.get方法把一个对象放入到二级缓存中
              当事务提交的时候,把对象放入到二级缓存中
   7、二级缓存的缓存策略
          <cache usage="read-only"/>
            read-only: 把对象放入到二级缓存中不能进行修改
            read-write:可以把对象放入到二级缓存,也可以修改
   8、利用CacheModel的值限制一级缓存和二级缓存的交互
   9、可以把对象缓存在磁盘上
   10、统计
先设置开启统计机制
<property name="hibernate.generate_statistics">true</property>
session.getStatistics().getEntityCount()
sessionFactory.getStatistics().getSecondLevelCachePutCount()


一级缓存和二级缓存称为对象缓存
   对象缓存(对象在数据库中有对应的表)
      1、对象缓存是根据主键进行标示的
      2、对象缓存会把数据库表中相应的行的所有的字段全部加载到对象中
           如果一个表有50个字段,而需要的是5个字段,这样利用对象缓存
           会把很多没有用的数据加载到缓存中

Query:
   1、query.list和query.iterator的区别
       query.list
           Query query = session.createQuery("from Classes");
           query.setCacheable(true);
           query.list();
                 1、加载的是对象的所有的内容
                 2、该hql语句查询出来的是List<Classes>,正好符合对象缓存,所以
                     该结果会在一级缓存,二级缓存中存储
                 3、如果hql语句是"select name from Classes",查询出来的结果
                      不符合对象缓存,这个时候,结果不会储存在一级缓存和二级缓存中
                 4、当第二次执行query.list的时候,必须设置query.setCacheable(true);
                      才能从查询缓存中提取数据
       query.iterator
           Query query = session.createQuery("from Classes");
           Iterator<Classes> iterator = query.iterate();
           while(iterator.hasNext()){
                Classes classes = iterator.next();
                System.out.println(classes.getName());
           }
                 1、先加载所有的id
                 2、再根据id加载所有的值
                 3、该方法把对象放入到了二级缓存中,查询的时候利用的是二级缓存,不利用查询缓存
       总结:
           1、query.list方法一次那个把数据全部查询出来,而query.iterator方法先查询id,再查询数据
           2、query.list方法利用查询缓存获取数据,但是必须设置query.setCacheable(true)
              query.iterator方法利用二级缓存查询数据
   2、分页
   3、hql
        1、单表
        2、一对多
        3、多对多
        4、一对多和多对多

查询缓存是数据缓存
   数据缓存
      1、数据缓存是根据hql语句进行标示的
  如果想把一些数据放入到查询缓存中,或者从查询缓存中把一些数据提取出来,
  必须通过query对象,而且必须设置query.setCacheable(true)才能做到
  如果想利用查询缓存,则hql必须相同 

      2、能按照需求缓存数据

      3、实现
          1、基于二级缓存
          2、在配置文件中开启查询缓存
              <property name="cache.use_query_cache">true</property>
          3、利用session.createQuery方法,把数据放入到查询缓存中



猜你喜欢

转载自blog.csdn.net/qq_34801169/article/details/80673136
今日推荐