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

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

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

    學(xué)海拾遺

    生活、技術(shù)、思想無處不在學(xué)習(xí)
    posts - 52, comments - 23, trackbacks - 0, articles - 3
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

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

    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(關(guān)系-對象映射)針對對象的初始化分別提供了延遲和非延遲模式。非延遲裝載將在讀取時獲得對象和其所關(guān)聯(lián)的所有對象,這樣當(dāng)獲取一個實體對象時,將會導(dǎo)致成千上萬的select語句產(chǎn)生。這個問題在使用雙向關(guān)聯(lián)的時候?qū)⒏踊靵y,經(jīng)常會導(dǎo)致在初始化請求就需要讀取整個數(shù)據(jù)庫。當(dāng)然,某個人可以去繁重地檢查每一個對象之間的關(guān)系,并且花費更多的代價去手動地移除它們。但是最終,我們可能已經(jīng)失去了使用ORM工具換來的易用性。

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

    在WEB層上延遲

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

    攔截器配置

     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>            

    實現(xiàn)Hibernate DAO來使用打開的Session很簡單。實際上,如果你準(zhǔn)備用Spring框架來實現(xiàn)你的Hibernate DAO,最可能的是你不需要改變?nèi)魏我惶幋a。強制DAO必須通過方便的HibernateTemplate工具來訪問Hibernate,將會使得數(shù)據(jù)庫訪問是小菜一碟。下面是一個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  }               

    在業(yè)務(wù)層延遲

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

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

    BusinessObjectImpl類實現(xiàn)了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應(yīng)用程序上下文(Application Context)中的一些配置,我們能構(gòu)造HibernateInterceptor來攔截BusinessObjectImpl的調(diào)用,以允許它的方法延遲訪問數(shù)據(jù)對象。看一看下面的代碼片斷:

     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>               

    當(dāng)businessObject bean被引用時,HibernateInterceptor打開一個Hibernate Session并且將調(diào)用傳遞給BusinessObjectImpl。當(dāng)BusinessObjectImpl完成執(zhí)行時,HibernateInterceptor透明地關(guān)閉這個Session。應(yīng)用程序代碼沒有任何的持久化邏輯,然而它也能夠延遲地訪問數(shù)據(jù)對象。

    在你的單元測試中延遲

    最后一項重點是,我們需要能夠從Junit中測試我們的延遲應(yīng)用的能力。這很容易通過覆蓋用例測試(TestCase)類中的setUp和tearDown方法做到。我更趨向于將這些代碼放于一個方便的能被我所有的測試?yán)^承的抽象測試用例(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视频| 亚洲精品欧美综合四区| 亚洲日本香蕉视频| 久久久久无码精品亚洲日韩| 亚洲综合国产精品第一页| 国产免费拔擦拔擦8x| a级毛片无码免费真人| 最近免费中文字幕大全免费版视频 | 亚洲国产一区视频| 男女啪啪永久免费观看网站| 99久久99久久精品免费看蜜桃| 最近的2019免费中文字幕| 一级成人毛片免费观看| 美女羞羞视频免费网站| 精品国产亚洲第一区二区三区| 亚洲久悠悠色悠在线播放| 亚洲一卡2卡4卡5卡6卡在线99| 亚洲网站视频在线观看| 亚洲伦另类中文字幕| 亚洲成在人天堂在线| 久久综合九九亚洲一区| 亚洲av日韩av天堂影片精品| 亚洲日韩精品一区二区三区无码 | 亚洲黄色免费在线观看| 亚洲第一区香蕉_国产a| 亚洲ⅴ国产v天堂a无码二区| 亚洲Av综合色区无码专区桃色| 国产亚洲一区二区精品| 亚洲成AV人片在线观看无码| 亚洲综合另类小说色区| 亚洲区小说区激情区图片区| 人人狠狠综合久久亚洲88| 精品国产亚洲一区二区三区| 日韩亚洲人成在线综合日本| 国产亚洲精品国产| 亚洲国产综合精品中文第一区| 色婷婷六月亚洲婷婷丁香| 亚洲毛片在线免费观看|