您的位置:首页 > 其它

Hibernate ORM(2):Hibernate实践记录之一

2015-11-05 19:33 225 查看
#1 ORM文件中,<property>元素的access属性可以指定待持久化类属性的访问方式

<property name="userName" type="string" access="property">

<column name="USER_NAME" length="20" not-null="true" />

</property>


property为缺省访问方式,则hibernate通过setter和getter访问属性。因此如果一个字段仅在ORM文件有定义、在java类中并无定义,java类只要提供其setter/getter后,hibernate仍旧可以读取这个值。

<property name="createdBy" type="string" access="field">

<column name="CREATED_BY" length="20" not-null="true" />

</property>


如果某个属性没有setter/getter,或者access设置为field,则hibernate用过反射直接访问属性;

#2 动态映射字段

<property name=”totalPrice” formula=”SELECT SUM(o.price) FROM orders o WHERE o.customer_id=id” />


Hibernate将根据formula的sql语句动态为totalPrice设置值,formula可以操作各表字段,所以并不需要orders表中有total_price的字段;如果formula查询的结果为空则totalPrice的值返回null,因此Java类中totalPrice的属性需要设置为Double包装类型。

#3 动态生成INSERT和UPDATE语句

缺省情况下Hibernate会预先生成并编译针对所有column的insert和update子句;但预编译好的sql语句不管待写入DB的字段是否为空,也不管待写入DB的字段是否有更新,都全部进行操作,当column比较多的时候缺省设置会耗费比较多的DB资源;

因此Hibernate一并提供关键字用于控制column的插入和更新:

<property name=”price” insert=”false” />


缺省为true;如果为false,表示Hibernate不再为insert生成price字段,也就是该DB column不能被插入;

<property name=”price” update=”false” />


缺省为true;如果为false,表示Hibernate不再为update生成price字段,也就是该DB column不能被更新;

<class name=”org.hibernate.totorial.domain.User” table=”USER” mutable=”false” />


缺省为true;如果为false,表示所有该class的property的update属性为false,该实例不能被更新;

<class name=”org.hibernate.totorial.domain.User” table=”USER” dynamic-insert=”true” />


缺省为false;如果为true,表示插入一个对象时动态生成insert语句,insert的字段仅包含取值不为null的字段;

<class name=”org.hibernate.totorial.domain.User” table=”USER” dynamic-update=”true” />


缺省为false;如果为true,表示更新一个对象时动态生成update语句,update的字段仅包含取值有更新的字段;

#4 java.sql.Date & java.util.Date & java.sql.Time & java.sql.Timestamp的区别

Java.util.Date的时间格式为:yyyy/mm/dd/ : hh/mm/ss

Java.sql.Date的时间格式为:yyyy/mm/dd

Java.sql.time的时间格式为:hh/mm/ss

Java.sql.Timestamp的时间格式为:yyyy/mm/dd/ : hh/mm/ss/ns

Java.util.Calender深入封装了java.util.Date,并且功能更全面

#5 数据库表主键ID的设置

设计数据库表的时候主键ID一般使用非业务相关的独立字段,从而保证主键在任何时候都不受业务变动的影响;

<hibernate-mapping>

<class name="org.hibernate.tutorial.domain.Cart" table="CARTS" dynamic-update="true">

<id name="cartID" type="int" access="field">

<column name="CART_ID" />

<generator class="increment" />

</id>

</class>

</hibernate-mapping>


常用的主键ID生成器如下:

代理主键Increment:

由Hibernate设置,适用于所有数据库;

如果多个SessionFactory同时连接一个DB,则increment的自增操作失效;

仅适合DB被单个Hibernate App访问的场景;

OID必须为Long、INT或者Short;

代理主键Identity:

由DB设置,根据不同DB配置不同的DB dialect,从而映射成不同的类型,MySQL为auto_increment,SQL Server为identity;

底层数据库必须支持自动增长字段的类型;

OID必须为Long、INT或者Short;

代理主键Sequence:

由Hibernate设置,但序列来自于底层数据库;

底层数据库必须支持序列,MySQL不支持序列,Oracle,DB2和PostgreSQL支持;

OID必须为Long、INT或者Short;

单自然主键assigned:

表示由应用程序为当前赋值,并且该属性为自然主键,业务相关,永远不会为null;

一般而言saveOrUpdate()方法通过判断主键ID是否为null来确定对象的状态,当主键的生成属性generator为assigned的时候则不能判断;只能通过额外的属性<version>来控制;如果unsaved-value为null就表示为临时对象,非null就表示游离对象;

<hibernate-mapping>

<class name="org.hibernate.tutorial.domain.Cart" table="CARTS"

dynamic-update="true">

<id name="name" type="string" access="field">

<column name="CART_NAME" />

<generator class="assigned" />

</id>

<version name="version" column="VERSION" unsaved-value="null"/>

</class>

</hibernate-mapping>


复合自然主键composite-id:

<hibernate-mapping>

<class name="mypack.Customer" table="CUSTOMERS">

<composite-id name="customerId" class="mypack.CustomerId">

<key-property name="name" column="NAME" type="string" />

<key-property name="company" column ="COMPANY_ID" type="long" />

</composite-id>

<version name="version" column="VERSION" unsaved-value="null" />

<many-to-one name="company" column="CLIENT_ID"

insert="false” update="false”

class="org.hibernate.tutorial.domain.Company" />

</class>

</hibernate-mapping>


Customer对象由CustomerId对象确定,CustomerId由name和company组成;

凡是由自然键担任主键的class都需要定义version属性以区分状态;

<many-to-one>标签表示company与customer为多对一的关系;

Insert和update属性为false表示当customer对象被保存的时候,会忽略company属性;

#6 多对一单向关联关系

如果将IN_ORDER和WINE设计为多对一的单向关联关系,则IN_ORDER类中需要定义一个WINE属性,WINE类中则无须定义IN_ORDER的set集合属性;

IN_ORDER的映射文件中需要定义<many-to-one>标签,在类中则对应Wine类型的类属性

<many-to-one name="wine"

column="WINE_ID"

class="org.hibernate.tutorial.domain.Wines"

not-null="true"

cascade="save-update"

lazy="true" />


name对应java类中的属性名;

column对应db表中的外键名;

class对应关联属性的类型;

not-null缺省为false,如果为true表示增加关联属性的约束检查,保存IN_ORDER对象时会检查WINE是否为null,如果此时WINE还没有持久化则抛出异常;

cascade缺省为none,表示不进行级联更新;如果为save-update则在更新IN_ORDER对象的同时会级联更新WINE对象;

lazy缺省为proxy,表示对WINE对象使用延迟检索策略并使用代理;如果为false则在加载IN_ORDER对象的同时就会检索并加载WINE对象;

由于是多对一的单向关联,则WINE的映射文件中无须定义<set>标签;

当Hibernate持久化一个临时对象(IN_ORDER)时,缺省情况下并不会自动持久化其关联的临时对象(WINE),因此会报错;可以通过<many-to-one>标签的cascade=”save-update”属性解决,表示当IN_ORDER进行insert或者update操作时,会优先对关联对象WINE执行insert或者update;

#7 多对一双向关联关系

类与类之间设计成是单向关联还是双向关联,这是由具体业务决定;如果将IN_ORDER和WINE设计为多对一的双向关联关系,则IN_ORDER类中需要定义一个WINE属性,WINE类中需要定义IN_ORDER的set集合属性;

IN_ORDER的映射文件中需要定义<many-to-one>标签,同上

<many-to-one name="wine"

column="WINE_ID"

class="org.hibernate.tutorial.domain.Wines"

not-null="true"

cascade="save-update"

lazy="true" />


WINE的映射文件中需要定义<set>标签,在类中则对应Set<InOrder>类型的类属性

<set name="inOrders" inverse="true" cascade="save-update">

<key column="IN_ORDER_ID" />

<one-to-many class="org.hibernate.tutorial.domain.InOrders" />

</set>


name对应java类中的属性名;

inverse 优化Hibernate性能;

cascade表示是否对inOrders属性执行级联策略,取值为none(缺省值), save-update(级联保存和更新), delete(级联删除), all-delete-orphan(级联删除解除关联的对象)

<key>对应级联属性的外键;

<one-to-many>对应级联属性的类型;

首先分别持久化两个不相关的WINE和IN_ORDER,然后在他们之间建立关联,需要在java代码中执行如下代码,

wine.getInOrders().add(inOrder);

inOrder.setWine(wine);


Hibernate一旦检测到内存中类属性的变动(wine的inOrders属性,inOrder的wine属性)则会独立执行sql语句,因此会执行两条sql语句;但实际效果仅仅是更新IN_ORDER表的WINE_ID列,为了解决这个性能问题,Hibernate引入inverse=”true”属性,仅执行wine一方的属性变动;

在建立两个对象的双向关联时,应该同时修改关联两端的对象的属性,以保证程序的健壮性;同样,解除关联也必须是双方同时解除;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: