Hibernate ORM(2):Hibernate实践记录之一
2015-11-05 19:33
225 查看
#1 ORM文件中,<property>元素的access属性可以指定待持久化类属性的访问方式
property为缺省访问方式,则hibernate通过setter和getter访问属性。因此如果一个字段仅在ORM文件有定义、在java类中并无定义,java类只要提供其setter/getter后,hibernate仍旧可以读取这个值。
如果某个属性没有setter/getter,或者access设置为field,则hibernate用过反射直接访问属性;
#2 动态映射字段
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的插入和更新:
缺省为true;如果为false,表示Hibernate不再为insert生成price字段,也就是该DB column不能被插入;
缺省为true;如果为false,表示Hibernate不再为update生成price字段,也就是该DB column不能被更新;
缺省为true;如果为false,表示所有该class的property的update属性为false,该实例不能被更新;
缺省为false;如果为true,表示插入一个对象时动态生成insert语句,insert的字段仅包含取值不为null的字段;
缺省为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一般使用非业务相关的独立字段,从而保证主键在任何时候都不受业务变动的影响;
常用的主键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就表示游离对象;
复合自然主键composite-id:
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类型的类属性
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>标签,同上
WINE的映射文件中需要定义<set>标签,在类中则对应Set<InOrder>类型的类属性
name对应java类中的属性名;
inverse 优化Hibernate性能;
cascade表示是否对inOrders属性执行级联策略,取值为none(缺省值), save-update(级联保存和更新), delete(级联删除), all-delete-orphan(级联删除解除关联的对象)
<key>对应级联属性的外键;
<one-to-many>对应级联属性的类型;
首先分别持久化两个不相关的WINE和IN_ORDER,然后在他们之间建立关联,需要在java代码中执行如下代码,
Hibernate一旦检测到内存中类属性的变动(wine的inOrders属性,inOrder的wine属性)则会独立执行sql语句,因此会执行两条sql语句;但实际效果仅仅是更新IN_ORDER表的WINE_ID列,为了解决这个性能问题,Hibernate引入inverse=”true”属性,仅执行wine一方的属性变动;
在建立两个对象的双向关联时,应该同时修改关联两端的对象的属性,以保证程序的健壮性;同样,解除关联也必须是双方同时解除;
<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一方的属性变动;
在建立两个对象的双向关联时,应该同时修改关联两端的对象的属性,以保证程序的健壮性;同样,解除关联也必须是双方同时解除;
相关文章推荐
- sha-1 签名的java实现
- Oracle开发之:窗口函数 3( rows between unbounded preceding and current row)
- Java:使用synchronized和Lock对象获取对象锁
- 【Java线程】锁机制:synchronized、Lock、Condition
- linux下的用户组管理
- 冒泡排序 文法树
- 分享个用Android Studio多渠道打包教程链接
- 【UML】RUP开发过程
- 基于Mavell Wifi模块的透传程序
- PHP 获取二维数组中某个key的集合
- 关于Only the original thread that created a view hierarchy can touch its views的解决方案
- 第11讲 项目1-分离各位数
- 文章标题
- interrupt()中断
- Oracle开发专题之:分析函数2(Rank, Dense_rank, row_number)
- [leetcode#6]ZigZag Conversion
- Centos7 install Openstack - (第三节)添加镜像服务(Glance)
- hdoj2036 c语言实现(任意多边形的面积
- linux下安装配置nginx
- 带有下拉刷新功能的Listview控件