• hibernate基础总结


    hibernate:ormapping 对象关系映射
    jdbc:面向sql语句
    hibernate:面向对象

    jdbc缺点:
    1、写sql语句比较繁琐
    2、把sql语句的操作封装成面向对象的操作比较麻烦
    3、关闭资源的操作特别繁琐
    4、查询的操作代码太多(冗余太多)
    5、没有做到数据的缓存(向数据库频繁的要数据,性能很差)
    6、sql语句的移植性太差(存储过程、触发器)
    jdbc优点:
    1、有连接池,所以获取connection的速度更快了
    2、最低层的数据库的操作

    hibernate:
    优点:

    1、面向对象的操作
    2、关闭资源操作很简单
    3、查询变得很简单了
    4、一级缓存、二级缓存、查询缓存
    5、移植性很好
    缺点:
    1、sql语句是由hibernate内部生成的,如果要对sql语句做优化,几乎不能
    2、如果一张表中的数据集达到千万级别,hibernate不适合
    总结:hibernate适合一些中小型的项目开发

    hibernate学习
    1、完成crud
    2、一对多、多对多的关系怎么样转变成hibernate的面向对象的操作
    3、hibernate的hql语句:类似于sql语句
    4、性能的问题
    1、延迟加载
    2、数据缓存
    3、抓取策略
    5、二级缓存(不是重点,面试重点)


    hibernate的组成部分:
    1、持久化类
    2、映射文件:描述了表到类的映射关系
    3、hibernate的配置文件:用于产生链接的

    4、客户端


    *.hbm.xml(映射文件)
    建立表到类的映射
    1、表明和类名映射
    2、表里字段的名称和类中属性的名称映射
    3、表里的字段类型和类中的属性类型映射


    框架搭建过程:
    1、导包
    2、写bean
    3、导入配置文件 bean名.hbm.xml(详细看源文件)
    <hibernate-mapping>
    <!--
    class是用来描述一个持久化类
    name属性就是累的全名
    table表明如果不写,默认就是类名
    catalog数据库的名称 一般不写
    -->
    <class name="" table="" catalog="">
    <!--
    id代表标示符属性
    name为属性呢的名称 提示来自于属性
    column表中的列名  默认就是属性的名称
    length指的是数据中的类型长度,如果不写,默认最大长度
    <id name="pid" column="pid" length="5" [type=""]>
    <!--
    generator 主键的产生机制
    -->
    <generator class="increment"></generator>
    </id>
    <property name="pname" length="20" [type=""]></property>
    <property name="sex" length="5" [type=""]></property>
    </class>
    4、导入hibernate.cfg.xml并配置
    5、类实现
    1、加载解析配置文件
    默认方法:Configuration configuration = new Configuration();
    configuration.configure()-->configure("/hibernate.cfg.xml");-->配置文件放在src下
    按名称:Configuration configuration = new Configuration();
    configuration.configure("")-->configure(String path);
    2、连接数据库,动态生成表
    configuration.buildSessionFactory
    SessionFactory:
    1、一个SessionFactory只能连接一个数据库
    2、配置文件的信息、映射文件的信息会存到sessionFactory中
    3、sessionFactory是一个重量级类
    4、sessionFactory是一个单例类
    5、sessionFactory是线程安全的
    3、sessionFactory.optionSession 打开session
    4、session.beginTransaction
    1、打开事务
    2、完成cud的操作
    3、commit()

    5、关闭session.close();数据库链路断开


    功能:crud由session完成的
    1、添加数据save
    Person person = new Person();
    person.setPname("老方");
    person.setPsex("不详");
    session.save(person);
    2、更新数据update
    *先把数据提取出来
    *修改
    *更新update
    session.get(要取的表,主键的属性值)
    Person person = (Person)session.get(Person.class, 1L);
    person.setPsex("纯爷们");
    session.update(person);
    3、删除数据delete
    //Person person = (Person)session.get(Person.class, 1L);//Person person = new Person();
    //person.setPid(1L);
    session.delete(person);
    4、查询createQuery
    List<Person> personList = session.createQuery("from Person").list();
    for(Person person:personList){
    }

    字段类型的映射
    hibernate java类型      sql类型
    integer java.lang.Integerint/number
    long java.lang.Longlong/number
    配置的时候写java类型,映射快
    详细java类型和hibernate类型对比参照:http://blog.csdn.net/kuyuyingzi/article/details/10012367

    id生成器
    1、increment,主键类型是数字,不自动增加,由hibernate(先获取max,再加1)自动增加
    注意:increment时,不能手动设置id,否则会报错
    2、identity,主键类型是数字,由sql自动增加,因此效率比increment高
    用increment优点,删除后,id没有断片
    3、uuid,企业里面一般用这个
    *主键类型是字符串
    *由hibernate生成
    4、assigned手动指定主键值

    持久化状态
    1、Person person = new Person();
    2、person.setPname("laofng");
    3、perso.setPsex("sdf");
    4、session.save(person);
    5、transaction.commit();
    6、session.close();
    1,2,3person对象时临时状态的对象
    4、person由临时状态转化成持久化状态
    5、person也是持久化状态,数据库中相对应的值了
    6、session关闭,hibernate与数据库通信断开,变成脱管状态
    总结:持久化状态:与数据库有关联和交互,脱管状态,有过交互但停了
    session.save(person),如果是新对象则执行insert,如果是更新操作则执行update
    session.evict(person)将对象从session中移除,变成脱管状态
    session.update(person)变成持久化状态,如果同一个对象进行多个更新,则只更新最近的一个
    session.clear()把session中的所有对象全部清空了
    注意:
    session.save,update,get方法都可以把一个对象变成持久化状态,并都能产生一个副本
    如果没有上述方法,session.commit的时候,hibernate会比较session中的副本中的值,不一样才与数据库发生相应交互



    hibernate的多表:
    一对多:
    <set name="students" cascade="save-update" inverse="false">
    <key>
    <!-- 外键-->
    <column name="cid"></column>
    </key>
    <!-- -->
    <one-to-many class="..student"/>
    </set>
    另一方是多对一,应配置<!-- 引入外键 -->
    <many-to-one name="classes" class="..." column="cid" cascade="save-update"></many-to-one>
    类配置文件:
    <!-- 
    cascade(默认为none)级联:在保存或者更新一个对象的时候保存或者更新级联对象
    即session.save(classs)时级联保存set<student>
    inverse(默认为false):表示对关系的不维护
    true  不维护关系
    false 维护关系
    default false
    表示class是否维护class与student的关系
    -->
    <set name="students" cascade="save-update" inverse="false">
    <key>
    <!-- 用来描述class和student的关系-->
    <column name="cid"></column>
    </key>
    <!-- -->
    <one-to-many class="..student"/>
    </set>
    总结:
    1、一对多的单项关联,维护关系指的就是发出update语句
    2、维护关系的操作,如果update cid=null肯定就是解除关系的操作
    如果update cid=4就是建立关系或者更改关系
    3、在维护关系的代码中,是通过classes维护关系的,所以应该看classes.hbm.xml文件
    4、级联指的是对象和对象之间的操作与关系无关,inverse指的是对象和关系之间的操作与对象无关

    多对多:
    多对多谁维护关系,效率都一样,都要对第三种表进行操作
    多对多维护关系体现在:
    1、建立关系指的是在第三张表中插入一行数据
    2、解除关系指的是在第三张表中删除一行数据
    3、更新数据
    执行update语句
    先删除,后增加
    <set name="students" table="student_course" cascade="save-update">
    <key>
    <column name="cid"></column>
    </key>
    <many-to-many class="" column="sid">
    </set>

    总结:一对多和多对多
    1、两边都是可以连通的
    2、inverse和cascade
    inverse指的是对象与关系的操作(对象与外键的操作)
    cascade指的是对象与对象之间的操作(与外键没有关系)
    一班默认情况下:
    一对多
    多的一方维护效率比较高
    维护关系指的是发出update语句
    update set 关系=null 解除关系
    update set 关系=值 建立关系
    多对多
    哪一方维护都行
    维护关系
    建立关系:在关系表中插入一行数据 insert
    解除关系:在关系表中删除数据 delete
    更新关系:在关系表中先删除后增加
    3、在客户端session.save/update操作谁,看谁的映射文件
    4、在写客户端代码的时候,一定要考虑这几个方面的因素
    1、当session执行save/update方法的时候,是否发生对象的关联
    2、当session执行save/update方法的时候,是否维护关系
    3、发生级联的时候,什么情况下对于级联对象执行save/update操作
    4、客户端代码中持久化对象的转换状态:临时状态-持久化


    hibernate性能的提高 :延迟加载、抓取策略、缓存、内连接-外连接
    延迟加载:关键词load
    懒加载lazy:要配合session.load方法使用
      true(默认)
    alse
    extra;用count/sum/avg等函数计算数值的时候,这个时候并不需要查
    1、概念:该加载时加载
    2、类型
    类的延迟加载
    类的基本属性 
    1、classes = session.load("");
    当classes.getCname()、setCname()的时候才发出sql语句
    2、<class lazy="false">,取消session.load()的延迟加载
    经典错误:
    classes = session.load("");
    session.close();
    classes.getCname();发生no session错误
    集合的延迟加载
    在关联对象时集合的情况
    一对多 多对多
    1、students = classes.getStudents();并没有发出sql语句
    for(Student student:students){}才发出sql语句
    2、<set lazy="false"> 取消集合的延迟加载,获取的时候就发出sql语句
    单端关联的延迟加载
    通过多的一方加载一的一方的策略
    <many-to-one>中lazy的值有
    false
    proxy 延迟加载
    no-proxy
    通过多的一方加载一的一方,就一条数据,保持默认值就可以了,不会特别影响效率

    抓取策略:关键词createQuery
    根据一个对象提取关联对象的策略
    抓取策略的情况:
    集合的提取
    <set fetch="">
    fetch
    "join"外连接 left outer join
    "subselect"子查询:查询效率最高 select+“batch-size"==subselect
    后面可跟:session.createQuery("from classes where cid in(1,2)");
    "select"默认的
    batch-size: 一次性查询出集合的数量
    根据多的 一段加载一的一端
    说明:
    1、如果把雪球分析翻译成sql语句,sql语句存在子查询,这个时候,首选子查询
    2、如果没有子查询,但是想把数据一次性的提取出来,这个时候选择”join"
    3、如果没有子查询,但是不想把数据一次性提取出来,这个时候选择默认“select”
    抓取策略和懒加载结合:结合面试重点内容
    lazy fetchsql
    true/extra join 采用左外连接,lazy不起作用
    false join采用左外连接
    true/extra select 先加载一的一段,再加载多的一端,多的一端在迭代时候加载
    false select在session.get方法时,把集合加载出来了,但是发出两条sql
    false select在session.createQuery时,就已经发出sql语句

    session:
    1、session的产生方式
    2、session的缓存
    3、session与实务的关系


    openSession:每次执行该方法都会新建一个session;
    getCurrentSession的执行过程
    1、先从当前线程中查找session
    2、如果找到,则直接使用,如果偶找不到执行第三步
    3、当事务提交transaction.commit,getCurrestSession中的session会自动关闭
    4、需要配置<property name="current_session_context_class">thread</property>(可以通过界面配置)
    5、所有的操作必须在事务环境下进行
    优点:安全性、自动关闭session
    session缓存:一级缓存 私有缓存
    1、缓存的生命周期
    生命周期开始:当session打开的时候
    生命周期结束:session.close(),session为当前线程,则程序执行完以后session自动关闭,缓存结束
    2、缓存中数据的安全性
    如果是当前线程打开session,session本身在threadLocal中,所以session中的数据时安全的(其他线程访问不到)
    3、数据怎么样放入到一级缓存中的
    当执行session.get、load、save、update方法时,把对象放入到了一级缓存中
    4、怎么样从一级缓存中取出数据
    session.get、load取数据
    5、怎么样把缓存中的数据同步到数据库中
    transaction.commit其实默认执行session.flush
    session.flush该语句包含作用:
    1、save/update数据
    2、有关系,更新关系
    3、有级联,更新级联操作
    一般配合session.clear()使用
    6、怎么样把数据库中的数据同步到缓存中
    session.refresh()只能把一个数据同步到缓存中
    7、怎么样把一个对象从缓存中移除
    session.evict(Object obj)
    8、怎么样清空缓存中所有的数据
    session.clear();


    二级缓存
    1、缓存的生命周期
    sessionFactory级别:当hibernate容器启动的时候,二级缓存就有了
    2、缓存中数据的安全性
    *sessionFactory线程安全的
    3、二级缓存存在的意义
    *提高查询速度
    *如果数据更新特别频繁,不适合做二级缓存
    *一些重要的数据不能放到二级缓存中
    *存放到二级缓存中的数据是不经常改变的,所以hibernate3以上的版本相对于一级缓存,有一些区别:
    二级缓存并不建议清除(把一个对象清除获取把所有的对象清除)
    *二级缓存分为类的二级缓存和集合的二级缓存,用法一样
    4、hibernate本身没有二级缓存,是借助第三方框架来实现的(面试亮点)
    5、二级缓存默认是关闭的
    6、二级缓存配置
    二级缓存的提供商
    <property name="cache.provider_class">
    org.hibernate.cache.EhCacheProvider
    </property>
    开启二级缓存
    <property name="cache.use_second_level_cache">true</property>
    类级别的二级缓存:usage读取策略
    1、在hibernate.cfg.xml<class-cache usage="read-write" class="..'/>  我用着不行哪
    2、一般在相应对的映射文件中配置<class name="..">
    <cache usage="read-only"/>
    不配置就不会放到二级缓存
    7、如果利用二级缓存
    session.get、session.load方法:把数据拿出来,存到一级缓存和二级缓存
    8、当二级缓存中的数据量比较大事,hibernate提供了一种机制,可以在内存缓存一部分数据,另一部分存在磁盘上
    ehcache.xml
    将缓存放到磁盘的配置文件,必须放在src目录下
    需要修改的项目
    <diskStore path=""/>
    <defaultCache
    maxElementsInMemory="12"
    maxElementsOnDisk="10000000"
    查询缓存:
    *查询缓存是建立在二级缓存基础之上的
    *查询缓存默认也不是开启的
    *打开查询缓存
    <property name="cache.use_query_cache">true</property>
    *在程序中的用法
    Query query= session.createQuery("from Classes")
    query.setCacheable(true);//开启查询缓存
    query.list();//把数据写入到查询缓存中
    query = session.createQuery("from Classes")
    query.setCacheable(true);//开启查询缓存
    query.list();//从查询缓存中取数据

    二级缓存:针对ID的查询缓存
    查询缓存:针对数据的查询
    session.createQuery("from Classes").list()
    session.createQuery().list()与session.createQuery().iterator()方法的区别(面试点)
    list:利用查询缓存,不利用一级缓存和二级缓存
    iterator:n+1查询
    利用一级缓存、二级缓存,不利用查询缓存
    hql语句(重点):得到合适的结果集,单表查询尽量用select,多表用fetch
    *语法规则:
    from持久化类 where 属性
    sql语句中的函数count,avg,sum等在hal语句中都适合
    order by,group by,having,子查询,in等在hql语句中都适合
    投影查询:只查询某些属性
    *单表的查询
    *select X X from 表,取出来的元素是Object
    *如果要求select查出来的是对象元素:select new com.....(类的路径)Classes(X,X) from 表
    该中查询方法,要求bean中要有有参构造函数,而且查询的参数个数与构造函数个数一致
    *from 表取出来的元素是对象
    总结:
    1、如果页面上的字段和数据库中的字段的个数差不多,直接”from 持久化类“
    2、如果页面上的字段和数据库中的字段相差很多,则利用到构造函数的查询
    3、如果是第一种情况,查询出来的Object[]中的顺序和select后的顺序保持一致
    迫切内连接:fetct规范取出去的数据
    from Student s inner join fetch s.classes c
    from Classes c inner join fetch c.students s
    from Classes c left outer join fetch c.students s
    外连接:可以在条件不成立的时候,仍然可以包含某些不成立的记录
    左外连接: 在条件不成立的时候,等号左边的表仍然被包含 left outer join
    右外连接: 在条件不成立的时候,等号右边的表仍然被包含 right outer join
    总结:无论是内连接还是左外连接,如果查询出来的结构和持久化的结构保持一致,要在join后面加fetch
    需求:查询表一的一部分和表二的一部分
    需要建一个bean来接收
    select new com.....(类的路径)Classes(c.X,s.X) from Classes c inner join c.students s
    *关联表的查询
    一对多
    多对多
    一对多和多对多的结合(难点)
    关键:找核心表(能同时联系其他的表),表的设计要用星型设计
    最终的目的:好取数据
    from Student s inner join fetch s.classes inner join fetch s.course
    问题:因为内连接用的是笛卡尔积,有重复数据
    解决:利用hashset不重复元素原理
    Set<Studnet>students = new HashSet<Student>(StudentList);
    studentList = new ArrayList<Student>(Students);



    附录:

    小细节1:Hibernate 中 HQL问号冒号的区别:

    在网上搜资料,得到的答案是基本相同,既然是基本相同并不是完全相同,所以肯定有区别。

    目前发现的区别就是用了则用变量的序号来赋值,从0 开始。

    如果用了变量名的则用变量名来赋值。



  • 相关阅读:
    C#多线程参数传递
    Delphi单元测试工具Dunit介绍
    使用javascript生成文件
    Windows自动登录源码
    [Win32]一个调试器的实现
    用MASM写一个简单的实现递归操作的汇编程序,所谓递归,上课已经跟大家说清楚了,如果我们只考虑简单的只分一次的递
    C#多线程编程(4)多线程与UI操作
    在Delphi中实现类型安全的容器,Delphi泛型库DGL引介(提供源码下载) .
    delphi 中几种多线程操作方式
    C#实现WEB服务器
  • 原文地址:https://www.cnblogs.com/kuyuyingzi/p/4266388.html
Copyright © 2020-2023  润新知