精通Hibernate:對象關(guān)系映射基礎(chǔ)
1、持久化類的屬性和訪問方法
(1)持久化類簡介
在Hibernate中持久化類的訪問方法有兩個調(diào)用者,一個是Java應(yīng)用程序,一個是Hibernate。值得注意的是,Java應(yīng)用程序不能訪問持久化類的private類型的getXXX()、setXXX(),而Hibernate沒有這樣的限制。
(2)基本類型屬性和包裝類型屬性
Java有8種基本類型:byte,short,char,int,long,float,double,boolean;與之對應(yīng)的Java提供了8種包裝類型:Byte,Short,Character,Integer,Long,F(xiàn)loat,Double,Boolean?;绢愋团c包裝類型之間可以如下簡單轉(zhuǎn)換:
- double prD=1;
- //把double基本類型轉(zhuǎn)換成Double包裝類型
- Double wrD=new Double(prD);
- //把Double包裝類型轉(zhuǎn)換成double基本類型
- prD=wrD.doubleValue();
Hibernate兩種類型都是支持的。
(3)在持久化類的訪問方法中加入程序邏輯
(a)在Customer類的getName()和setName()方法中加入程序邏輯
假如在Customer類中有firstname屬性和lastname屬性,但是沒有name屬性,而數(shù)據(jù)庫CUSTOMERS表中只有NAME字段。當(dāng)Hibernate從數(shù)據(jù)庫中取得了CUSTOMERS表的NAME字段值后,會調(diào)用setName()方法,此時應(yīng)該讓Hibernate通過setName()方法來自動設(shè)置firstname屬性和lastname。故要在setName()方法中加入額外的程序邏輯。
- public String getName(){
- return firstname+ " "+lastname;
- }
- public void setName(String name){
- StringTokenizer t=new StringTokenizer(name);
- firstname=t.nextToken();
- lastname=t.nextToken();
- }
在映射文件中此時直接映射name即可,無需映射firstname等。
- <property name="name" column="NAME">
盡管在Customer類中沒有定義name屬性,由于Hibernate并不會直接訪問name屬性,而是通過getName()和setName()方法。只要在Customer.hbm.xml文件中映射了name屬性,HQL語句就能訪問:
- Query query=seesion.createQuery("from Customer as c where c.name='Tom'");
但是如果把Customer.hbm.xml文件中name屬性配置為:
- <property name="name" column="NAME" access="field">
程序會直接去訪問Customer實例中的name屬性,就會出現(xiàn)異常。
(b)在Customer類的setOrders()方法中加入程序邏輯
假定Customer類中有一個avgPrice屬性,表示訂單的平均價格,取值為它所關(guān)聯(lián)Order對象的price的平均值。在CUSTOMERS表中沒有AVG_PRICE字段??梢匀缦虏僮鳎?/p>
- public Double getAvgPrice(){
- return this.avgPrice;
- }
- private void setAvgPrice( Double avgPrice ){
- this.avgPrice = avgPrice;
- }
- public Double getTotalPrice(){
- return this.totalPrice;
- }
- private void setTotalPrice( Double totalPrice ){
- this.totalPrice = totalPrice;
- }
- public void setOrders( Set orders ){
- this.orders = orders;
- calculatePrice();
- }
- public Set getOrders(){
- return orders;
- }//定義為一個Set
- private void calculatePrice(){
- double avgPrice = 0.0;
- double totalPrice = 0.0;
- int count=0;
- /迭代計算orders里面所有price
- if ( getOrders() != null ){
- Iterator iter = getOrders().iterator();
- while( iter.hasNext() ){
- double orderPrice = ((Order)iter.next()).getPrice();
- totalPrice += orderPrice;
- count++;
- }
- // Set the price for the order from the calcualted value
- avgPrice=totalPrice/count;
- setAvgPrice( new Double(avgPrice) );
- }
- }
在Customer.hbm.xml文件不用映射avgPrice,因為Hibernate不會直接訪問avgPrice屬性,也不會調(diào)用getavgPrice()和setavgPrice().
(c)在Customer類的setSex()方法中加入數(shù)據(jù)驗證邏輯
在持久化類的訪問方法中,還可以加入數(shù)據(jù)驗證邏輯。
- public char getSex(){
- return this.sex;
- }
- public void setSex(char sex){
- if(sex!='F' && sex!='M'){
- throw new IllegalArgumentException("Invalid Sex");
- }
- this.sex =sex ;
- }
(4)設(shè)置派生屬性
持久化類并非所有屬性都直接和表的字段匹配,持久化類的有些屬性是可以在運行的時候得出的,這些稱作派生屬性。正如之前的avgPrice屬性,該方案包括兩個步驟:
- 在映射文件中不映射avgPrice屬性
- 在Customer類的setOrders()方法中加入程序邏輯,自動為avgPrice屬性賦值。
除了這種方法來設(shè)置派生屬性,還可以如下解決:
利用<property>元素的formula屬性。formula屬性用來設(shè)置一個SQL表達式,Hibernate將根據(jù)它來計算派生屬性的值。以Customer類的totalPrice屬性為例:
- <property name="totalPrice" formula="(select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=ID)"/>
在Hibernate從數(shù)據(jù)庫中查詢Customer對象時,若查詢totalPrice,即:
- select totalPrice from CUSTOMERS;
使用formula屬性后,上面的查詢語句就會自動地被替代成:
- select (select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=1) from CUSTOMERS;
如果子句的查詢結(jié)果為空,那么上述的語句就會出現(xiàn)異常。解決方法是:將totalPrice的屬性定義為Double包裝類型。
(5)控制insert和update語句
Hibernate在初始化階段,就會根據(jù)映射文件的映射信息,為所有的持久化類定義以下的SQL語句。
以上SQL語句中的“?”代表JDBC PreparedStatement中的參數(shù)。這些SQL語句都存放在SessionFactory的內(nèi)置緩存中,當(dāng)執(zhí)行Session的save()、update()、delete() 、load()和get()方法的時候,將從緩存中找到對應(yīng)預(yù)定義的SQL語句,再把具體的參數(shù)值綁定到該SQL語句中。
#p#
2、創(chuàng)建命名策略
還有一直一種方法是實現(xiàn)Hibernate的org.hibernate.cfg.NamingStrategy接口,對于這個接口Hibernate提供了兩種參考實現(xiàn)類:org.hibernate.cfg.defaultNamingStrategy和org.hibernate.cfg.ImprovedNamingStrategy類。
MyNamingStrategy.java
- package mypack;
- import org.hibernate.cfg.ImprovedNamingStrategy;
- import org.hibernate.util.StringHelper;
- public class MyNamingStrategy extends ImprovedNamingStrategy {
- public String classToTableName(String className) {
- return StringHelper.unqualify(className).toUpperCase()+'S';//classname轉(zhuǎn)化成大寫字母+S就是對應(yīng)的表名
- }
- public String propertyToColumnName(String propertyName) {
- return propertyName.toUpperCase();
- }
- public String tableName(String tableName) {
- return tableName;
- }
- public String columnName(String columnName) {
- return columnName;
- }
- public String propertyToTableName(String className, String propertyName) {
- return classToTableName(className) + '_' +
- propertyToColumnName(propertyName);
- }
- }
使用命名策略后可以更好的將數(shù)據(jù)庫中表名、列名對象化成類中的對象。
#p#
3、實例
本節(jié)的代碼下載地址:http://down.51cto.com/data/326754
主要的BusinessService.java
- package mypack;
- import org.hibernate.*;
- import org.hibernate.cfg.Configuration;
- import java.util.*;
- public class BusinessService{
- public static SessionFactory sessionFactory;
- static{
- try{
- Configuration config = new Configuration()
- .setNamingStrategy( new MyNamingStrategy() )
- .configure(); //加載hibernate.cfg.xml文件中配置的信息
- sessionFactory = config.buildSessionFactory();
- }catch(RuntimeException e){e.printStackTrace();throw e;}
- }
- public Customer loadCustomer(long customer_id){
- Session session = sessionFactory.openSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- Customer customer=(Customer)session.get(Customer.class,new Long(customer_id));
- tx.commit();
- return customer;
- }catch (RuntimeException e) {
- if (tx != null) {
- tx.rollback();
- }
- throw e;
- } finally {
- session.close();
- }
- }
- public void saveCustomer(Customer customer){
- Session session = sessionFactory.openSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- session.save(customer);
- tx.commit();
- }catch (RuntimeException e) {
- if (tx != null) {
- tx.rollback();
- }
- throw e;
- } finally {
- session.close();
- }
- }
- public void loadAndUpdateCustomer(long customerId) {
- Session session = sessionFactory.openSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- Customer customer=(Customer)session.get(Customer.class,new Long(customerId));
- customer.setDescription("A lovely customer!");
- tx.commit();
- }catch (RuntimeException e) {
- if (tx != null) {
- tx.rollback();
- }
- throw e;
- } finally {
- session.close();
- }
- }
- public void updateCustomer(Customer customer){
- Session session = sessionFactory.openSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- session.update(customer);
- tx.commit();
- }catch (RuntimeException e) {
- if (tx != null) {
- tx.rollback();
- }
- throw e;
- } finally {
- session.close();
- }
- }
- public void saveDictionary(Dictionary dictionary) {
- Session session = sessionFactory.openSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- session.save(dictionary);
- tx.commit();
- }catch (RuntimeException e) {
- if (tx != null) {
- tx.rollback();
- }
- throw e;
- } finally {
- session.close();
- }
- }
- public void updateDictionary(Dictionary dictionary){
- Session session = sessionFactory.openSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- session.update(dictionary);
- tx.commit();
- }catch (RuntimeException e) {
- if (tx != null) {
- tx.rollback();
- }
- throw e;
- } finally {
- session.close();
- }
- }
- public Dictionary loadDictionary(long dictionary_id) {
- Session session = sessionFactory.openSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- Dictionary dictionary=(Dictionary)session.get(Dictionary.class,new Long(dictionary_id));
- tx.commit();
- return dictionary;
- }catch (RuntimeException e) {
- if (tx != null) {
- tx.rollback();
- }
- throw e;
- } finally {
- session.close();
- }
- }
- public void printCustomer(Customer customer){
- System.out.println("name:"+customer.getName());
- System.out.println("sex:"+customer.getSex());
- System.out.println("description:"+customer.getDescription());
- System.out.println("avgPrice:"+customer.getAvgPrice());
- System.out.println("totalPrice:"+customer.getTotalPrice());
- }
- public void printDictionary(Dictionary dictionary){
- System.out.println("type:"+dictionary.getType());
- System.out.println("key:"+dictionary.getKey());
- System.out.println("value:"+dictionary.getValue());
- }
- public void test(){
- Customer customer=new Customer("Laosan","Zhang",'M',new HashSet(),"A good citizen!");
- Order order1=new Order("Order001",new Double(100),customer);
- Order order2=new Order("Order002",new Double(200),customer);
- customer.getOrders().add(order1);
- customer.getOrders().add(order2);
- saveCustomer(customer);
- customer=new Customer("Laowu","Wang",'M',new HashSet(),null);
- saveCustomer(customer);
- customer=loadCustomer(1);
- printCustomer(customer);
- customer.setDescription("An honest customer!");
- updateCustomer(customer);
- loadAndUpdateCustomer(1);
- Dictionary dictionary=new Dictionary("SEX","M","MALE");
- saveDictionary(dictionary);
- dictionary=loadDictionary(1);
- dictionary.setValue("MAN");
- updateDictionary(dictionary);
- dictionary=loadDictionary(1);
- printDictionary(dictionary);
- }
- public static void main(String args[]) {
- new BusinessService().test();
- sessionFactory.close();
- }
- }
原文鏈接:http://blog.csdn.net/yu422560654/article/details/7047661
【編輯推薦】