定义Pojo对象和**.hbm.xml文件
-1 对于每一个需要持久化的对象都需要创建一个Pojo类定义,Hibernate要求POJO类定义中必须有一个no-argument的构造方法,便于Hibernate通过java reflection机制创建实例:[java.lang.reflect.Constructor.newInstance()];
-2 对于Pojo类定义中的类属性而言,不管访问符是否为public,也不管是否提供了对应的setter/getter方法,Hibernate都可以通过java reflection进行访问,类属性类型最好使用装箱类型,便于业务隔离;
-3 Hibernate也不要求每一个POJO必须实现Serializable接口,但如果对采用RMI和J2EE分布式结构的应用,POJO在不同进程节点之间传输时,或者在HttpSession内,则一定需要实现此接口;
1 <hibernate-mapping package="com.leo.chen.dao.hibernate"> 2 <class name="User" table="user" dynamic-insert="true" dynamic-update="true"> 3 <id name="id" column="id" access="property"> 4 <generator class="native"></generator> 5 </id> 6 <property name="name" column="name access="field"></property> 7 <property name="password" column="password" access="field"></property> 8 </class> 9 </hibernate-mapping>
指定插入行的primary key生成策略
设计数据库表的时候主键ID一般使用非业务相关的独立字段,从而保证主键在任何时候都不受业务变动的影响,对于<generator>而言hibernate提供了多种实现方式:
#1 代理主键:increment
由hibernate负责生成,每次增量为1,插入一条数据会执行两个sql语句,先从表中查找出最大的id,执行加1,然后插入当前数据;适用于所有数据库,但是如果多个SessionFactory同时连接一个DB,则increment的自增操作失效;仅适合DB被单个Hibernate App访问的场景;OID必须为Long、INT或者Short;
#2 代理主键:identity
由底层数据库负责生成,依赖数据库的主键自增功能;由DB设置,根据不同DB配置不同的DB dialect,从而映射成不同的类型,MySQL为auto_increment,SQL Server为identity;底层数据库必须支持自动增长字段的类型;OID必须为Long、INT或者Short;
#3 代理主键:sequence
由Hibernate设置,但序列来自于底层数据库;底层数据库必须支持序列,MySQL不支持序列,Oracle,DB2和PostgreSQL支持;OID必须为Long、INT或者Short;
#4 单自然主键:assigned
表示由应用程序为当前赋值,并且该属性为自然主键,业务相关,永远不会为null;一般而言saveOrUpdate()方法通过判断主键ID是否为null来确定对象的状态,当主键的生成属性generator为assigned的时候则不能判断;只能通过额外的属性<version>来控制;如果unsaved-value为null就表示为临时对象,非null就表示游离对象;
1 <hibernate-mapping> 2 <class name="org.hibernate.tutorial.domain.Cart" 3 table="CARTS" dynamic-update="true"> 4 <id name="name" type="string" access="field"> 5 <column name="CART_NAME" /> 6 <generator class="assigned" /> 7 </id> 8 <version name="version" column="VERSION" 9 unsaved-value="null"/> 10 </class> 11 </hibernate-mapping>
#5 复合自然主键:composite-id
Customer对象由CustomerId对象确定,CustomerId由name和company组成; 凡是由自然键担任主键的class都需要定义version属性以区分状态;<many-to-one>标签表示company与customer为多对一的关系;Insert和update属性为false表示当customer对象被保存的时候,会忽略company属性;
1 <hibernate-mapping> 2 <class name="mypack.Customer" table="CUSTOMERS"> 3 <composite-id name="customerId" class="mypack.CustomerId"> 4 <key-property name="name" column="NAME" type="string" /> 5 <key-property name="company" column ="COMPANY_ID" type="long" /> 6 </composite-id> 7 <version name="version" column="VERSION" unsaved-value="null" /> 8 <many-to-one name="company" column="CLIENT_ID" 9 insert="false” update="false” 10 class="org.hibernate.tutorial.domain.Company" /> 11 </class> 12 </hibernate-mapping>
#6 hilo:由hibernate根据hilo算法自己生成主键。
#7 native:根据底层数据库对自动生成主键的支持能力选择 identity|sequence|hilo
#8 uuid :根据当前机器的mac地址和time生成UUID作为主键。
#9 customized class:可以通过实现org.hibernate.id.IdentifierGenerator接口自定义id。
指定Dao类属性的访问方式
<id>和<property>的属性access可以控制类属性的访问方式,缺省为property:
#1 access=”field”:表示让hibernate通过反射的方式直接访问field,丢失封装性;
#2 access=”property”:表示让hibernate通过类对外暴露的getter/setter访问field,推荐;
指定Dao类和关联对象的数据加载策略和SQL生成方式
加载Dao对象<class>元素可以使用属性lazy控制类数据的加载时机,缺省为true;
#1 lazy=”true”:当使用load()加载对象时会先生成一个代理对象,其中只有primary key被赋值,其他属性只有等对象实际被使用时才会生成SQL语句到DB进行查询。
#2 lazy=”false”:立即加载,也就是使用load方法会立即生成SQL到DB进行查询。
级联查询<set>元素使用lazy来控制关联对象的加载时机,缺省值为true;
#1 lazy=”true”:跟<class>级别同理;
#2 lazy=”false”:跟<class>级别同理;
#3 lazy=”extra”:采用精细化的延迟加载,比如关联对象调用size/contains/isEmpty等非访问整个集合的元素方法时,不会加载整个集合元素,仅生成返回特定信息的SQL;
级联查询<set>元素使用fetch来控制查询关联对象时的SQL生成策略
#1 fetch=”select”:缺省值,额外生成一条SQL进行独立查询。
#2 fetch=”subselect”:额外生成一条SQL查询集合数据,比如当查询多个用户,每个用户上有多个订单,这样可以通过一条独立的SQL 将所有用户的所有订单一次性查询出来,在内存中将不同的订单分配到不同用户上。
#3 fetch=”join”:采用LEFT JOIN table的方式生成唯一SQL,减少执行SELECT的次数,同时会忽略lazy属性,立即加载所有数据,但由于关联多张表,可以造成性能下降;
级联查询<many-to-one>/<one-to-many>也有lazy和fetch属性,功能也类似。另外<class>和<set>元素上设置batch-size=”10”可以生成批量加载数据的SQL将数据放入缓存,从而减少SQL语句的执行条数。
通过sql语句获取复杂查询的字段值
Hibernate将根据formula的sql语句动态为totalPrice设置值,formula可以操作各表字段,所以并不需要orders表中有total_price的字段;如果formula查询的结果为空则totalPrice的值返回null,因此Java类中totalPrice的属性需要设置为Double包装类型。
1 <property name=”totalPrice” 2 formula=”SELECT SUM(o.price) FROM orders o WHERE o.customer_id=id” />
强制动态生成insert和update的SQL语句
缺省情况下Hibernate会预先生成并编译针对所有column的insert和update子句;但预编译好的sql语句不管待写入DB的字段是否为空,也不管待写入DB的字段是否有更新,都全部进行操作,当column比较多的时候缺省设置会耗费比较多的DB资源;因此Hibernate提供关键字用于控制<class>上各个column的插入和更新:
#1 insert属性:缺省为true;如果为false,表示Hibernate不再为insert生成price字段,也就是该DB column不能被插入;
<property name=”price” insert=”false” />
#2 update属性:缺省为true;如果为false,表示Hibernate不再为update生成price字段,也就是该DB column不能被更新;
<property name=”price” update=”false” />
#3 mutable属性:缺省为true;如果为false,表示所有该class的property的update属性为false,该实例不能被更新;
<class name=”org.hibernate.totorial.domain.User” table=”USER” mutable=”false” />
#4 dynamic-insert属性:缺省为false;如果为true,表示插入一个对象时动态生成insert语句,insert的字段仅包含取值不为null的字段;
<class name=”org.hibernate.totorial.domain.User” table=”USER” dynamic-insert=”true” />
#5 dynamic-update属性:缺省为false;如果为true,表示更新一个对象时动态生成update语句,update的字段仅包含取值有更新的字段;
<class name=”org.hibernate.totorial.domain.User” table=”USER” dynamic-update=”true” />
#6 select-before-update属性:缺省为false,表示只要使用Session.update(),则不管目标对象的属性是否有更新都会执行UPDATE操作;如果为true,则会先执行一条SELECT语句查询DB的状态并对比是否有更新,表示仅当目标对象的属性被修改时才执行UPDATE操作;
<class name=”org.hibernate.totorial.domain.User” table=”USER” select-before-update=”true” />