Hibernate复习笔记

(一)第一个hibernate项目


1、创建java项目
2、创建User Library,加入依赖包
* HIBERNATE_HOME/lib/*.jar
* HIBERNATE_HOME/hibernate3.jar
* 加入数据库驱动(mysql驱动)
3、提供hibernate.cfg.xml文件,完成基本的配置
4、建立实体类User.java
5、提供User.hbm.xml文件,完成实体类的映射
6、将User.hbm.xml文件加入到hibernate.cfg.xml文件中
<mapping resource="com/bjpowernode/hibernate/User.hbm.xml"/>
7、编写工具类ExoprtDB.java,将hbm生成ddl,也就是hbm2ddl
Configuration cfg = new Configuration().configure();
SchemaExport export = new SchemaExport(cfg);
export.create(true, true);
8、建立客户端类Client,添加用户数据到mysql
最好加入如下配置项,方便观察hibernate sql的生成:
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
最好加入log4j配置文件,将该配置文件拷贝到src下,便于程序的调试


(二)基础知识


junit简介:
* 编写测试类XXTest,需要继承TestCase
* 编写单元测试方法,方法名称必须为test开头,方法没有参数没有返回值,采用public修饰

* 最好采用单独的目录存放测试程序
* 建议使用断言(this.assertEquals(expected, username);)

掌握HIbernate的CRUD操作


必须掌握get和load方法的差别?
* get不支持lazy,load在默认情况下支持lazy
* get加载数据,如果不存在返回null,而load返回ObjectNotFoundException异常

Transeint
* 没有被session管理
* 在数据库中没有与之匹配的记录

Persistent
* 纳入session管理
* 在数据库中有与之匹配的记录
* 当属性发生改变,在清理缓存时(脏数据检查)会自动和数据库同步

Detached
* 没有被session管理
* 在数据库中存在与之匹配的记录

Session是一个持久化管理器
new一个对象是Transient状态,save或update之后是Persistent状态,关闭session后是detached状态.
commit()之前自动调用了flush(),在flush()时会发sql并清理缓存.
get()立即发sql,load()默认会延迟加载,
//load不会马上发出查询语句,因为load支持lazy(延迟加载/懒加载)
//什么叫lazy?只有真正使用这个对象的时候,再创建,对于hibernate来说
//才真正的发出查询语句,主要是为了提高性能,lazy是hibernate中非常重要的特性
//hibernate的lazy是如何实现的?采用代理对象实现,代理对象主要采用的是CGLIB库生成的
//而不是JDK的动态代理,因为JDK的动态代理只能对实现了接口的类生成代理,CGLIB可以对类
//生成代理,它采用的是继承方式
简单了解hql



(三)hibernate基本映射


实体类---表,采用<class>标签映射
实体类中的普通属性(不包括集合、自定义类和数组)---表字段,采用<property>标签映射


注意:如果实体类的名称或实体类中属性的名称和数据库关键字重复,将会出现问题
   可以考虑采用table属性和column属性对其进行重新命名

实体类的设计原则:
* 实现无参的默认的构造函数
* 提供一个标识
* 建议不要使用final修饰实体类
* 建议为实体类生成getter和setter方法

主要了解如下主键生成策略:
* identity
* sequence
* uuid
* native
* assigned
* foreign
<id name="id" column="user_id" length="32" access="field">
<generator class="uuid"/>
</id>  
了解hibernate.cfg.xml文件中的hbm2ddl属性
 

(四)hibernate多对一关联映射


关联映射,就是将关联关系映射到数据库中,所谓的关联关系
在对象模型中就是一个或多个引用

多对一关联映射原理:在多的一端加入一个外键,指向一的一端

在多的一端采用如下标签映射:
<many-to-one name="group" column="groupid" cascade="save-update"/>

掌握级联的含义?
* 级联是对象之间的连锁操作,它只影响添加、删除和修改
如果不设置cascade时必须显示调用save保存group和user,否则报错.

(五)hibernate一对一主键关联映射(单向关联Person----->IdCard)


一对一关联映射原理:让两个实体的主键一样,这样就不需要加入多余的字段了

<class name="com.bjpowernode.hibernate.Person" table="t_person">
<id name="id">
<!-- 采用foreign生成策略,forgeign会取得关联对象的标识 -->
<generator class="foreign">
<!-- property只关联对象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<!-- 
one-to-one指示hibernate如何加载其关联对象,默认根据主键加载
也就是拿到关系字段值,根据对端的主键来加载关联对象
constrained="true表示,当前主键(person的主键)还是一个外键
参照了对端的主键(IdCard的主键),也就是会生成外键约束语句
-->
<one-to-one name="idCard" constrained="true"/>
</class>


(六)hibernate一对一主键关联映射(双向关联Person<----->IdCard)

需要在IdCard加入<one-to-one>标签,指示hibernate将关联对象Person
根据主键加载上来

<one-to-one>不影响存储,只影响加载


(七)hibernate一对一唯一外键关联映射(单向关联Person----->IdCard)


一对一唯一外键关联映射其实是多对一的特例

采用<many-to-one>标签来映射,指定多的一端unique为true,这样就限制了多的一端的多重性
为一,就是这样来映射的。
Person.hbm.xml:<many-to-one name="idCard" unique="true"/>


(八)hibernate一对一唯一外键关联映射(双向关联Person<----->IdCard)


一对一唯一外键关联双向采用<one-to-one>标签映射,必须指定<one-to-one>
标签中的property-ref属性为关系字段的名称
Person.hbm.xml:<many-to-one name="idCard" unique="true"/>
IdCard.hbm.xml:<one-to-one name="person" property-ref="idCard"/>

(九)session flush测试


session flush方法主要做了两件事:
* 清理缓存
* 执行sql

session在什么情况下执行flush
* 默认在事务提交时
* 显示的调用flush
* 在执行查询前,如:iterate

hibernate按照save(insert),update、delete顺序提交相关操作

(1).uuid生成策略:
//因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理
//不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false
session.save(user);

//调用flush,hibernate会清理缓存,执行sql
//如果数据库的隔离级别设置为为提交读,那么我们可以看到flush过的数据
//并且session中existsInDatebase状态为true
session.flush();

//提交事务
//默认情况下commit操作会先执行flush清理缓存,所以不用显示的调用flush
//commit后数据是无法回滚的
tx.commit();

(2).native生成策略:
//因为user的主键生成策略为native,所以调用session.save后,将执行insert语句,返回有数据库生成的id
//纳入了session的管理,修改了session中existsInDatebase状态为true
//如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据
session.save(user);
tx.commit();

(3).uuid主键生成策略
//因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理
//不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false
session.save(user);

//将user对象从session中逐出,即session的EntityEntries属性中逐出
session.evict(user);

//无法成功提交,因为hibernate在清理缓存时,在session的insertions集合中取出user对象进行insert操作后
//需要更新entityEntries属性中的existsInDatabase为true,而我们采用evict已经将user从session的entityEntries
//中逐出了,所以找不到相关数据,无法更新,抛出异常
tx.commit();


(4).uuid主键生成策略
//因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理
//不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false
session.save(user);

//flush后hibernate会清理缓存,会将user对象保存到数据库中,将session中的insertions中的user对象
//清除,并且设置session中existsInDatebase的状态为true
session.flush();

//将user对象从session中逐出,即session的EntityEntries属性中逐出
session.evict(user);

//可以成功提交,因为hibernate在清理缓存时,在session的insertions集合中无法找到user对象
//所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态
tx.commit();


(5).native主键生成策略
//因为user的主键生成策略为native,所以调用session.save后,将执行insert语句,返回有数据库生成的id
//纳入了session的管理,修改了session中existsInDatebase状态为true
//如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据
session.save(user);

//将user对象从session中逐出,即session的EntityEntries属性中逐出
session.evict(user);

//可以成功提交,因为hibernate在清理缓存时,在session的insertions集合中无法找到user对象
//所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态
tx.commit();


(十)hibernate一对多关联映射(单向Classes--->Student)


一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端

它们的区别在于维护的关系不同:
* 多对一维护的关系是:多指向一的关系,有了此关系,在加载多的时候可以将一加载上来
* 一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来

在一一端维护关系存在缺陷:
* 因为多的一端Student不知道Classes的存在(也就是Student没有维护与Classes的关系)
所以在保存Student的时候关系字段classesid是为null的,如果将该关系字段设置为非空,则
将无法保存数据
* 另外因为Student不维护关系,而Classes维护关系,Classes就会发出多余的update语句,保证
Classes和Student有关系,这样加载Classes的时候才可以把该Classes对应的学生加载上来



(十一)hibernate一对多关联映射(双向Classes<--->Student)


采用一对多双向关联映射的目的主要是为了主要是为了解决一对多单向关联的缺陷
而不是需求驱动的

一对多双向关联的映射方式:
* 在一的一端的集合上采用<key>标签,在多的一端加入一个外键
* 在多的一端采用<many-to-one>标签

!!!注意:<key>标签和<many-to-one>标签加入的字段保持一直,否则会产生数据混乱

inverse属性:
* inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为
false表示本端可以维护关系,如果inverse为true,则本端不能维护关系,会交给另一端
维护关系,本端失效。

所以一对多关联映射我们通常在多的一端维护关系,让一的一端失效,所以设置为inverse为true

inverse和cascade
* inverse是控制方向上的反转,只影响存储
* cascade是操作上的连锁反映
--------------------------------------------
<class name="com.bjpowernode.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="classes" column="classesid"/>
</class>
---------------------------------------------
<class name="com.bjpowernode.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" inverse="true">
<!-- 
<key column="classesid" not-null="true"/>
-->
<key column="classesid"/>
<one-to-many class="com.bjpowernode.hibernate.Student"/>
</set>
</class>
-------------------------------------------------

(十二)hibernate多对多关联映射(单向User--->Role)


具体映射:
<set name="roles" table="t_user_role">
<key column="user_id"/>
<many-to-many class="com.bjpowernode.hibernate.Role" column="role_id"/>
</set>


(十三)hibernate多对多关联映射(双向User--->Role)


映射方法:
<set name="users" table="t_user_role">
<key column="role_id" not-null="true"/>
<many-to-many class="com.bjpowernode.hibernate.User" column="user_id"/>
</set>
------------
<set name="roles" table="t_user_role">
<key column="user_id"/>
<many-to-many class="com.bjpowernode.hibernate.Role" column="role_id"/>
</set>


需要注意:
* 生成的中间表名称必须一样
* 生成的中间表中的字段必须一样

(十四)整棵类继承树一张表

因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,
必须有某种机制来区分哪些记录是属于哪个类的。这种机制就是,在表中添加一个字段,
用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:
父类用普通的<class>标签定义
在父类中定义一个discriminator,即指定这个区分的字段的名称和类型
如:<discriminator column=”XXX” type=”string”/>
子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:
Subclass标签的name属性是子类的全路径名
在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段
(用来区分不同类的字段)的值Subclass标签,既可以被class标签所包含(这种包含关系
正是表明了类之间的继承关系),也可以与class标签平行。 当subclass标签的定义与class
标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的全路径名称。
子类的其它属性,像普通类一样,定义在subclass标签的内部。


关于鉴别值在存储的时候hibernate会自动存储,在加载的时候会根据鉴别值取得相关的对象


get和hql支持多态查询
load在lazy设置为false的情况下支持多态查询


多态查询:hibernate在加载数据的时候,能够采用instancof鉴别出其真正的类型,load在lazy=true时不能鉴别出真正的类型.

(十五)每个类一张表


这种策略是使用joined-subclass标签来定义子类的。父类、子类,每个类都对应一张数据库表。
在父类对应的数据库表中,实际上会存储所有的记录,包括父类和子类的记录;在子类对应的数据库表中,
这个表只定义了子类中所特有的属性映射的字段。子类与父类,通过相同的主键值来关联。
实现这种策略的时候,有如下步骤:
父类用普通的<class>标签定义即可
父类不再需要定义discriminator字段
子类用<joined-subclass>标签定义,在定义joined-subclass的时候,需要注意如下几点:
Joined-subclass标签的name属性是子类的全路径名
Joined-subclass标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。
如:<key column=”PARENT_KEY_ID”/>,这里的column,实际上就是父类的主键对应的映射字段名称。
Joined-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),
也可以与class标签平行。 当Joined-subclass标签的定义与class标签平行的时候,
需要在Joined-subclass标签中,添加extends属性,里面的值是父类的全路径名称。
子类的其它属性,像普通类一样,定义在joined-subclass标签的内部。

(十六)每个具体类一张表

这种策略是使用union-subclass标签来定义子类的。每个子类对应一张表,而且这个表的信息是完备的,
即包含了所有从父类继承下来的属性映射的字段(这就是它跟joined-subclass的不同之处,
joined-subclass定义的子类的表,只包含子类特有属性映射的字段)。实现这种策略的时候,有如下步骤:
父类用普通<class>标签定义即可
子类用<union-subclass>标签定义,在定义union-subclass的时候,需要注意如下几点:
Union-subclass标签不再需要包含key标签(与joined-subclass不同)
Union-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),
也可以与class标签平行。 当Union-subclass标签的定义与class标签平行的时候,需要在Union-subclass标签中,
添加extends属性,里面的值是父类的全路径名称。
子类的其它属性,像普通类一样,定义在Union-subclass标签的内部。这个时候,虽然在union-subclass
里面定义的只有子类的属性,但是因为它继承了父类,所以,不需要定义其它的属性,在映射到数据库表的时候,
依然包含了父类的所有属性的映射字段。

!!!注意:在保存对象的时候id不能重复(不能使用数据库的自增方式生成主键)

(十七)复合(联合)主键映射


通常做法是将主键相关字段放到一个单独的类中,这样类是有要求的:
* 必须实现序列化接口
* 覆盖equals和hashcode方法
<class name="com.bjpowernode.hibernate.FiscalYearPeriod" table="t_fiscal_year_period">
<composite-id name="fiscalYearPeriodPK">
<key-property name="fiscalYear"/>
<key-property name="fiscalPeriod"/>
</composite-id>
<property name="beginDate" type="date"/>
<property name="endDate" type="date"/>
<property name="periodSts"/>
</class>
---------------------------------------------------------
session.beginTransaction();
FiscalYearPeriod fiscalYearPeriod = new FiscalYearPeriod();
//构造复合主键对象
FiscalYearPeriodPK fiscalYearPeriodPK = new FiscalYearPeriodPK();
fiscalYearPeriodPK.setFiscalYear(2009);
fiscalYearPeriodPK.setFiscalPeriod(12);
fiscalYearPeriod.setFiscalYearPeriodPK(fiscalYearPeriodPK);

fiscalYearPeriod.setBeginDate(new Date());
fiscalYearPeriod.setEndDate(new Date());
fiscalYearPeriod.setPeriodSts("Y");

session.save(fiscalYearPeriod);

session.getTransaction().commit();


(十八)Component映射


在hibernate中Component映射采用<component>标签即可

Component是某个实体的逻辑组成部分,它与实体类的主要差别在于,它没有oid
Component在DDD中成为值类

采用Component的好处:实现对象模型的细粒度划分,复用率高,含义明确,层次分明

对象模型与关系模型的设计恰恰相反,对象模型一般是细粒度的,关系模型一般是粗粒度的
<class name="com.bjpowernode.hibernate.Employee" table="t_emplyee">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<component name="employeeContact">
<property name="email"/>
<property name="address"/>
<property name="zipCode"/>
<property name="contactTel"/>
</component>
</class>
--------------------------------
<class name="com.bjpowernode.hibernate.User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<component name="userContact">
<property name="email"/>
<property name="address"/>
<property name="zipCode"/>
<property name="contactTel"/>
</component>
</class>

(十九)完成set、list、array、map的映射


<class name="com.bjpowernode.hibernate.CollectionMapping" table="t_collection_mapping">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="setValues" table="t_set_values">
<key column="set_id"/>
<element type="string" column="set_value" not-null="true"/>
<!-- 
<composite-element class=""></composite-element>
-->
</set>
<list name="listValues" table="t_list_values">
<key column="list_id"/>
<list-index column="list_index"/>
<element type="string" column="list_value"/>
</list>
<array name="arrayValues" table="t_array_values">
<key column="array_id"/>
<list-index column="array_index"/>
<element type="string" column="array_value"/>
</array>
<map name="mapValues" table="t_map_values">
<key column="map_id"/>
<map-key type="string" column="map_key"/>
<element type="string" column="map_value"/>
</map>
</class>


(二十)hibernate的lazy策略可以使用在:


* <class>标签上,可以取值:true/false
* <property>标签上,可以取值:true/false,需要类增强工具,对字节码进行修改
* <set>/<list>标签上,可以取值:true/false/extra
* <many-to-one>/<one-to-one>单端关联标签上,可以取值:false/proxy/noproxy

lazy的概念:在正真使用某个对象的时候才正真的去创建,对于hibernate才会正真的发出sql语句
            去加载该对象
            
hibernate的lazy策略必须在session打开状态下有效

<class>上的lazy只影响普通属性     


(二十一)lazy策略在集合上可以取值,true/false/extra

<class>标签上的lazy不会影响集合上的lazy特性,<class>上的lazy只会影响普通属性


(二十二)hibernate在单端关联上的lazy特性


<many-to-one>/<one-to-one>单端关联标签上,可以取值:false/proxy/noproxy

<class>标签上的lazy不会影响单端关联对象的lazy策略


(二十三)略


(二十四)hibernate查询语言hql


在hql中关键字不区分大小写,通常小写,类的名称和属性名称必须区分大小写

1、简单属性查询【重要】
* 单一属性查询,返会属性结果集列表,元素类型和实体类中相应的类型一致
* 多个属性查询,多个属性查询返会对象数组,对象数组的长度取决于属性的个数
 对象数组中元素的类型取决于属性在实体类中的类型
* 如果认为返会数组不够对象化,可以使用hql动态实例化Student对象,需要提供构造函数
参见:SimplePropertyQueryTest.java

//返回结果集属性列表,元素类型和实体类中的属性类型一致
List students = session.createQuery("select name from Student").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
String name = (String)iter.next();
System.out.println(name);

---------------------------------------------------
 //查询多个属性,返回对象数组集合
//数组元素的类型与查询的属性类型一致
//数组的长度与select中查询的属性个数一致
List students = session.createQuery("select id, name from Student").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
Object[] obj = (Object[])iter.next();
System.out.println(obj[0] + ", " + obj[1]);
}
---------------------------------------------------
 //可以使用hql返回Student对象
//需要提供构造函数
List students = session.createQuery("select new Student(id, name) from Student").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println(student.getId() + ", " + student.getName());
}
2、实体对象查询【重要】
    * N + 1问题,就是发出了N+1条sql语句
    1:首先发出查询对象id列表的语句
    N:根据id到缓存中查询,如果缓存中不存在与之匹配的数据,那么会根据id发出相应的sql语句
    
    *list和iterate的区别?
     list: 默认情况下list每次都会发出sql语句,list会将数据放到缓存中,而不利用缓存
     iterate:默认情况下iterate利用缓存,如果缓存中不存在会出现N+1问题
参见:SimpleObjectQueryTest1.java,SimpleObjectQueryTest2.java     
--------------------------------------------------------
/**
* 会出现N+1问题,所谓的N+1指的是发出了N+1条sql语句

* 1:发出一条查询id列表的语句
* Hibernate: select student0_.id as col_0_0_ from t_student student0_

* N:根据id发出N条sql语句,加载相关的对象
* Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, 
* student0_.createTime as createTime0_0_, student0_.classesid as classesid0_0_ 
* from t_student student0_ where student0_.id=?

*/
Iterator iter = session.createQuery("from Student").iterate();
while (iter.hasNext()) {
Student student = (Student)iter.next();
System.out.println(student.getName());
}
-----------------------------------------------------
List students = session.createQuery("from Student").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println(student.getName());
}
/**
* 避免了N+1问题

* 因为执行list操作后会将数据放到session的缓存中(一级缓存),所以采用iterate的时候
* 首先会发出一条查询id列表的语句,再根据id到缓存中加载相应的数据,如果缓存中存在与之匹配的数据
* 则不再发出根据id查询的sql语句,直接使用缓存中的数据

* Iterate方法如果缓存中存在数据,它可以提高性能,否则出现N+1问题

*/
Iterator iter = session.createQuery("from Student").iterate();
while (iter.hasNext()) {
Student student = (Student)iter.next();
System.out.println(student.getName());
}
----------------------------------------------------------
List students = session.createQuery("from Student").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println(student.getName());
}

/**
* 再此发出查询语句

* 在默认情况下,每次执行list查询实体对象都会发出查询语句,除非配置了查询缓存
* 虽然一级缓存中存在Student数据,但list不用,所以仍然发出查询语句,

* 其实list就是只向缓存中放入数据,而不利用缓存中的数据
*/
students = session.createQuery("from Student").list();
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println(student.getName());

-----------------------------------------------------------
        
3、条件查询【重要】
* 可以采用拼字符串的方式传递参数
* 可以采用 ?来传递参数(索引从0开始)
* 可以采用 :参数名 来传递参数
* 如果传递多个参数,可以采用setParamterList方法
* 在hql中可以使用数据库的函数,如:date_format
参见:SimpleConditionQueryTest.java
----------------------------------------------------
//采用 ?方式,查询学号为1,2,3,4,5的学生
List students = session.createQuery("select s.id, s.name from Student s where s.id in(?, ?, ?, ?, ?)")
.setParameter(0, 1)
.setParameter(1, 2)
.setParameter(2, 3)
.setParameter(3, 4)
.setParameter(4, 5)
.list();
----------------------------------------------------
//采用 :参数名 方式,查询学号为1,2,3,4,5的学生
List students = session.createQuery("select s.id, s.name from Student s where s.id in(:ids)")
.setParameterList("ids", new Object[]{1, 2, 3, 4, 5})
.list();
----------------------------------------------------
4、hibernate直接使用sql语句查询
参见:SqlQueryTest.java
List students = session.createSQLQuery("select * from t_student").list();

5、外置命名查询
    * 在映射文件中使用<query>标签来定义hql
    * 在程序中使用session.getNamedQuery()方法得到hql查询串
    参见:NameQueryTest.java,Student.hbm.xml
Student.hbm.xml文件:
<query name="queryStudent">
<![CDATA[
select s from Student s where s.id <?
]]>
</query>
代码:
List students = session.getNamedQuery("queryStudent").setParameter(0, 10).list();

6、查询过滤器
* 在映射文件中定义过滤器参数
* 在类的映射中使用过滤器参数
* 在程序中必须显示的启用过滤器,并且为过滤器参数赋值
参见:FilterQueryTest.java,Student.hbm.xml

Student.hbm.xml:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="createTime"/>
<many-to-one name="classes" column="classesid"/>
<filter name="testFilter" condition="id &lt; :myid"></filter>
</class>
<filter-def name="testFilter">
<filter-param type="integer" name="myid"/>
</filter-def>
</hibernate-mapping>

FilterQueryTest.java代码:
session.enableFilter("testFilter").setParameter("myid", 10);
List students = session.createQuery("from Student").list();

7、分页查询【重要】
* setFirstResult(),从0开始
* setMaxResults(),每页显示的记录数
参见:PageQueryTest.java

List students = session.createQuery("from Student")
.setFirstResult(1)
.setMaxResults(2)
.list();

8、对象导航查询【重要】
参见:ObjectNavQueryTest.java


List students = session.createQuery("from Student s where s.classes.name like '%2%'")
.list();

9、连接查询【重要】
* 内连接
* 外连接(左连接/右连接)
参见:JoinQueryTest.java

List students = session.createQuery("select c.name, s.name from Student s left join s.classes c").list();

10、统计查询【重要】
参见:StatQueryTest.java
Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();

11、DML风格的操作(尽量少用,因为和缓存不同步)
参见:DMLQueryTest.java
//数据库表中更新了,但缓存不更新
//所以一般不建议使用,除非有必须,如遇到性能问题
session.createQuery("update Student s set s.name=? where s.id<?")
.setParameter(0, "王五")
.setParameter(1, 5)
.executeUpdate();

(二十五)悲观锁


悲观锁,通常是有数据库机制实现的,在整个过程中把数据锁住(查询时),只要事务不释放(提交/回滚)
那么任何用户都不能查看或修改

锁主要是解决并发性问题

Inventory inv = (Inventory)session.load(Inventory.class, "1001", LockMode.UPGRADE);

(二十六)乐观锁


大多数的使用是采用数据版本的方式(version)实现,一般在数据库中加入一个version字段
在读取数据的时候将version读取出来,在保存数据的时候判断version的值是否小于数据库中的
version值,如果小于不予更新,否则给予更新


(二十七)hibernate一级缓存


一级缓存生命周期很短和session的生命周期一致,一级缓存也叫session级的缓存或事务级缓存

哪些方法支持一级缓存:
* load/get/iterate查询实体对象

一级缓存是缓存实体对象的

了解大批量数据更新的做法

Oracle SQL Loader



import java.io.Serializable;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Session;

import junit.framework.TestCase;

public class CacheTest extends TestCase {

	/**
	 * 在同一个session中发出两次load查询
	 */
	public void testCache1() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.load(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			
			//不会发出查询语句,load使用缓存
			student = (Student)session.load(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}		
	
	/**
	 * 在同一个session中发出两次get查询
	 */
	public void testCache2() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.get(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			
			//不会发出查询语句,get使用缓存
			student = (Student)session.get(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}			
	
	/**
	 * 在同一个session中发出两次iterate查询,查询实体对象
	 */
	public void testCache3() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Iterator iter = session.createQuery("from Student s where s.id<5").iterate();
			while (iter.hasNext()) {
				Student student = (Student)iter.next();
				System.out.println(student.getName());
			}
			System.out.println("--------------------------------------");
			//它会发出查询id的语句,但不会发出根据id查询学生的语句,因为iterate使用缓存
			iter = session.createQuery("from Student s where s.id<5").iterate();
			while (iter.hasNext()) {
				Student student = (Student)iter.next();
				System.out.println(student.getName());
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}	
	
	/**
	 * 在同一个session中发出两次iterate查询,查询普通属性
	 */
	public void testCache4() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Iterator iter = session.createQuery("select s.name from Student s where s.id<5").iterate();
			while (iter.hasNext()) {
				String name = (String)iter.next();
				System.out.println(name);
			}
			System.out.println("--------------------------------------");
			
			//iterate查询普通属性,一级缓存不会缓存,所以发出查询语句
			//一级缓存是缓存实体对象的
			iter = session.createQuery("select s.name from Student s where s.id<5").iterate();
			while (iter.hasNext()) {
				String name = (String)iter.next();
				System.out.println(name);
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}		
	
	/**
	 * 在两个session中发load查询
	 */
	public void testCache5() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.load(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.load(Student.class, 1);
			//会发出查询语句,session间不能共享一级缓存数据
			//因为他会伴随着session的消亡而消亡
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
	}		
	
	/**
	 * 在同一个session中先调用save,再调用load查询刚刚save的数据
	 */
	public void testCache6() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = new Student();
			student.setName("张三");
			Serializable id = session.save(student);
			student = (Student)session.load(Student.class, id);
			//不会发出查询语句,因为save支持缓存
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}	
	
	/**
	 * 大批量的数据添加
	 */
	public void testCache7() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			for (int i=0; i<100; i++) {
				Student student = new Student();
				student.setName("张三" + i);
				session.save(student);
				//每20条更新一次
				if (i % 20 == 0) {
					session.flush();
					//清除缓存的内容
					session.clear();
				}
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}			
	
}


(二十八)hibernate二级缓存


二级缓存也称为进程级的缓存或SessionFactory级的缓存,二级缓存可以被所有的session共享
二级缓存的生命周期和SessionFactory的生命周期一致,SessionFactory可以管理二级缓存

二级缓存的配置和使用:
* 将ehcache.xml文件拷贝到src下
* 在hibernate.cfg.xml文件中加入缓存产品提供商
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
* 启用二级缓存,这也是它的默认配置
<property name="hibernate.cache.use_second_level_cache">true</property>
* 指定哪些实体类使用二级缓存
可以在映射文件中采用<cache>标签指定或在hibernate.cfg.xml文件中统一指定
注意使用的策略,通常采用read-only和read-write
缓存原则:通常读远远大于写的数据进行缓存

二级缓存主要是缓存实体对象的

了解一级缓存和二级缓存的交互(session.setCacheMode(CacheMode.IGNORE);)

注意大批量数据更新时,如果配置了二级缓存建议禁用一级缓存和二级缓存的交互

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;

import org.hibernate.CacheMode;
import org.hibernate.Session;

import junit.framework.TestCase;

public class CacheTest extends TestCase {

	/**
	 * 开启二级缓存
	 * 
	 * 在两个session中发load查询
	 */
	public void testCache1() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.load(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.load(Student.class, 1);
			
			//不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据
			//二级缓存是进程级的缓存
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
	}		
	
	/**
	 * 开启二级缓存
	 *  
	 * 在两个session中发get查询
	 */
	public void testCache2() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.get(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.get(Student.class, 1);
			
			//不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据
			//二级缓存是进程级的缓存
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
	}	
	
	/**
	 * 开启二级缓存
	 *  
	 * 在两个session中发load查询,采用SessionFactory管理二级缓存
	 */
	public void testCache3() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.load(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
		//管理二级缓存
		//HibernateUtils.getSessionFactory().evict(Student.class);
		HibernateUtils.getSessionFactory().evict(Student.class, 1);
		
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.load(Student.class, 1);
			
			//会发出查询语句,因为二级缓存中的数据被清除了
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}
	
	
	/**
	 * 开启二级缓存
	 *  
	 * 一级缓存和二级缓存的交互 
	 */
	public void testCache4() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			//禁止将一级缓存中的数据放到二级缓存中
			session.setCacheMode(CacheMode.IGNORE);
			Student student = (Student)session.load(Student.class, 1);
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}

		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Student student = (Student)session.load(Student.class, 1);
			
			//会发出查询语句,因为禁止了一级缓存和二级缓存的交互
			System.out.println("student.name=" + student.getName());
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}
	
	/**
	 * 大批量的数据添加
	 */
	public void testCache5() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			//禁止一级缓存和二级缓存交互
			session.setCacheMode(CacheMode.IGNORE);
			for (int i=0; i<100; i++) {
				Student student = new Student();
				student.setName("张三" + i);
				session.save(student);
				//每20条更新一次
				if (i % 20 == 0) {
					session.flush();
					//清除缓存的内容
					session.clear();
				}
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}			
}


(二十九)hibernate查询缓存


查询缓存缓存什么?
* 查询缓存是缓存普通属性结果集的
* 对实体对象的结果集会缓存id
查询缓存的生命周期,当关联的表发生修改,查询缓存的生命周期结束


查询缓存的配置和使用:
* 修改hibernate.cfg.xml文件,来开启查询缓存,默认是false是不起用的
<property name="hibernate.cache.use_query_cache">true</property>
* 必须在程序启用
query.setCacheable(true)


import java.io.Serializable;
import java.util.Iterator;
import java.util.List;

import org.hibernate.CacheMode;
import org.hibernate.Session;

import junit.framework.TestCase;

public class CacheTest extends TestCase {

	/**
	 * 开启查询,关闭二级缓存,采用query.list()查询普通属性
	 * 
	 * 在一个session中发query.list()查询
	 */
	public void testCache1() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			List names = session.createQuery("select s.name from Student s")
								.setCacheable(true)
								.list();
			for (int i=0; i<names.size(); i++) {
				String name = (String)names.get(i);
				System.out.println(name);
			}
			System.out.println("-------------------------------------------------------");
			//不会发出查询语句,因为启用查询缓存
			names = session.createQuery("select s.name from Student s")
							.setCacheable(true)
							.list();
			for (int i=0; i<names.size(); i++) {
				String name = (String)names.get(i);
				System.out.println(name);
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}
	
	/**
	 * 开启查询,关闭二级缓存,采用query.list()查询普通属性
	 * 
	 * 在两个session中发query.list()查询
	 */
	public void testCache2() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			List names = session.createQuery("select s.name from Student s")
								.setCacheable(true)
								.list();
			for (int i=0; i<names.size(); i++) {
				String name = (String)names.get(i);
				System.out.println(name);
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		System.out.println("-------------------------------------------------------");
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			//不会发出查询语句,因为查询缓存和session的生命周期没有关系
			List names = session.createQuery("select s.name from Student s")
								.setCacheable(true)
								.list();
			for (int i=0; i<names.size(); i++) {
				String name = (String)names.get(i);
				System.out.println(name);
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
	}		
	
	/**
	 * 开启查询,关闭二级缓存,采用query.iterate()查询普通属性
	 * 
	 * 在两个session中发query.iterate()查询
	 */
	public void testCache3() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			Iterator iter = session.createQuery("select s.name from Student s")
								.setCacheable(true)
								.iterate();
			while(iter.hasNext()) {
				String name = (String)iter.next();
				System.out.println(name);
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		System.out.println("-------------------------------------------------------");
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			//会发出查询语句,query.iterate()查询普通属性它不会使用查询缓存
			//查询缓存只对query.list()起作用
			Iterator iter = session.createQuery("select s.name from Student s")
							.setCacheable(true)
							.iterate();
			while(iter.hasNext()) {
				String name = (String)iter.next();
				System.out.println(name);
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
	}
	
	/**
	 * 关闭查询,关闭二级缓存,采用query.list()查询实体
	 * 
	 * 在两个session中发query.list()查询
	 */
	public void testCache4() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			List students = session.createQuery("select s from Student s")
								.list();
			for (int i=0; i<students.size(); i++) {
				Student studnet = (Student)students.get(i);
				System.out.println(studnet.getName());
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		System.out.println("-------------------------------------------------------");
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			//会发出查询语句,默认query.list()每次执行都会发出查询语句
			List students = session.createQuery("select s from Student s")
								.list();
			for (int i=0; i<students.size(); i++) {
				Student studnet = (Student)students.get(i);
				System.out.println(studnet.getName());
			}
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
	}	
	
	/**
	 * 开启查询,关闭二级缓存,采用query.list()查询实体
	 * 
	 * 在两个session中发query.list()查询
	 */
	public void testCache5() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			List students = session.createQuery("select s from Student s")
								.setCacheable(true)
								.list();
			for (int i=0; i<students.size(); i++) {
				Student studnet = (Student)students.get(i);
				System.out.println(studnet.getName());
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		System.out.println("-------------------------------------------------------");
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			//会发出n条查询语句,因为开启了查询缓存,关闭了二级缓存,那么查询缓存就会缓存实体对象的id
			//第二次执行query.list(),将查询缓存中的id依次取出,分别到一级缓存和二级缓存中查询相应的实体
			//对象,如果存在就使用缓存中的实体对象,否则根据id发出查询学生的语句
			List students = session.createQuery("select s from Student s")
								.setCacheable(true)
								.list();
			for (int i=0; i<students.size(); i++) {
				Student studnet = (Student)students.get(i);
				System.out.println(studnet.getName());
			}
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
	}	
	
	/**
	 * 开启查询,开启二级缓存,采用query.list()查询实体
	 * 
	 * 在两个session中发query.list()查询
	 */
	public void testCache6() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			List students = session.createQuery("select s from Student s")
								.setCacheable(true)
								.list();
			for (int i=0; i<students.size(); i++) {
				Student studnet = (Student)students.get(i);
				System.out.println(studnet.getName());
			}
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		System.out.println("-------------------------------------------------------");
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			//不再发出查询语句,因为配置了二级缓存和查询缓存
			List students = session.createQuery("select s from Student s")
								.setCacheable(true)
								.list();
			for (int i=0; i<students.size(); i++) {
				Student studnet = (Student)students.get(i);
				System.out.println(studnet.getName());
			}
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
		
	}		
}


(三十)hibernate抓取策略,单端代理的批量抓取


保持默认,同fetch="select",如:
<many-to-one name="classes" column="classesid" fetch="select"/>

fetch="select",另外发送一条select语句加载当前对象的关联对象或集合

fetch为select或join不影响hql,它影响的是load,get方法


(三十一)hibernate抓取策略,单端代理的批量抓取


设置fetch="join",如:
<many-to-one name="classes" column="classesid" fetch="join"/>

fetch="join",hibernate会通过一个select语句连接(内联/外联)抓取其关联对象或集合

fetch="join",那么lazy失效

fetch="join",只影响get和load,对hql没有影响

<many-to-one>可能会出现N+1问题,
如:查询100个学生显示到列表中:
  * 首先会发出查询学生的sql语句
  * 然后会发出根据班级id查询班级的sql语句
  这样就会导致N+1问题,也就是发出了N+1条语句,会严重影响性能
  
所以我们可以采用预先抓取的策略,如:
select s from Student s join fetch s.classes

(三十二)hibernate抓取策略,集合代理的批量抓取


保持默认,同fetch="select",如:
<set name="students" order-by="id" inverse="true" cascade="all" fetch="select">

fetch="select",另外发送一条select语句加载当前对象的关联对象或集合
  

(三十三)hibernate抓取策略,集合代理的批量抓取


设置fetch="join",如:
<set name="students" order-by="id" inverse="true" cascade="all" fetch="join">

fetch="join",hibernate会通过一个select语句连接(内联/外联)抓取其关联对象或集合

fetch="join",那么lazy失效

fetch="join",只影响get和load,对hql没有影响



(三十四)hibernate抓取策略,集合代理的批量抓取


设置fetch="subselect",如:
<set name="students" order-by="id" inverse="true" cascade="all" fetch="subselect">

fetch="subselect",另外发送一条select语句抓取在前面查询到的所有实体的关联集合

fetch="subselect",会影响hql查询


(三十五)hibernate抓取策略,batch-size在<class>的应用


batch-size属性,可以批量加载实体类,参见Classes.hbm.xml
<class name="com.bjpowernode.hibernate.Classes" table="t_classes" batch-size="10">


(三十六)hibernate抓取策略,batch-size在集合上的应用


batch-size属性,可以批量加载实体类,参见Classes.hbm.xml
<set name="students" order-by="id" inverse="true" cascade="all" batch-size="3">


(三十七)略


(三十八)略


(三十九)第一个hibernate(hibernate annotation) JPA项目


1、建立java项目
2、创建User Library,加入依赖包
* HIBERNATE_HOME/lib/*.jar
* HIBERNATE_HOME/hibernate3.jar
* 加入数据库驱动(mysql驱动)
3、加入hibernate annotation支持包
* hibernate-annotations.jar
* ejb3-persistence.jar
* hibernate-commons-annotations.jar
4、提供hibernate.cfg.xml文件,完成基本的配置
5、建立实体类User.java
5、采用注解完成映射
6、将实体类加入到hibernate.cfg.xml配置文件中,注意与hbm.xml文件有区别
<mapping class="com.bjpowernode.hibernate.User"/>

7、编写工具类ExoprtDB.java,注解生成ddl,必须采用AnnotationConfiguration类,注意与hbm.xml配置文件方式不同,
Configuration cfg = new AnnotationConfiguration().configure();//annotation方式
Configuration cfg = new Configuration().configure();//文件方式

8、建立客户端类Client,添加用户数据到mysql

(四十)hibernate jpa基本映射


了解常用注解:
@Entity
@Id
@Table
@GeneratedValue
@Transient
@Column

采用如下注解会默认采用数据库的主键生成能力,相当于hibernate中的native
@GeneratedValue相当于@GeneratedValue(strategy=GenerationType.AUTO)


了解如何采用hibernate的uuid生成主键
//采用hibernate uuid生成器
@Id
@GenericGenerator(name="myIdGenerator",strategy="uuid")
@GeneratedValue(generator="myIdGenerator")
public String getId() {
return id;
}


(四十一)hibernate JPA多对一关联映射


采用@ManyToOne来映射多对一
关于关联对象在表中的维护,JPA会采用关联对象+"_" + "id"方式作为字段加入表中
@Entity
@Table(name="t_user")
public class User {
...
@ManyToOne
public Group getGroup() {
return group;
}
...
}


(四十二)hibernate JPA一对多关联映射


采用@OneToMany来映射
了解mappedBy属性
了解targetEntity属性
了解@JoinColumn注解
@Entity
@Table(name="t_student")
public class Student {
...
@ManyToOne
@JoinColumn(name="classesid")
public Classes getClasses() {
return classes;
}
...
}
-----------------
@Entity
@Table(name="t_classes")
public class Classes {
...
//mappedBy在哪一端,哪一端就不维护关系,它成为了关系的被管理端
//向当于hibernate中的inverse=true
//如果采用了泛型,可以不用采用targetEntity属性
@OneToMany(mappedBy="classes",targetEntity=Student.class)
@JoinColumn(name="classesid")
public Set getStudents() {
return students;
}
...
}


(四十三)hibernate jpa多对多关联映射


采用ManyToMany映射
采用@JoinTable指定第三方表的名称


@Entity
@Table(name="t_role")
public class Role {
...
@ManyToMany(mappedBy="roles")
public Set<User> getUsers() {
return users;
}
...
}

----------------------------------------
@Entity
@Table(name="t_user")
public class User {
...
//因为集合使用泛型所以不再使用targetEntity来指定类型
@ManyToMany
@JoinTable(
name="t_user_role",
joinColumns={@JoinColumn(name="user_id")},
inverseJoinColumns={@JoinColumn(name="role_id")}
)
public Set<Role> getRoles() {
return roles;
}
...
}


(四十四)采用JPA映射每棵类继承树一张表


@Entity
@Table(name="t_animal")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.STRING)
public class Animal {...

--------------------------------------------
@Entity
@DiscriminatorValue(value="P")
public class Pig extends Animal {...

----------------------------------------------
@Entity
@DiscriminatorValue(value="B")
public class Bird extends Animal {...

(四十五)采用JPA映射每个类一张表


@Entity
@Table(name="t_animal")
@Inheritance(strategy=InheritanceType.JOINED)
public class Animal {...

(四十六)采用JPA映射每个具体类一张表


@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)

public class Animal {...


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值