Hibernate 学习小结

    技术2022-05-11  64

    一、PO的数据类型设置 int 还是Integer Integer 允许为 null Hibernate 既可以访问Field也可以访问Property,访问Property是只是调用getXXX()、setXXX()方法,因此在from Customer where c.name=’Tom’ HQL中,name属性不需要存在,只要getName()存在就可以了。

    二、Hibernate映射

    1、映射复合主键

    代码 主键类   Public class CustomerId implements Serializable{       Private final String name;       Private final String companyid;   }   映射文件   <class name=”test.Customer” table=”CUSTOMERS”>      <composite-id name=”customerId” class=”test.CustomerId”>          <key-property name=”name” column=”NAME” type=”string”/>          <key-property name=”companyId” column=”COMPANY_ID”  type=”long”/>      </composite-id>      <version name=”varsion” column=”VERSION” unsaved-value=”0”/>      <many-to-one name=”company” class=”test.Company” column=”COMPANY_ID” insert=”false” update=”false”/>      <set name=”orders” lazy=”true” inverse=”true”>          <key>              <columncolumn=”NAME”/>              <columncolumn=”COMPANY_ID”/>          </key>      </set>  </class>  <class name=”test.Order” table=”ORDERS”>      <many-to-one name=”customer” class=”test.Customer”>              <columncolumn=”NAME”/>              <columncolumn=”COMPANY_ID”/>      </many-to-one>  </class>    或     <class name=”test.Customer” table=”CUSTOMERS”>      <composite-id name=”customerId” class=”test.CustomerId”>          <key-property name=”name” column=”NAME” type=”string”/>  <key-many-to-one name=”company” class=”test.Company” column=”COMPANY_ID”/>        </composite-id>      <version name=”varsion” column=”VERSION” unsaved-value=”0”/>      <set name=”orders” lazy=”true” inverse=”true”>          <key>              <columncolumn=”NAME”/>              <columncolumn=”COMPANY_ID”/>          </key>      </set>  </class>  <class name=”test.Order” table=”ORDERS”>      <many-to-one name=”customer” class=”test.Customer”>              <columncolumn=”NAME”/>              <columncolumn=”COMPANY_ID”/>      </many-to-one>  </class>   <script type="text/javascript">render_code();</script>

     

    2、映射组成关系

    代码 <hibernate-mapping>      <class name=”Customer” table=”CUSTOMERS”>  <property />          <component name=”homeAddress” class=”Address”>              <parent name=”customer”/>              <property/>          </component>          <component name=”comAddress” class=”Address”>              <parent name=”customer”/>              <property/>          </component>      </class>  </hibernate-mapping>    Public class Customer implements Serializable{       Address homeAddress;       Address comAddress;   }   Public class Address implements Serializable{//是VO不是PO不能单独Save,也不能关联。       Customer customer;   }   <script type="text/javascript">render_code();</script>

     

    3、映射聚合关系

     

    代码 <set/idbag name=”images” table=”IMAGES” lazy=”true”>      <key column=”CUSTOMER_ID”/>      <composite-element class=”Image”>          <parent name=”customer”/>          <property/>  <property/>      </composite-element>  </set/idbag>    <map name=”images” table=”IMAGES” lazy=”true”>      <key column=”CUSTOMER_ID”/>      <index type=”string” column=”IMAGE_NAME”/>      <composite-element class=”Image”>          <parent name=”customer”/>          <property/>  <property/>      </composite-element>  </map >   <script type="text/javascript">render_code();</script>

     

    4、映射继承关系

     

    代码 DOClass{      id   }   ClassA extends DOClass{       A1   }     ClassC extends ClassA{       C1   }     ClassD extends ClassA{       D1   }     ClassG extends ClassD{       G1   }     ClassH extends ClassD{       H1   }     ClassB extends DOClass{       B1   }     ClassE extends ClassB{       E1,e2,e3,e4,e5,e6   }     ClassF extends ClassB{       F1,f2,f3,f4,f5,f6,f7   }     TABLE_A {ID(PK),A_TYPE(discriminator),A1,C1,D1,G1,H1}   TABLE_B {ID(PK),B1}   TABLE_E {B_ID(PK/FK),E1,E2,E3,E4,E5,E6}   TABLE_F {B_ID(PK/FK),F1,F2,F3,F4,F5,F6,F7}     ClassA.hbm.xml   <hibernate-mapping>      <class name=”ClassA” table=”TABLE_A” discriminator-value=”A”>          <id/>          <discriminator column=”A_TYPE” type=”string”/>          <property name=”a1” column=”A1”/>          <sub-class name=”ClassC” discriminator-value=”C”>              <property name=”c1” column=”C1”/>          </sub-class>  <subclass name=”ClassD” discriminator-value=”D”>              <property name=”d1” column=”D1”/>              <subclass name=”ClassG” discriminator-value=”G”>                  <property name=”g1” column=”G1”/>              </subclass>              <subclass name=”ClassH” discriminator-value=”H”>                  <property name=”h1” column=”H1”/>              </subclasss>  </subclass>  </class>  </hibernate-mapping>  ClassB.hbm.xml   <hibernate-mapping>      <class name=”ClassB” table=”TABLE_B”>          <id/>          <property name=”b1” column=”B1”/>          <joined-subclass name=”ClassE” table=”TABLE_E”>              <key column=”B_ID”/>              <property name=”e1” column=”E1”/>              <property name=”e2” column=”E2”/>              <property name=”e3” column=”E3”/>              <property name=”e4” column=”E4”/>              <property name=”e5” column=”E5”/>              <property name=”e6” column=”E6”/>          </joined-subclass>          <joined-subclass name=”ClassF” table=”TABLE_F”>              <key column=”B_ID”/>              <property name=”f1” column=”F1”/>              <property name=”f2” column=”F2”/>              <property name=”f3” column=”F3”/>              <property name=”f4” column=”F4”/>              <property name=”f5” column=”F5”/>              <property name=”f6” column=”F6”/>              <property name=”f7” column=”F7”/>          </joined-subclass>      </class>  </hibernate-mapping>   <script type="text/javascript">render_code();</script>

     

    5、映射Bag,List和Map

    IDBag

    代码 IMAGES{ID(PK),CUSTOMER_ID(FK),FILENAME}   List images = new ArrayList();   Customer.hbm.xml     <idbag name=”images” table=”IMAGES” lazy=”true”>      <collection-id type=”long” column=”ID”>          <generator class=”increment”/>      </collection-id>      <key column=”CUSTOMER_ID”/>      <element column=”FILENAME” type=”string” not-null=”true”/>  </idbag>   <script type="text/javascript">render_code();</script>

     

    List

    代码 IMAGES{CUSTOMER_ID(PK/FK),POSITION(PK),FILENAME}   List images = new ArrayList();   Customer.hbm.xml   <list name=”images” table=”IMAGES” lazy=”true”>      <index column=”POSITION”/>      <key column=”CUSTOMER_ID”/>      <element column=”FILENAME” type=”string” not-null=”true”/>  </list>   <script type="text/javascript">render_code();</script>

     

    Map

     

    代码 IMAGES{CUSTOMER_ID(PK/FK),IMAGE_NAME(PK),FILENAME}   Map images = new HashMap();   <map name=”images” table=”IMAGES” lazy=”true”>      <key column=”CUSTOMER_ID”/>  <index column=”IMAGE_NAME” type=”string”/>      <element column=”FILENAME” type=”string” not-null=”true”/>  </map>    Set idbag map 支持数据库排序  order by =”ID”   Set map 支持内存排序  sort = “MyComparator”   <script type="text/javascript">render_code();</script>

     

    6、映射一对一关联关系特殊情况一

     

    代码 Public class Customer{       Address homeAddress;       Address comAddress;   }     Customer.hbm.xml   <many-to-one name=”homeAddress” class=”Address” column=”HOME_ADDRESS_ID” cascade=”all” unique=”true”/>   <many-to-one name=”comAddress” class=”Address” column=”COM_ADDRESS_ID” cascade=”all” unique=”true”/>     Address.hbm.xml   <one-to-one name=”address” class=”Customer” property-ref=”homeAddress”/>   <script type="text/javascript">render_code();</script>

     

    映射一对一关联关系主键映射

     

    代码 Customer.hbm.xml   <one-to-one name=”address” class=”Address” cascade=”all”/>  Address.hbm.xml   <class name=”address”>      <id>          <generator class=”foreign”>              <param name=”property”>customer</param>          </generator>      </id>  <one-to-one name=”customer” class=”Customer” constrained=”true”/>  </class>   <script type="text/javascript">render_code();</script>

     

    7、映射一对多关联

     

    代码 <class name="Person">  <id name="id" column="personId">          <generator class="native"/>  </id>  <many-to-one name="address" column="addressId" not-null="true"/>  </class>    <class name="Address">  <id name="id" column="addressId">  <generator class="native"/>  </id>  <set name="people" inverse="true">        <key column="addressId"/>  <one-to-many class="Person"/>  </set>  </class>   <script type="text/javascript">render_code();</script>

     

    8、映射多对多关联

     

    代码 <set name=”items” table=”CATEGORY_ITEM” lazy=”true” cascade=”save-update”>      <key column=”CATEGORY_ID”>      <many-to-many class=”Item” column=”ITEM_ID”/>  </set>   <script type="text/javascript">render_code();</script>

     

    三、Inverse与cascade Inverse 应该将Set的inverse属性设置为true,如果为many-to-many 需要将一方设置为true 如Customer:Order为1:N双向关联,将Customer的Set的inverse设置为true,表示Customer与Order之间的关联关系由Order端来维护,如customer.getOrders().addOrder(o)不会更新Customer与Order之间的关联关系,而order.setCustomer(o)才会更新Customer与Order之间的关联关系。

    Cascade Save-update 保存、更新Customer会同步更新Order. Delete 同步删除 All 包含save-update和delete操作,另外调用当前对象的evice或者lock时,对关联对象也调用相应方法。 Delete-orphan 删除所有和当前对象解除关联关系的对象。 All-delete-orphan 当关联双方为父子关系是(父亲控制孩子的持久化生命周期),如果父方删除,子方自动删除(同delete),如果子方无父亲,子方应删除。包含Delete和all-orphan的行为。

    四、Hibernate缓存

    Session 缓存(一级缓存),每一session确保自己的缓存的所有的持久对象唯一 通过调用session.setFlushMode()可设定缓存的清理模式,缓存的清理模式有三种: FlushMode.AUTO:query、commit和flush的时候清理缓存。 FlushMode.COMMIT:commit和flush的时候清理缓存。 FlushMode.NEVER:只有在调用session.flush()的时候才清理缓存。 Session 只有在清理缓存的时候才会执行相应的sql操作。 可以使用session.evict()和session.clear()清空缓存。 Save、update、query都加入Session缓存 Select c.ID,c.Name,c.age,o.ORDER_NUM,o.CUSTOMER_ID from Customer c,inner join c.orders c 除外。

    SessionFactory缓存(二级缓存)

    代码 <class name=”Category” table=”CATEGORYS”>      <cache usage=”read-write”/>      <id/>      <set name=”items” inverse=”true” lazy=”true”>          <cache usage=”read-write”/>          <key/>      </set>  </class>  <class name=”Item”>      <cache usage=”read-write”/>      <id/>  </class>    Hibernate.cache.provider=…………EhCacheProvider   Hibernate.cache.user_query_cache=true    Ehcache.xml   <ehcache>      <diskStore path=”c://temp”/>      <defaultCache          maxElementsInMemory=”10000”           eternal=”false”           timeToIdleSeconds=”120”           timeToLiveSeconds=”120”           overflowToDisk=”true”/>      <cache name=”Category”           maxElementsInMemory=”10000”           eternal=”false”           timeToIdleSeconds=”120”           timeToLiveSeconds=”120”           overflowToDisk=”true”/>        <cache name=”Category.Items”           maxElementsInMemory=”10000”           eternal=”false”           timeToIdleSeconds=”120”           timeToLiveSeconds=”120”           overflowToDisk=”true”/>        <cache name=”Item”           maxElementsInMemory=”10000”           eternal=”false”           timeToIdleSeconds=”120”           timeToLiveSeconds=”120”           overflowToDisk=”true”/>        <cache name=”customerQueries”…./> <!—设置查询缓存     </ehcache>   <script type="text/javascript">render_code();</script>

     

    Query q = session.createQuery(); q.setCacheable(true); q.setCacheRegion(“customerQueries”);

    SessionFactory.evict(),SessionFactory.evictCollection()清除二级缓存。

    直接调用JDBC API不会使用任何缓存。 二级缓存适合查询较多但是很少更新的情况。

    尽量对数据库的所有操作由Hibernate来完成,而不要用其它方式对数据库进行操作,否则可能与缓存冲突,当然如果对缓存有深入研究的除外。

    五、临时对象(Transient Object)、持久对象(Persistent Object)和游离对象(Detached Object) 临时对象:表示对象的主键不存在(OID不存在),Hibernate通过key的unsave-value或者version的unsaved-value来判断是否为临时对象。Session对临时对象的唯一操作应该是save()。 持久对象:在session缓存中存在持久对象,数据库中存在相应纪录。 游离对象:数据库中有相应纪录,session中不存在持久对象,可通过session.evict()获得。 Session缓存中存在,数据库中不存在,这是什么类型的对象?实际这种情况不存在,因为所有的Session操作均在事务中进行,缓存中的数据是通过save、update或者query生成,而save或者update得到的是数据库的独占锁,因此其它事务没有可能删除数据库中的数据。而query获得的是数据库的共享锁,因此其它事务也不可能获得独占锁来更新数据。因此在一个事务内部session缓存才有意义,如果脱离事务,仅仅是只读操作也可能导致session缓存中存在数据库中根本不存在相应纪录的持久性对象。

    六、Hibernate 的检索策略

    设定批量检索数量 batch-size 外连接深度控制hibernate.max_fetch_depth 类级别检索 load、get和find。其中load可以设置延迟检索(cglib生成代理类,可通过Hibernate.initialize()初始化),这也是load和get的区别之一。Get/find立即检索,与是否设置延迟无关。 关联检索 立即检索,延迟检索,迫切左外连接检索。Set/list/map等,无论是否延迟检索得到的都是代理集合类。而非HashSet,ArrayList等。

    Lazy与outer-joint False,false 立即检索 False,true 迫切左外连接, True,false 延迟检索

    Many-to-one 的outer-join属性 Auto:Customer的lazy为true则延迟加载,否则迫切左外连接 True:迫切左外连接 False:延迟加载或者立即加载由Customer的lazy决定。 One-to-one的延迟加载策略 <one-to-one name=”customer” class=”Customer” constrained=”true”/> HQL会忽略迫切左外连接检索和lazy(只有load才为代理对象)策略。 Session.find(“from Customer c as c left join fetch c.orders where c.id=1”)

    Hibernate的检索方式 HQL、NativeSql和QBC From Customer c inner join c.orders o 查询结果保存到session缓存 Select c.ID,c.Name,c.age,o.ORDER_NUM,o.CUSTOMER_ID from Customer c,inner join c.orders c查询结果不存入Session缓存。

    七、Hibernate并发控制 乐观锁:VERSION或者timestamp控制,session.lock()立刻进行版本检查,session.update(),update的时候执行版本检查。 悲观锁:select for upload,session.get(Customer.class,new Long(1),LockMode.UPGRADE)

    总结:本文绝大多数为摘录内容,有些地方加上自己的理解,有不对之处恳请批评指正。看了书,阅读了相关帖子后,感觉学习Hibernate的重点应该是Hibernate的缓存策、查询和如何提高性能方面。

    另外说点自己的感受,本人做项目到现在都是在设计阶段先有关系模型后有对象模型(其实一个Table一个对象),在这种情况下Hibernate的优势大大降低了,其实是为了Hibernate而Hibernate了,个人感觉在先有关系模型的情况下用Hibernate的意义不大。

    如果按照OOAD的开发流程先有对象模型,然后根据对象模型生成关系模型,那应该说用Hibernate用对了地方。毕竟Hibernate对继承、多态,各种复杂的关系都有很好的支持。

     

    最新回复(0)