Hibernate自学随笔笔记

674 阅读16分钟

SSH-整合

什么hibernate

持久化的ORM框架 1.ORM :Object Relation Mapping 对象/关系 映射

  • (1)思想将关系型数据库中表中的记录映射成对象 将对象的形势表现 可以把对数据表的操作转化为对对象的操作
  • (2)ORM采用将元数据来描述对象 关系映射细节 元数据采用XML格式并且存放在专门的对象 关系映射文件中

整合SSH

  • 1.链接数据库的基本信息 jdbc注意加入 配置在session-factory
  • 2.配置hibernate基本信息 .cfg.xml
  • (1)hibernate方言 :dialect
  • (2)是否打印sql 是否打印 是否对sql格式化
  • (3)指定关联的hbm.xml文件 3.创建持久化包 .hnm.xml 对应实体类表
<hibernate-mapping>
<class name=”classpath” table=”类名”>
<id name=”id” type=””>
<column name=””ID>
<generator class=”native”>
</id>
<property></property>

简单使用hibernate

// 创建一个seesionFactory 对象
SessionFactory sessionFactory=null;
// 创建configuratiuon获取配置信息
Configuratuon configuration = new Configuration.configure();
// serviceRegistry 4.0新创建的对象,Hibernate要在里面注册之后才能生效
serviceRegistry serviceRegistry  = new ServiceRegistryBuild().
applySetting(configuration .getproperties()).buildserviceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
// 创建seesion对象
Session session = sessionFactory.openSession();
// 开启事物
Transaction Transaction = seesion.beginTransaction();
// 执行保存操作
News news = new News(xx,xx,xx);
Session.save(news);
// 提交事物
Transaction .commit();
// 关闭seesion
Seesion.close();
// 关闭sessionFactory对象
sessionFactory.close();

Transaction 原子操作 具有数据库事物的感念所有操作的事物管理下进行

配置文件的两个配置项 生成数据表策略:hbm2ddl.auto :

  • 1.create 会重新生成表
  • 2.create_drop sessionFactory关闭就会删除表
  • 3.Update 会更新数据表结构 但不会删除表
  • 4.Validate 如果映射与数据表结构不同 就抛出异常
Session 操作对象

是Hibernate最主要的操作数据库的接口 可以根据数据库换缓存中的变化执行特定的SQL 操作Session缓存 一个方法的同样查询,第一次查询之后第二条会查询缓存。

  • 1.Flush() 让数据表中的记录和session缓存对象中的状态保持一致,为了保持一致则可能会发送对应的sql语句。 1. transaction.commit()方法中先进行flush()再提交事物。
  • 2.flush方法可能会发送sql语句,但不会提交事物。
  • 3.注意:若在session未提交事物或显式的调用session.flush方法之前,也有可能进行flush() :
  • 4.执行后HQL或QBC查询,会进行flush(),已得到最新的记录
  • 5.若记录的id是有底层数据库使用自增的方式生成的,则在调用save方法后,就会立即发送Insert语句,因为save方法后,必须保证对象的ID是存在的!
  • 6.flush不提交事物,session.commit提交事物就意味着数据被永久保存 因为提交了事物
  • 7.Refresh() 会强制发送select语句 以使session缓存中对象的状态和数据包中的对应的记录保持一致 设置Hinbernate隔离级别
<property name=”connection.isolation”>2</>

持久化对象的四种对象状态

  • 1.临时对象 在使用代理主键的情况下,OID通常为Null,不在session的缓存中,在数据库中没有对于记录
  • 2.持久化对象 对象与数据库数据对应 保存操作在session中 一对一数据库表中记录通过flush同步更新到数据库中
  • 3.删除对象:数据库中没有记录,删除操作不在session中一般情况下 不使用删除对象
  • 4.游离对象 OID不为空 不处于session中 由持久化转变过来 因此数据库还存在对应的记录
常用hibernate方法操作数据库的方法

1.Save() 保存操作 前后最大不同的是OID为空和不为空

  • (1)使一个临时对象变成持久化对象 为对象分配id
  • (2)session.commit-flush 缓存时 会发送一条Insert语句
  • (3)在save方法之前设置Id是无效的
  • (4)持久化对象的ID是不能被修改的
  • (5)Persist 与 save差不多都能完成Insert操作
  • 1)和save区别:在persist方法之前调用,若对象已经有id了则不会执行Insert会抛出异常

2.Get vs load 区别

  • (1)执行get方法会立即加载对象而执行Load方法若不使用该对象属性,则不会立即执行查询操作而返回一个代理对象
  • (2)Get是立即检索,load是延迟检索用的时候再加载
  • (3)若数据表中没有对应的记录 get返回null load抛出异常,且session没关闭,同时需要使用对象时
  • (4)load方法可能会抛出懒加载异常 lazyinitializationException异常,在需要初始化代理对象就已经关掉了session

3.update方法 游离对象转化成持久化对象

  • (1)若更新一个持久化对象 不需要update 因为transaction.commit-flush
  • (2)更新游离状态对象 可以显示调用update方法 可以将游离对象变成持久化对象
  • (3)需要注意的点:1. 更新update游离对象 不管是否一样不会发 但是更新持久化对 象如果一样就不会发Update语句,如何让update不盲目触发update语句:.hbm.xml 对应class设置上<select-before-update=true >默认false但是通常不需要设置属性
  • (4).若数据表没对应记录 还调用update会抛出异常
  • (5).当update关联一个游离对象时,如果session存在相同OID的持久化对象,会抛出异常

4.saveOrUpdate 保存或者更新 临时对象insert 游离则update

  • (1)若OID不为空 但数据表中和其对应的记录会抛出异常
  • (2)了解IOD值等于ID的unsaved-value属性值的对象,也会被认为游离对象 .hbm.xml
  1. delete 删除操作 只要OID和数据表中的一条记录对应 就删 如果OID没有对应的,就抛出异常 .cfg.xml sessionFactory下设置属性 hibernate.use_identifier_rollback=true将ID置为空 再删

6.evict 从session缓存中将指定的持久化对象删除

Cfg.xml

Hibernate.jdbc.fetch_size 每次读取几条数据 设置越大 读取次数越小 100 Hibernate.jdbc.batch_size 设定对数据库进行批量删除 批量更新和批量插入的时候批次大小 30 对Mysql无效

Hibernate mapping hbm.xml详解
  • 1.一个xml映射多个实体 hibernate-mapping package=”包路径”
  • 2.Property=”类名” table=”表名”
  • 3.Dymamic-Upate = true 动态更新 设置一个字段只更新一个字段 默认为false
  • 4.Dymamic-insert = true 动态插入 同上
  • 5.Id = “” Generator class =”” 指定生成主键方式 推荐使用代理主键 不具备业务任何含义
  • (1)Increment hibernate以递增的方式为代理主键赋值 会有多并发主键相同问题 支持db2 mysql sqlserver 不支持oragle 因为他不支持主键自增
  • (2)Sequence
  • (3)Hilo
  • (4)Native 常用 本地自动选择前三种自增生成

6.Property unique=”” update=”标识不能被修改” index=”添加索引” length=”指定长度”

  • (1)Formula =”子查询sql语句” 派生属性

7.String - clob varchar大于255使用string好于clob Blob多用于大对象二进制

8.映射组成关系 当类里有引用

<component name=”pay” class=””>
指定组成关系的组件属性		<parent name=”所属类名”>
<property name=”” column=””/>
</component>
映射一对多关联关系

1.怎么映射 单向多对一

  • (1)在副表配置下 <many-to-one name=”主类名” class=”主类路径” column=”外键” 使-用many-to-one来映射多对一的关系,name:多这一段关联的一那一端的属性的名字,class:那一端属性对应的类名,column: 一那一端在多的一端对应的数据表中的外键的名字,需操作之前操作关联关系即主类的操作,先插入1的一端在插入多的一端,只有Insert语句有三条insert。如果先操作多的数据,会多两条Update语句。
  • (2)Get 获取多的那端数据时,不会查询一的那一端的数据。但是如果用到了一那一端的对象时,才会查询一的那一端的数据,因为也是懒加载,如果session关闭,也会出现懒加载异常。获取order对象时,默认情况下其关联的主对象用的是代理对象。
  • (3)delete在设置级联关系情况下,且一这一端的对象中有n个对象在引用。不能删除1这一端的对象
双向1-n

1.映射一对多的那个set集合属性 hbm.xml

(1)<set name=”orders” table=”多的表名”> <key column=”一的主键或者多的外键”>		<one-to-mang class=”多的类路径”> </set>
  • (2)可以通过Inverse=true 由主动方维护关联关系 可以在一的一端集合映射set节点指定inverse=true来使一的一端放弃维护关联关系,建议设定inverse=true,建议先插入一的一端,后插入多的一端,好处使不会多出update语句。需要把集合进行初始化,可以防止空指针异常。
  • (3)获取操作 对多的一端的集合使用延迟加载,再获取多的一端数据时,使hibernate内置的集合类型,是延迟加载,且声明集合类型时,需要使用Hibernate内类的集合类型,因为set下无子类,他支持延迟检索策略。
  • (4)修改操作 使用集合iterator.next.set
  • (5)set映射set类型的属性,table:set中的元素对应的记录放在哪一个数据表中,该值需要和多对一的多的那个表的名字一致。key执行多的表中的外键列的名字,one-to-many 指定映射类型
  • (6)inverse指定由哪一方来维护关联关系 通常设置为true,以指定由多的一端来维护关联关系
  • (7)Cascade 级联 有对象在引用不能删除,设置级联删除就可以删除 设定级联操作,在我删一的一端时会把多的一端也删除。 cascade=delete/delete-orphan删除孤儿、save-update级联保存操作,开发时不建议设置该属性,建议使用手工的方式来处理
  • (8)Set 排序操作 order-by=”order_name desc” 在查询时对集合的数据进行排序,还可以加入SQL语句

2.一对一关联关系

  • (1)基于外键的1-1关联 其外键可以存放在任意一边 在=需要存放外键一端,增加many-to-one元素。为Many-to-one元素增加Unique=true 属性来表示关联
  • (2)没有外键的一端需要使用one-to-one元素该元素使用property-ref属性指定使用被关联实体主键以外的字段作为关联字段
  • (3)在查询没有外键的实体对象时,使用的是主外链接查询,一并查询其关联的对象并已经进行初始化
  1. 基于主键映射一对一
  • (1)使用外键的方式生成当前的主键
<generator class=”foregin”><param name=”property”>mgr</param>
  • (2)采用foreign主键生成器策略的一端加One-to-one元素映射关联属性 其one-to-one节点还应增加constrained=true属性,以使当前的主键添加外键的约束

4.N-n

  • (1)标签table指定中间表 指定多对多关联关系 column指定set集合中的 持久化类在中间表的外键列的名称
  • (2)双向多对多 交叉配置 如果不指定inverse=”true”就会抛出异常

5.继承映射 三种继承策略

  • (1)Subclass 可以实现对于继承关系中父类和子类使用同一张表 因此要多个字段称为辨别着类 子类所有字段不能有非空约束 父类映射子类 使用subclass进行映射
<subclass name=”student”><property name=school” type=”string” column=”SCHOOL”></></>
辨别者类 <discriminator column=”type” type=”string”></>

在父类和子类添加辨别的参数 主类和subclass都要配置只不过值不同<discriminato-value=”person/students”> 插入操作对于对象只需把记录插入到一张数据表(父类表)中,由hibernate自动维护 查询 多态查询只需要查一张数据表 对于子类记录 也只要查询一张数据表 缺点:使用了辨别者列 子类独有的字段不能添加非空约束 若继承层次较深则数据表的字段也会较多

  • (2)Joined-subclass 每个子类一个表 无需辨别着列 但是需要子类映射主类的主键但是可以添加非空约束
1)<joined-subclass name=”student” table=”STUDENTS”> <key column=”STUDENT_ID”></><property name=”school” type=”string” column=”SCHOOL”></></>
  • 2)对于插入子类记录 至少插入两张数据表中
  • 3)查询父类记录 做一个左外链接查询 查询子类 内连接查询
  • 4)优点 不需要使用辨别者列 子类能添加非空约束 没有沉郁字段 (3)Union-subclass 将每个实体映射到单独表中 子类可以非空约束 子类经保存在子类表中 不需要辨别者 不能用identy主键生成策略 1)</></> 2)优点 查询父类记录,需要把父子类记录汇总一起再查询 性能差 3)缺点 存在冗余字段 更新效率较低 若更新父表的字段则更新效率较低

6.hibernate检索策略 即查询数据

  • (1)不浪费内存 当需要加载customer还加载了Orders 而查询只需要customer
  • (2)更高的查询效率:发送少的sql
  • (3)类级别检索策略 可以配置lazy属性进行配置
  • 1)立即检索
  • 2)延迟检索 在使用具体的属性时 如果知识获取他的引用时,load.注意懒加载异常,仅对load方法有效。ID也是有值的
  • (4)一对多和多对多的检索策略 默认懒加载
  • 1)lazy决定orders初始化的时机 true/false/extra 增强延迟检索该取值会尽可能延迟初始化的时机 可以用hibernate.init立刻初始化
  • 2)Fetch 取值为select/subselect 决定初始化orders的查询语句的形势.若取值为join则决定orders集合被初始化的时机 若吧fetch设置为join lazy属性将被忽略 set集合的属性默认为select 通过正常的方式来吃实话set集合。可以取值为subselect 通过子查询的方式来初始化所有的set集合,子查询作为where字句的In的条件出现,子查询查询所有1的那一端的ID,此时lazy有效batch-size失效,若取值为Join则
  • 1.在加载一的那一端对象时,使用迫切左外连接(使用左外链接查询,且初始化集合属性)的方式检索n的那一端的集合属性
  • 2.忽略Lazy属性
  • 3.HQL查询忽略fetch=join的取值
  • 3)Batch-size 决定立即策略或立即检索策略的检索数量 设定一次初始化set集合的数量
  • (5)多对一和一对一关联的检索策略
  • 1)lazy取值为proxy 和false则分别代表对对应的属性采用延迟检索和立即检索
  • 2)Fetch取值为join表示使用迫切左外链接的方式初始化n关联的一的那一端的属性
  • 3)批量初始化batch-size=5 一个批次初始化个数在对应的一的那一端class配置上配置,作用:一次初始化一的那一端代理对象的个数

7.hibernate检索方式

// 导航对象图检索方式
// OID检索方式
// HQL检索方式 使用面向对象的HQL查询语言
Query  query = Session.createquery(sql ) //基于配置/基于命名占位符换成:name 底标换成name // // 还可以设置引用类型
Query.set(“index”,”param”).(index,param)
List<Object> data = Query.list();
// 分页查询 setFirstResult setMaxResult
Query  query = Session.createquery(sql ) //基于配置/基于命名占位符换成:name 底标换成name 
// 还可以设置引用类型
List<Object> data = Query.setFirstResult(xx).setMaxResult(xx).list()

命名查询

<query name=”xxxx”><![CDATA[FROM XXX e WHERE e.param > :par]]></>
Query query = seesion.getNameQuery(“xxxx”);
List<Object> data = query.setString(“par”, “”).list();

3.投影查询

  • (1)查询结果仅包含实体的部分属性
String sql = “SELECT new Employee (e.email, e.salary. e.dept) FROM Employee e WHERE e.dept=:dept”;  //写个带参的构造器 前提要写无参构造
Query query = session.createQuery(sql);
New Dept...
List<Object[]> data = query.setEntity(“dept”, dept).list(); 

4.报表查询

  • (1)就说GROUP BY(分组) HAVING(前置条件)等相关查询

5.迫切左外链接

  • (1)SELECT DISTINCT d FROM D d letf join fetch d.emps
  • (2)去重 new ArrayList<>(new LinkedHashSet(dept))
  • (3)左外链接 : 获取一个的一端的类和多的一端的类的集合根据配置文件决定子类的检索策略
  • (4)迫切内连接
  • a.不返回左表不符合条件的记录
  • b.与左外迫切链接一样
  • c.忽略左外链接的检索策略
  • (5)QBC检索方式
// Query By Criteria API
// 创建对象
Criteria criteria = session.createCriteria(E.class);
// 添加查询条件:在QBC中查询使用CRITERION表示
Criteria.add (Restrictions.eq(“email”,”SUMMER”));
Ctiteria.add(Restrictions.gt(“”salary, 600F));
// 执行查询
E e = criteria.uniqueResult();
// and Restrictions.conjunction(); 然后加条件 然后再加入criteria.add(conjunction);
// or  Disjunction
//统计查询  
criteria.setProjection(Projection.max(“sal”));
//排序查询 
criteria.addOrder(Order.asc(“sal”));  criteria.addOrder(Order.desc”email”);
//添加翻页方法 
criteria.setFirstResult().setMaxResult()
// 本地SQL检索方式
// 完善HQL不能覆盖操作
Session.createSQLQuery(“sql”);
Query.set(index, par).set(index, par)
Hibernate 二级缓存

1.Session 一级缓存 生命周期结束缓存就结束了 他属于事物凡物的缓存 2.二级缓存 sessionFactory级别的缓存 属于进程范围的缓存

集合类别的二级缓存

<collection-cache=”read-write” collection=””类路径.集合>

还要缓存集合的object类才能shiyongHbm.xml 配置 set下

<collection-cache=”read-write” collection=””类路径.集合>

还需要配置集合中的元素持久化类也是用二级缓存

配置磁盘存储路径 当数据到一定程度时 需要设置临界值 超过就写在磁盘上 <设置默认的数据过期策略> 设置具体命名的缓存的数据过期策略 每个命名缓存代表一个缓存区域 缓存区域(region) 存储不同区域 不同集合和类

<cache name=””
maxElementsInMemory= 设置基于内存的缓存中可存放最大对象数量
Eternal	永久?
timeToIdleSeconds	空闲时间
timeToLiveSeonds	生存时间 /s 要大于空闲时间 0是永久
overflowToDisk	是否将溢出来的对象存放磁盘上>
1.查询缓存
  • (1)默认情况下对HQL,QBC查询是无效的,可以通过以下方式使其有效
  • (2)在cfg.xml 声明开启缓存
  • (3)调用query或criteria的setCacheable(true);
  • (4)查询缓存依赖与二级缓存 2.二级缓存下使用迭代器可以稍微提高查询性能

管理session session对象的生命周期与本地线程绑定 构造参数传入SESSION不适合 获取当前线程绑定的session 多个DAO可以使用一个事务 提供单例Util类 返回sessionFactory 单例写法 获取session getSessionFactory.getCurrentSession(); 配置cfg.xml 配置管理session的方式

<property name=current_seesion_context_class>true</>