精通Hibernate:對(duì)象關(guān)系映射基礎(chǔ)
1、持久化類的屬性和訪問方法
(1)持久化類簡介
在Hibernate中持久化類的訪問方法有兩個(gè)調(diào)用者,一個(gè)是Java應(yīng)用程序,一個(gè)是Hibernate。值得注意的是,Java應(yīng)用程序不能訪問持久化類的private類型的getXXX()、setXXX(),而Hibernate沒有這樣的限制。
(2)基本類型屬性和包裝類型屬性
Java有8種基本類型:byte,short,char,int,long,float,double,boolean;與之對(duì)應(yīng)的Java提供了8種包裝類型:Byte,Short,Character,Integer,Long,F(xiàn)loat,Double,Boolean。基本類型與包裝類型之間可以如下簡單轉(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字段值后,會(huì)調(diào)用setName()方法,此時(shí)應(yīng)該讓Hibernate通過setName()方法來自動(dòng)設(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();
- }
在映射文件中此時(shí)直接映射name即可,無需映射firstname等。
- <property name="name" column="NAME">
盡管在Customer類中沒有定義name屬性,由于Hibernate并不會(huì)直接訪問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">
程序會(huì)直接去訪問Customer實(shí)例中的name屬性,就會(huì)出現(xiàn)異常。
(b)在Customer類的setOrders()方法中加入程序邏輯
假定Customer類中有一個(gè)avgPrice屬性,表示訂單的平均價(jià)格,取值為它所關(guān)聯(lián)Order對(duì)象的price的平均值。在CUSTOMERS表中沒有AVG_PRICE字段。可以如下操作:
- 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;
- }//定義為一個(gè)Set
- private void calculatePrice(){
- double avgPrice = 0.0;
- double totalPrice = 0.0;
- int count=0;
- /迭代計(jì)算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,因?yàn)镠ibernate不會(huì)直接訪問avgPrice屬性,也不會(huì)調(diào)用getavgPrice()和setavgPrice().
(c)在Customer類的setSex()方法中加入數(shù)據(jù)驗(yàn)證邏輯
在持久化類的訪問方法中,還可以加入數(shù)據(jù)驗(yàn)證邏輯。
- 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è)置派生屬性
持久化類并非所有屬性都直接和表的字段匹配,持久化類的有些屬性是可以在運(yùn)行的時(shí)候得出的,這些稱作派生屬性。正如之前的avgPrice屬性,該方案包括兩個(gè)步驟:
- 在映射文件中不映射avgPrice屬性
- 在Customer類的setOrders()方法中加入程序邏輯,自動(dòng)為avgPrice屬性賦值。
除了這種方法來設(shè)置派生屬性,還可以如下解決:
利用<property>元素的formula屬性。formula屬性用來設(shè)置一個(gè)SQL表達(dá)式,Hibernate將根據(jù)它來計(jì)算派生屬性的值。以Customer類的totalPrice屬性為例:
- <property name="totalPrice" formula="(select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=ID)"/>
在Hibernate從數(shù)據(jù)庫中查詢Customer對(duì)象時(shí),若查詢totalPrice,即:
- select totalPrice from CUSTOMERS;
使用formula屬性后,上面的查詢語句就會(huì)自動(dòng)地被替代成:
- select (select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=1) from CUSTOMERS;
如果子句的查詢結(jié)果為空,那么上述的語句就會(huì)出現(xiàn)異常。解決方法是:將totalPrice的屬性定義為Double包裝類型。
(5)控制insert和update語句
Hibernate在初始化階段,就會(huì)根據(jù)映射文件的映射信息,為所有的持久化類定義以下的SQL語句。
以上SQL語句中的“?”代表JDBC PreparedStatement中的參數(shù)。這些SQL語句都存放在SessionFactory的內(nèi)置緩存中,當(dāng)執(zhí)行Session的save()、update()、delete() 、load()和get()方法的時(shí)候,將從緩存中找到對(duì)應(yīng)預(yù)定義的SQL語句,再把具體的參數(shù)值綁定到該SQL語句中。
#p#
2、創(chuàng)建命名策略
還有一直一種方法是實(shí)現(xiàn)Hibernate的org.hibernate.cfg.NamingStrategy接口,對(duì)于這個(gè)接口Hibernate提供了兩種參考實(shí)現(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就是對(duì)應(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ù)庫中表名、列名對(duì)象化成類中的對(duì)象。
#p#
3、實(shí)例
本節(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
【編輯推薦】