欢迎使用我的 在线工具

小D

读历史、看小说、写程序都是我所爱。技术不好,头脑不灵光,靠的是兴趣。
随笔 - 35, 文章 - 25, 评论 - 13, 引用 - 0
数据加载中……

Hibernate的笔记

1、 left outer join 左外连接:
左外连接的查询结果集中包括指定左表(主表)中的所有行,
* 而不仅仅是连接列的所有行。如果左表的某行在右表(从表)中没有找到匹配的行,则结果
       * 集中的右表的相对的位置为 NULL

2、关于hibernate.hbm2ddl.auto
  <property name="hibernate.hbm2ddl.auto">update</property>
     将这个属性设为 update 只有我们发生修改的时候才会重新创建表 否则不会被覆盖掉(未理解)

,在SessionFactory创建时,自动检查数据库结构,或者将数据库schema的DDL导出到数据库。使用

create-drop时,在显式关闭SessionFactory时,将drop掉数据库schema.
        例如:我们将所有的表都删除了当我们执行插入操作时,SessionFactory被创建那么会自动检

查数据库scheme的DDL,建立数据表,并且会保留原来的数据,所以我们不用 Export 配置中的数据到数

据库,那样会覆盖掉所有的数据。

3、 关于对象关系信息导出
这里必须调用 configure 方法 否则会映射 properties 文件
        Configuration cfg = new Configuration().configure();  
  //用于导出用户定义的 xml 配置信息,在数据库中生成对应的Table
  SchemaExport export = new SchemaExport(cfg);
  export.create(true, true);

4、* 测试lazy在class上的策略 这里默认为true
我们在这里应当搞清session.get()和session.load()的区别
方法load支持 lazy(在Session缓存中生成一个User的子类对象返回,只有当调用方法是才查询) 如果

不存在查询的结果则抛异常
     session = HibernateUtil.getSession();
   tx = session.beginTransaction();
            Classes c1 = (Classes)session.load(Classes.class, 1);
            System.out.println("c1.getId()"+c1.getId());
            System.out.println("c1.getName()"+c1.getName());
这里不会发出sql语句,因为这里就采用lazy策略,所以这里采用了第三方的组件返回了一个,一个新的

Classes 的实例(代理),只有当我们需要查询属性时才会发出算sql语句,在这里不会发出sql语句因为

id 是我们输入的。
hibernate 支持的lazy 策略只在session的生命周期内有效。

5、lazy在collection上的策略
 很显然这些lazy都是默认的
    Classes c1 = (Classes)session.load(Classes.class, 1);
   //如果我们将集合上的lazy设为false,这里会发出两条sql除了将要查询的

普通属性查出来外,还会将非普通属性
   //将集合上的lazy设为extra和true是一样的
   System.out.println("c1.name= " + c1.getName());
   //没有发出sql 但是会生成一个 persistent 的set作为代理
            Set students = c1.getStudents();
            for(Iterator it = students.iterator();it.hasNext();){
             Student s = (Student)it.next();
             System.out.println("student.name= " + s.getName());
            }
            //System.out.println("student.number= " + student.size());
            //这里会将所有的数据读取出来并生成对象存放在set中
            /*这里Classes的lazy策略只对普通的属性有关,而collection的lazy策略才对
             * collection对象生效*/
*测试在标签上的lazy 策略和集合上的lazy策略一样。
6、one2one
<class name="org.n2535.hibernate.Person" table="t_person">
  <id name="id">
  <!-- 这里表示了Person的主键是作为一个外键关联了IdCard的主键 -->
     <generator class="foreign">
     <!-- 表示主键的生成是根据 属性 idCard 的 id -->
       <param name="property">idCard</param>
     </generator>
  </id>
  <property name="name" />
  <!-- 表示了Person与Idcard是一对一的关系 默认为根据主键加载对象(主键关联) -->
        <!-- constrained(约束) (可选) 表明该类对应的表对应的数据库表,
               和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。
              而且它们之间的约束条件为true
        在这里默认了两者的级联操作,否则的话一方的主键就为空没有任何意义了 -->
  <one-to-one name="idCard" constrained="true"/>
</class>
关于idCard的xml配置可以用
   <!-- 默认为主键关联 即加载cardNo 时根据其主键将 关联的Person表中 主键相同的 元组

取出
       默认的抓取策略为 Join  -->
  <one-to-one name="person"/>

当然也可以不用。

7、extends
 <!-- 测试每个具体的类映射一种表,这里Animal应该是抽象的,所以不应该被生成出来,将

abstract="true"-->
<class name="Animal" abstract="true">

  <id name="id">
     <generator class="assigned"/>
  </id>
  <!-- 此处不需要鉴别器,因为每个具体的类都生产了一张表 -->
  <property name="name" />
  <property name="sex" />
  <union-subclass name="Pig" table="t_pig">
  <property name="weight"/>
  </union-subclass>
 
  <union-subclass name="Bird" table="t_bird">
  <property name="height"/>
  </union-subclass>
 </class> 

<!-- 测试单表继承映射 -->
<class name="Animal" table="t_animal" lazy="false">

  <id name="id">
     <generator class="native"/>
  </id>
  <!-- discriminator 鉴别器,用来识别不同的子类 -->
  <discriminator column="type" type="string"/>
 
  <property name="name" />
  <property name="sex" />
  <!-- Pig -->
  <!-- discriminator-value的默认是完整的类名 -->
  <subclass name="Pig" discriminator-value="P">
    <property name="weight"/>
  </subclass>
 
  <!-- Bird -->
  <subclass name="Bird" discriminator-value="B">
    <property name="height"/>
  </subclass>
 </class>

8、component 组件映射测试
 component类不是一个实体类,在hibernate中的实体是指的 一个Pojo+一个映射文件
  component类是一个辅助类
   component 组件映射
  <component name="contact" class="org.n2535.hibernate.Contact">
    <property name="email"/>
    <property name="address"/>
    <property name="zipCode"/>
    <property name="contactTel"/>
  </component>

9、复合主键
因为主键是不可重复的,所以在复合主键的类中我们实现了Serializable接口,
和hashcode、equals方法,能够确保主键的唯一性。
 <!-- 复合主键映射我们也可以认为是一种 component 组件映射的一种  -->
   <composite-id name="pk">
   <key-property name="productYear"/>
   <key-property name="productMonth"/>
   </composite-id>
   <property name="name"/>
   <property name="factory"/>
 </class> 

10、集合映射
  
  <set name="setValue" table="t_set_value">
   <key column="set_id"/>
   <element type="string" column="set_value"/>
  </set>
 
  <list name="listValue" table="t_list_value">
   <key column="list_id"/>
   <!-- 这里必须给出排序的索引,因为list是有序的(下同) -->
   <list-index column="list_index"/>
   <element type="string" column="list_value"/>
  </list>
 
  <array name="arrayValue" table="t_array_value">
   <key column="array_id"/>
   <list-index column="array_index"/>
   <element type="string" column="array_value"/>
  </array>
 
  <map name="mapValue" table="t_map_value">
   <key column="map_id"/>
   <map-key type="string" column="map_key"/>
   <element type="string" column="map_value"/>
  </map>

11、关于Hibernate的锁
 1)、悲观锁:先获得数据库的锁的线程,知道该线程放弃提交,其他的线程将无法修改该数据

(LockMode.UPGRADE :利用数据库的for update子句加锁。)
2)、乐观锁:通常利用一个 version 的版本冲突来实现,实际上不是数据库的锁,一个线程的version

必须大于数据库中的version值才能被存储,否则报错。这样提供了比悲观锁宽松的条件,只要 version

大于数据库中的version就可以被存储,而不会因为是否死一个线程先获得锁,因为乐观锁根本就不是一

种锁。
  * 未使用悲观锁的时候,不同的操作可以访问相同的数据,那么会造成数据的错误
  * 使用悲观锁的时候,可以避免这个问题
可以不用显示的调用,如果为调用update那么在提交的时候会自动的update,当第一个操作将数据锁住

的时候,(所有的其他访问将被禁止)第二个select操作将会阻塞,知道第一个操作释放了锁,第二个

对象的选择操作会根据第一个对像的update的结果来读取数据,如果两个对象都从数据库中读取了相同

的数据,那么第一次的update操作,将会被第二次的覆盖,造成错误的数据。
 session.update(inv);
 要使用悲观锁请使用指定的数据库的命令,或者使用hibernate中的配置。
  * 乐观锁采用的version的冲突机制,如果update的version小于或数据库中的version
  * 将会产生错误插入失败,一位update的限制条件是根据 主键和version 所以会失败
  * 我们还能仿照 Hibernate 的乐观锁机制,用Jdbc实现乐观锁
 
12、hibernate查询语言hql 
在hql中关键字不区分大小写,但是属性和类名区分大小写

1)、简单属性查询【重要】
 * 单一属性查询,返回结果集属性列表,元素类型和实体类中相应的属性类型一致
 * 多个属性查询,返回的集合元素是对象数组,数组元素的类型和对应的属性在实体类中的类型

一致
   数组的长度取决与select中属性的个数
 * 如果认为返回数组不够对象化,可以采用hql动态实例化Student对象
 参见:SimplePropertyQueryTest.java 

2)、实体对象查询【重要】
 * N + 1问题,在默认情况下,使用query.iterate查询,有可以能出现N+1问题
   所谓的N+1是在查询的时候发出了N+1条sql语句
   1: 首先发出一条查询对象id列表的sql
   N: 根据id列表到缓存中查询,如果缓存中不存在与之匹配的数据,那么会根据id发出相应的

sql语句
 * list和iterate的区别?
  * list每次都会发出sql语句,list会向缓存中放入数据,而不利用缓存中的数据
  * iterate:在默认情况下iterate利用缓存数据,但如果缓存中不存在数据有可以能

出现N+1问题
 参见:SimpleObjectQueryTest1.java/SimpleObjectQueryTest2.java
 
3)、条件查询【重要】 
 * 可以采用拼字符串的方式传递参数
 * 可以采用 ?来传递参数(索引从0开始)
 * 可以采用 :参数名 来传递参数
 * 如果传递多个参数,可以采用setParamterList方法
 * 在hql中可以使用数据库的函数,如:date_format
 参见:SimpleConditionQueryTest.java  
   
4)、hibernate也支持直接使用sql进行查询
 参见:SqlQueryTest.java

5)、外置命名查询
 * 在映射文件中采用<query>标签来定义hql
 * 在程序中采用session.getNamedQuery()方法得到hql查询串
 参见:Student.hbm.xml、NameQueryTest.java
 
6)、查询过滤器 
 * 在映射文件中定义过滤器参数
 * 在类的映射中使用这些参数
 * 在程序中启用过滤器
 参见:Student.hbm.xml、FilterQueryTest.java
 
7)、分页查询【重要】 
 * setFirstResult(),从0开始
 * setMaxResults,每页显示多少条数据
 参见:PageQueryTest.java
    
8)、对象导航查询,在hql中采用 . 进行导航【重要】
 参见:ObjectNavQueryTest.java
 
9)、连接查询【重要】
 * 内连
 * 外连接(左连接/右连接) 
 参见:JoinQueryTest.java
 
10)、统计查询【重要】
 参见:StatQueryTest.java
 
11)、DML风格的操作(尽量少用,因为和缓存不同步)
 参见:DMLQueryTest.java

13、Hibernate中的缓存
 1)、一级缓存
session 中一级缓存的生命周期和session的相同
由于load使用了session中的一级缓存 所以第二次的load 并不会发sql 因为在session的缓存中还存在

相同的数据。
由于get使用了session中的一级缓存 所以第二次的get 并不会发sql 因为在session的缓存中还存在相

同的数据。
    会发出查询 id 的 sql(使用一级缓存才会发出) 但是不会发出查询对象的 sql 因为Iterate

查询支持缓存。
在save的时候会在缓存中保存一份当前对象的引用。
session.clear();//全部清除
2)、二级缓存
     <!-- 指定二级缓存的提供者 -->
    <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    <!-- 指定是否使用二级缓存 默认为true -->
<property name="cache.use_second_level_cache">true</property>
使用ehcache.xml这个配置文件来配置二级缓存。
session 中二级缓存的生命周期和sessionFactory的相同,所以又称为 sessionFactory 级缓存,二级

缓存只能用于存储实体。
3)、三级缓存
    <!-- 使用查询缓存 默认为false-->
    <property name="cache.use_query_cache">true</property>
queryCache生命周期和sessionFactory的相同。
但是在数据库里面的数据改变的时候,queryCache中的对象失效。
QueryCache的生命周期与session无关。
Iterate 接口不支持 QueryCache。
这里使用list 来查询实体对象 并开启了QueryCache 由于QueryCache 会存储实体的主键值,而list 在

查询实体的时候不会使用缓存 所以list会使用QueryCache的实体的主键值 去查询相应的,实体,由于

它会现在缓存中查找实体对象 如果不存在则会发出sql到数据库中查询 这里没有配置二级缓存 ,又重

开了session所以在缓存中不存在实体对象 所以会根据在QueryCache 中的实体主键值发出sql到数据库

中查询。
因为开启了二级缓存,QueryCache 会存储查询出来的实体的主键,而list会根据在QueryCache中的 主

键值到二级缓存中查找相应的实体,所以不会发出sql(list接口不会使用一级缓存但是能够利用这种方

法使用QueryCache 和 二级缓存)。

14、抓取策略
 1)、fetch = "select" 抓取策略 发两个select语句;fetch = "join" 抓取策略 使用外连接

查询。
2)、在集合中的抓取策略
 •使用 load
  * fetch = "select" 抓取策略 发两条sql
  * fetch = "join" 发一条sql 采用外连接查询
•使用 HQL
* fetch = "select" 抓取策略 发两条sql 和加载对象方式一样,每次每个实体的集合时会发sql
* fetch = "subselect" 将会在查询实体的集合时将所有查询的实体的集合发一次sql 全部查询出来
3)、测试 batch – size
 batch-size="3"在集合中设置。

 

posted on 2009-11-04 21:09 vagasnail 阅读(301) 评论(0)  编辑  收藏 所属分类: Java框架


只有注册用户登录后才能发表评论。


网站导航: