<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    學海拾遺

    生活、技術、思想無處不在學習
    posts - 52, comments - 23, trackbacks - 0, articles - 3
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    關于Spring和Hibernate整合后的懶加載和DAO模式應用,尤其介紹了其中的Hibernate懶加載在應用Spring的情況下在各個層次實現的情況。暫時是英文的,有時間試著翻譯一下!~

    Hibernate and Lazy Initialization

    Hibernate object relational mapping offers both lazy and non-lazy modes of object initialization. Non-lazy initialization retrieves an object and all of its related objects at load time. This can result in hundreds if not thousands of select statements when retrieving one entity. The problem is compounded when bi-directional relationships are used, often causing entire databases to be loaded during the initial request. Of course one could tediously examine each object relationship and manually remove those most costly, but in the end, we may be losing the ease of use benefit sought in using the ORM tool.

    The obvious solution is to employ the lazy loading mechanism provided by hibernate. This initialization strategy only loads an object's one-to-many and many-to-many relationships when these fields are accessed. The scenario is practically transparent to the developer and a minimum amount of database requests are made, resulting in major performance gains. One drawback to this technique is that lazy loading requires the Hibernate session to remain open while the data object is in use. This causes a major problem when trying to abstract the persistence layer via the Data Access Object pattern. In order to fully abstract the persistence mechanism, all database logic, including opening and closing sessions, must not be performed in the application layer. Most often, this logic is concealed behind the DAO implementation classes which implement interface stubs. The quick and dirty solution is to forget the DAO pattern and include database connection logic in the application layer. This works for small applications but in large systems this can prove to be a major design flaw, hindering application extensibility.

    Being Lazy in the Web Layer

    Fortunately for us, the Spring Framework has developed an out of box web solution for using the DAO pattern in combination with Hibernate lazy loading. For anyone not familiar with using the Spring Framework in combination with Hibernate, I will not go into the details here, but I encourage you to read Hibernate Data Access with the Spring Framework. In the case of a web application, Spring comes with both the OpenSessionInViewFilter and the OpenSessionInViewInterceptor. One can use either one interchangeably as both serve the same function. The only difference between the two is the interceptor runs within the Spring container and is configured within the web application context while the Filter runs in front of Spring and is configured within the web.xml. Regardless of which one is used, they both open the hibernate session during the request binding this session to the current thread. Once bound to the thread, the open hibernate session can transparently be used within the DAO implementation classes. The session will remain open for the view allowing lazy access to the database value objects. Once the view logic is complete, the hibernate session is closed either in the Filter doFilter method or the Interceptor postHandle method. Below is an example of the configuration of each component:

    Interceptor Configuration

     1 <beans>
     2   <bean id="urlMapping"     
     3      class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">    
     4        <property name="interceptors">
     5          <list>
     6               <ref bean="openSessionInViewInterceptor"/>
     7          </list>
     8        </property>
     9        <property name="mappings">
    10   
    11   </bean>
    12   
    13   <bean name="openSessionInViewInterceptor"  
    14     class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor">
    15        <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    16   </bean>
    17 </beans>

    Filter Configuration

     1 <web-app>                           
     2   <filter>
     3     <filter-name>hibernateFilter</filter-name>
     4     <filter-class>
     5       org.springframework.orm.hibernate.support.OpenSessionInViewFilter
     6     </filter-class>
     7    </filter>
     8         
     9   <filter-mapping>
    10     <filter-name>hibernateFilter</filter-name>
    11      <url-pattern>*.spring</url-pattern>
    12   </filter-mapping>
    13   
    14 </web-app>            

    Implementing the Hibernate DAO's to use the open session is simple. In fact, if you are already using the Spring Framework to implement your Hibernate DAO's, most likely you will not have to change a thing. The DAO's must access Hibernate through the convenient HibernateTemplate utility, which makes database access a piece of cake. Below is an example DAO.

    Example DAO

     1  public class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO {
     2                                 
     3        public Product getProduct(Integer productId) {
     4               return (Product)getHibernateTemplate().load(Product.class, productId);
     5        }
     6 
     7        public Integer saveProduct(Product product) {
     8               return (Integer) getHibernateTemplate().save(product);
     9        }       
    10 
    11        public void updateProduct(Product product) {
    12               getHibernateTemplate().update(product);
    13        }
    14  }               

    Being Lazy in the Business Layer

    Even outside the view, the Spring Framework makes it easy to use lazy load initialization, through the AOP interceptor HibernateInterceptor. The hibernate interceptor transparently intercepts calls to any business object configured in the Spring application context, opening a hibernate session before the call, and closing the session afterward. Let's run through a quick example. Suppose we have an interface BusinessObject:

    1 public interface BusinessObject {
    2 
    3     public void doSomethingThatInvolvesDaos(); 
    4 }             

    The class BusinessObjectImpl implements BusinessObject:

    1 public class BusinessObjectImpl implements BusinessObject {
    2 
    3     public void doSomethingThatInvolvesDaos() {
    4         // lots of logic that calls
    5         // DAO classes Which access 
    6         // data objects lazily
    7     }
    8 }              

    Through some configurations in the Spring application context, we can instruct the HibernateInterceptor to intercept calls to the BusinessObjectImpl allowing it's methods to lazily access data objects. Take a look at the fragment below:

     1 <beans>
     2     <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
     3          <property name="sessionFactory">
     4            <ref bean="sessionFactory"/>
     5          </property>
     6     </bean>
     7     <bean id="businessObjectTarget" class="com.acompany.BusinessObjectImpl">
     8        <property name="someDAO"><ref bean="someDAO"/></property>
     9     </bean>
    10     <bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
    11          <property name="target"><ref bean="businessObjectTarget"/></property>
    12          <property name="proxyInterfaces">
    13            <value>com.acompany.BusinessObject</value>
    14          </property>
    15          <property name="interceptorNames">
    16            <list>
    17               <value>hibernateInterceptor</value>
    18            </list>
    19          </property>
    20      </bean>            
    21 </beans>               

    When the businessObject bean is referenced, the HibernateInterceptor opens a hibernate session and passes the call onto the BusinessObjectImpl. When the BusinessObjectImpl has finished executing, the HibernateInterceptor transparently closes the session. The application code has no knowledge of any persistence logic, yet it is still able to lazily access data objects.

    Being Lazy in your Unit Tests

    Last but not least, we'll need the ability to test our lazy application from J-Unit. This is easily done by overriding the setUp and tearDown methods of the TestCase class. I prefer to keep this code in a convenient abstract TestCase class for all of my tests to extend.

     1 public abstract class MyLazyTestCase extends TestCase {
     2 
     3         public void setUp() throws Exception {
     4                 super.setUp();
     5                 SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory");
     6                 Session s = sessionFactory.openSession();
     7                 TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));
     8 
     9         }
    10 
    11         protected Object getBean(String beanName) {
    12             //Code to get objects from Spring application context
    13         }
    14 
    15         public void tearDown() throws Exception {
    16                 super.tearDown();
    17                 SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.
    18                                getResource(sessionFactory);
    19                Session s = holder.getSession(); 
    20                s.flush();
    21                TransactionSynchronizationManager.unbindResource(sessionFactory);
    22                SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory);
    23        }
    24}
    Traceback: http://jroller.com/kbaum/entry/orm_lazy_initialization_with_dao

    在這里我試著翻譯一下,有部分地方改變了一下,希望看到的朋友多多指正。

    Hibernate和延遲裝載

    Hibernate ORM(關系-對象映射)針對對象的初始化分別提供了延遲和非延遲模式。非延遲裝載將在讀取時獲得對象和其所關聯的所有對象,這樣當獲取一個實體對象時,將會導致成千上萬的select語句產生。這個問題在使用雙向關聯的時候將更加混亂,經常會導致在初始化請求就需要讀取整個數據庫。當然,某個人可以去繁重地檢查每一個對象之間的關系,并且花費更多的代價去手動地移除它們。但是最終,我們可能已經失去了使用ORM工具換來的易用性。

    因此,顯而易見的解決方案是使用Hibernate提供的延遲加載機制。這種初始化策略僅在當那些字段訪問時讀取這個對象的一對多和多對多關系。這種情況對于開發者實際上是透明的,并且只創建一小部分數量的數據庫請求,這樣就可以很大地提升性能。這種技術的一個缺點就是當這個數據對象在使用時,延遲加載就需要Hibernate session一直打開。這就導致了一個主要問題:當嘗試通過DAO(數據訪問對象)模式來抽象化持久層時,為了完整地抽象持久化機制,所有的數據庫邏輯,包括打開和關閉session,都將不會被應用層調用執行。最經常的情況,這些邏輯被后面的實現某些DAO接口的類來關注。但是,這個快速但不好的解決方案違反了DAO模式,并且在應用層包含了數據庫連接邏輯。這樣做對于小型應用可能適合,但是在大型系統中,這會產生一個重大的設計失誤,阻止了應用的擴展。

    在WEB層上延遲

    我們是幸運的,Spring框架開發了一個開箱即用(out of box)的WEB解決方案,用來在組合Hibernate延遲加載時使用DAO模式。對于不熟悉使用Spring如何組合Hibernate的人,在這里我不會進入詳細的細節,但是我鼓勵你去閱讀使用Spring框架進行Hibernate數據訪問Hibernate Data Access with the Spring Framework》。就一個WEB應用來說,Spring提供了OpenSessionInViewFilterOpenSessionInViewInterceptor,一個可替換另一個使用而得到同樣的功能。兩者的唯一區別就是攔截器(Interceptor)在Spring容器中運行并且在WEB應用程序上下文(Application Context)中被配置,而過濾器(Filter)運行Spring之前并且是在web.xml中配置的。不管使用哪一個,它們都在綁定了session到當前線程的請求中打開Hibernate Session。一旦綁定到了線程,打開的Hibernate Session就能夠透明地在DAO實現類中使用了。這個Session將一直打開,為視圖(view)提供對數據庫值對象的延遲訪問。視圖邏輯如果完成了,Hibernate Session就會在過濾器的doFilter或攔截器的postHandle方法中關閉。下面是各個部件配置的一個例子:

    攔截器配置

     1 <beans>
     2   <bean id="urlMapping"     
     3      class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">    
     4        <property name="interceptors">
     5          <list>
     6               <ref bean="openSessionInViewInterceptor"/>
     7          </list>
     8        </property>
     9        <property name="mappings">
    10   
    11   </bean>
    12   
    13   <bean name="openSessionInViewInterceptor"  
    14     class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor">
    15        <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    16   </bean>
    17 </beans>

    過濾器配置

     1 <web-app>                           
     2   <filter>
     3     <filter-name>hibernateFilter</filter-name>
     4     <filter-class>
     5       org.springframework.orm.hibernate.support.OpenSessionInViewFilter
     6     </filter-class>
     7    </filter>
     8         
     9   <filter-mapping>
    10     <filter-name>hibernateFilter</filter-name>
    11      <url-pattern>*.spring</url-pattern>
    12   </filter-mapping>
    13   
    14 </web-app>            

    實現Hibernate DAO來使用打開的Session很簡單。實際上,如果你準備用Spring框架來實現你的Hibernate DAO,最可能的是你不需要改變任何一處代碼。強制DAO必須通過方便的HibernateTemplate工具來訪問Hibernate,將會使得數據庫訪問是小菜一碟。下面是一個DAO的例子。

    DAO例子

     1  public class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO {
     2                                 
     3        public Product getProduct(Integer productId) {
     4               return (Product)getHibernateTemplate().load(Product.class, productId);
     5        }
     6 
     7        public Integer saveProduct(Product product) {
     8               return (Integer) getHibernateTemplate().save(product);
     9        }       
    10 
    11        public void updateProduct(Product product) {
    12               getHibernateTemplate().update(product);
    13        }
    14  }               

    在業務層延遲

    即使是在視圖外面,Spring框架通過AOP攔截器HibernateInterceptor,也讓延遲加載初始化變得很容易使用。這個Hibernate攔截器透明地攔截在Spring應用程序上下文(Application Context)中配置的任何業務對象的調用,在調用前打開一個Hibernate Session,同時在調用后關閉Session。讓我們通過一個快速的例子來運行一下。假設我們有一個BusinessObject接口:

    1 public interface BusinessObject {
    2 
    3     public void doSomethingThatInvolvesDaos(); 
    4 }             

    BusinessObjectImpl類實現了BusinessObject接口:

    1 public class BusinessObjectImpl implements BusinessObject {
    2 
    3     public void doSomethingThatInvolvesDaos() {
    4         // lots of logic that calls
    5         // DAO classes Which access 
    6         // data objects lazily
    7     }
    8 }              

    通過在Spring應用程序上下文(Application Context)中的一些配置,我們能構造HibernateInterceptor來攔截BusinessObjectImpl的調用,以允許它的方法延遲訪問數據對象。看一看下面的代碼片斷:

     1 <beans>
     2     <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
     3          <property name="sessionFactory">
     4            <ref bean="sessionFactory"/>
     5          </property>
     6     </bean>
     7     <bean id="businessObjectTarget" class="com.acompany.BusinessObjectImpl">
     8        <property name="someDAO"><ref bean="someDAO"/></property>
     9     </bean>
    10     <bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
    11          <property name="target"><ref bean="businessObjectTarget"/></property>
    12          <property name="proxyInterfaces">
    13            <value>com.acompany.BusinessObject</value>
    14          </property>
    15          <property name="interceptorNames">
    16            <list>
    17               <value>hibernateInterceptor</value>
    18            </list>
    19          </property>
    20      </bean>            
    21 </beans>               

    當businessObject bean被引用時,HibernateInterceptor打開一個Hibernate Session并且將調用傳遞給BusinessObjectImpl。當BusinessObjectImpl完成執行時,HibernateInterceptor透明地關閉這個Session。應用程序代碼沒有任何的持久化邏輯,然而它也能夠延遲地訪問數據對象。

    在你的單元測試中延遲

    最后一項重點是,我們需要能夠從Junit中測試我們的延遲應用的能力。這很容易通過覆蓋用例測試(TestCase)類中的setUp和tearDown方法做到。我更趨向于將這些代碼放于一個方便的能被我所有的測試繼承的抽象測試用例(TestCase)類中。

     

     1 public abstract class MyLazyTestCase extends TestCase {
     2 
     3         public void setUp() throws Exception {
     4                 super.setUp();
     5                 SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory");
     6                 Session s = sessionFactory.openSession();
     7                 TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));
     8 
     9         }
    10 
    11         protected Object getBean(String beanName) {
    12             //Code to get objects from Spring application context
    13         }
    14 
    15         public void tearDown() throws Exception {
    16                 super.tearDown();
    17                 SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.
    18                                getResource(sessionFactory);
    19                Session s = holder.getSession(); 
    20                s.flush();
    21                TransactionSynchronizationManager.unbindResource(sessionFactory);
    22                SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory);
    23        }
    24}

    主站蜘蛛池模板: 亚洲欧洲日产v特级毛片| 色窝窝亚洲av网| 免费网站看v片在线香蕉| 亚洲精品在线免费观看| 亚洲免费福利在线视频| 亚洲欧洲自拍拍偷精品 美利坚| 人妻无码久久一区二区三区免费| 国产亚洲精品成人AA片| 4338×亚洲全国最大色成网站| 91免费国产精品| 日本中文字幕免费看| 亚洲制服在线观看| 国产亚洲?V无码?V男人的天堂| 国产精品永久免费10000| 亚洲国产理论片在线播放| 国产又大又黑又粗免费视频| 久操视频在线免费观看| 午夜亚洲国产精品福利| 亚洲色大成网站www永久| 亚洲国产av一区二区三区| 国内精品乱码卡1卡2卡3免费| www在线观看播放免费视频日本| 亚洲一卡2卡4卡5卡6卡残暴在线| 亚洲av无码乱码在线观看野外 | 亚洲国产一区二区视频网站| 最近中文字幕免费完整| 一级女性全黄久久生活片免费| 亚洲精品在线电影| 亚洲欧洲无码AV电影在线观看| 午夜一区二区免费视频| 在线a免费观看最新网站| 老司机精品免费视频| 亚洲不卡av不卡一区二区| 东北美女野外bbwbbw免费| 亚洲综合色婷婷在线观看| 亚洲va在线va天堂va不卡下载| 亚洲AV无码之日韩精品| 日本最新免费不卡二区在线| 免费观看美女用震蛋喷水的视频| 在线观看特色大片免费网站| 国产黄在线播放免费观看|