2014-10-09 88 views
1

Im在理解Spring處理hibernate實體的方式方面存在一些麻煩,並且執行了延遲加載過程。Spring事務中的Hibernate實體生命週期和會話生命週期

因此,對於這種情況下,我們的實體

@Entity 
public class EntityA{ 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 


    @ManyToMany(cascade={CascadeType.PERSIST, CascadeType.REFRESH}) 
    private Collection<EntityB> bss= new ArrayList<EntityB>(); 

和agregated實體

@Entity 
public class EntityB{ 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 


    @ManyToMany(mappedBy="bss") 
    private Collection<EntityA> ass= new ArrayList<EntityA>(); 

然後我有一個簡單的業務類標記爲事務:

@Component 
@Scope("session") 
@Transactional(propagation=Propagation.TRIED_EVERY_SINGLE_ONE) 
public class GenericTestBean { 

    private EntityA entityA; 

    @Autowired 
    private IGenericDAO genericDAO; 


    public GenericTestBean() { 
     System.out.println("bean creado!"); 
    } 

    public void testQuery() { 
     entityA= genericDAO.get(EntityA.class, 1l); 
     System.out.println(TransactionIndicatingUtil.getTransactionStatus(true)); 
     System.out.println("is element atached? :" + genericDAO.isAtached(entityA)); 
     //this.loadData(); 

    } 

    public void loadData(){ 

     System.out.println(TransactionIndicatingUtil.getTransactionStatus(true)); 
     System.out.println("is element atached? :" + genericDAO.isAtached(currentCompany)); 

     System.out.println(entityA.getBss.size()); 
    } 

} 

和簡單測試類

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "applicationContext.xml" }) 
@WebAppConfiguration 
public class EntityQueryTest { 

// @Autowired 
// private SessionFactory sessionFactory; 

    @Autowired 
    GenericTestBean genericTestBean; 


    @Test 
    public void consultarCompania(){ 

     genericTestBean.testQuery(); 
     genericTestBean.loadData(); 
    } 

什麼IM guessin應該發生的是:1。 被GenericTestBean實例 2. testQuery從代理外界稱爲啓動事務 2 loadData被調用時,代理看到活動的事務,並採取存在資源 3.數據retrieived 4. transacion關閉...

但是,這並不發生,似乎是在每個方法調用不同的事務,而實體被分離的呼叫之間,發行一個懶惰的init異常。

實際輸出日誌是這樣的:

bean creado! --here the object get created 
Hibernate: select company0_.companyId as ..... --here the first query get executed 
[com.pe.controlLines.data.dao.GenericTestBean.testQuery] --here we check the name for the transaction 
is element atached? :true --and see if the element is attached to the session 
[com.pe.controlLines.data.dao.GenericTestBean.loadData] --this is in the second method call (with a different transaction name :O) 
is element atached? :false --both now, the same element get detached 

我嘗試重新連接的實體,但是這給了我到數據庫中加一個新的查詢(表EntityA一個新的查詢發送查詢得到對象,我真的不喜歡)。

IM希望保存一個額外的查詢只是爲了有延遲加載,還是必須是這個樣子?也許我有一些配置錯了嗎?

PDTA:我想查看過濾選項比重新安裝選項,即使最壞的情況,就可能導致在高併發嚴重的性能問題。

任何人都可以請澄清方法的調用之間的事務上下文的行爲,以及它是如何被相關的會話和實體的狀態?

的TransactionIndicatingUtil實現從這裏http://java.dzone.com/articles/monitoring-declarative-transac?page=0,1

採取和通用DA​​O是這個想法後建立 General or specific DAO to record delivery with information from multiple tables?

更新

的情況下,一定用處的,這裏是Spring配置文件

<context:component-scan base-package="xxxxxx" /> 

    <context:annotation-config /> 
    <context:spring-configured /> 

    <aop:aspectj-autoproxy proxy-target-class="true"/> 

    <!-- Data Source Declaration --> 
    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"> 
     <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 

     <property name="url" value="jdbc:mysql://localhost:3306/xxxx" /> 

     <property name="username" value="xxxxx" /> 
     <property name="password" value="xxxxx" /> 
     <property name="initialSize" value="2" /> 
     <property name="minIdle" value="0" /> 
     <property name="minEvictableIdleTimeMillis" value="120000" /> 
     <property name="maxActive" value="20" /> 
     <property name="maxWait" value="5000" /> 
    </bean> 

    <!-- Session Factory Declaration <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> --> 
    <!-- Session Factory Declaration --> 
    <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
     <property name="dataSource" ref="myDataSource" /> 
     <property name="packagesToScan"> 
      <list> 
       <value>com.xx.xx.xx.xx</value> 
      </list> 
     </property> 
     <property name="hibernateProperties"> 
      <props> 
       <prop key="hibernate.hbm2ddl.auto">update</prop> 
       <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
       <prop key="hibernate.show_sql">true</prop> 
       <prop key="hibernate.search.default.directory_provider">filesystem</prop> 
       <prop key="hibernate.search.default.indexBase">C:/DEVELOPMENT/lucene/indexes</prop> 


      </props> 
     </property> 
    </bean> 

    <!-- Enable the configuration of transactional behavior based on annotations --> 
    <tx:annotation-driven transaction-manager="txManager"/> 

    <!-- Transaction Manager is defined --> 
    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="SessionFactory"/> 
    </bean> 
+0

顯示我不太清楚,如果你正在談論的XML代碼(註釋掉)從testQuery()到loadData()的內部調用,但如果你是然後:http://stackoverflow.com/a/8233459/1356423 – 2014-10-09 15:31:48

+0

Nop,實際上,當我取消註釋它的作品,就像我期望它可以:它可以一些彈簧錯過配置問題? – 2014-10-09 15:40:21

回答

0

測試類應該是事務太

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "applicationContext.xml" }) 
@Transactional // <--- add 
public class EntityQueryTest { 

我假設你applicationContext.xml文件是在您的文章

+0

它的其他選項類似的評論,如果我有的第一層是一個xhtml,而不是一個類本身,我是如何做到這一點?我的意思是,通過各種呼叫保持跨國管理(例如網絡嚮導) – 2014-10-09 17:43:55

+0

請糾正我如果我錯了。春季代理本身不是transacctional權利?它只是爲每個方法調用創建並保存事務。在我們通過整個類傳播事務的情況下,會話將保持數據庫連接打開,這會導致明顯的問題。 (也許這是愚蠢的)......這是一種重新映射到現有實體的新連接而不再執行查詢的方法嗎?我可以100%確定分離的實體完全不會被併發會話修改,這是否可能不知何故? – 2014-10-10 14:19:10

+0

** 1 **:任何具有'@ Transactional'的Bean都被代理包裝爲**添加**事務支持(方法必須是公共的,不確定是否也適用於受保護的方法)。 **兩**:當你運行一個Spring App時,一個'ApplicationContext'被創建並管理所有的bean。考慮測試一個特殊的場景,你必須向Spring指出**運行**這些具有Transaction支持的'@ Test'方法,這就是爲什麼類有'@Transactional',其中在測試環境中,而不是在生產/運行環境中。 – 2014-10-10 15:32:08

0

JUnit測試本身不是事務性的。您的GenericTestBean bean的每種方法都是事務性的。因此,每次非事務性測試調用事務性bean的方法時,都會啓動事務,執行bean方法並提交事務。由於您先後調用兩個事務性方法,因此將啓動兩個單獨的事務。

如果測試方法本身是事務性的,那麼將爲測試方法啓動一個事務,並且(默認情況下),這兩個bean方法將在現有事務的上下文中執行,並由測試啓動。事務將在測試方法返回後提交。

+0

huuuum我明白了,但在最後一個元素是jsp的情況下,我怎樣才能保持事務和連接活着,以便爲許多操作創建單個事務? (也是懶惰的工作) – 2014-10-09 16:35:13