2011-08-04 77 views
1

我有一個遺留的Web應用程序,我正在維護。它起初是Java 1.4,但我將它編譯成Java5。我們使用Spring + Hibernate。我還沒有使用註釋。我現在堅持使用XDoclet。在這裏面,我有一個對象圖,看起來像這樣:休眠正在更新中選擇

工作1:M操作1:M活動1:M交易

這些交易是 J2EE交易。我們只是記錄從一個活動到另一個活動的工作流程。

在HttpRequest#1中,我更新了一些活動並創建了一個新的事務。然後在HttpRequest#2中,我重新顯示整個Job。我在這裏看到的是Job,Operations和Activities的通常SELECT語句,但是後來我看到了這些Transactions的一些UPDATE語句。事實證明,這些更新正在將事務恢復到以前的狀態,放棄最新的更新。

爲什麼在這個世界上Hibernate是這樣做的?

按照要求,這裏的的.hbm.xml文件:

<hibernate-mapping> 
    <class name="ActivityTransaction" table="imed_if_move_transactions" 
    lazy="false" mutable="true"> 
    <cache usage="nonstrict-read-write" /> 
    <id name="id" column="IF_MOVE_TRANSACTION_ID" type="java.lang.Long"> 
     <generator class="sequence"> 
     <param name="sequence">IMED_IF_MOVE_TRANSACTIONS_S</param> 
     </generator> 
    </id> 
    <property name="activityActionKey" type="java.lang.String" 
     update="true" insert="true" column="ACTIVITY_ACTION_KEY" /> 
    <property name="approvalStatus" type="int" update="true" 
     insert="true" column="APPROVAL_STATUS" /> 
    <property name="authorizedBy" type="java.lang.Long" update="true" 
     insert="true" column="AUTHORIZATION_ID" /> 
    <many-to-one name="authorizedByUser" 
     class="UserModel" cascade="none" 
     outer-join="false" update="false" insert="false" not-found="ignore" 
     fetch="select" column="AUTHORIZATION_ID" /> 
    <property name="date" type="java.util.Date" update="true" 
     insert="true" column="JOA_TRANSACTION_DATE" /> 
    <many-to-one name="from" 
     class="JobOpActivity" cascade="none" 
     outer-join="false" update="true" insert="true" fetch="select" 
     column="FM_JOB_OP_ACTIVITY_ID" /> 
    <property name="fromIntraActivityStepType" type="java.lang.Integer" 
     update="true" insert="true" column="FM_INTRAACTIVITY_STEP_TYPE" /> 
    <property name="fromIntraOperationStepType" type="java.lang.Integer" 
     update="true" insert="true" column="FM_INTRAOPERATION_STEP_TYPE" /> 
    <property name="fromOperationSeqNum" type="java.lang.Integer" 
     update="true" insert="true" column="FM_OPERATION_SEQ_NUM" /> 
    <many-to-one name="job" class="Job" 
     cascade="none" outer-join="false" update="true" insert="true" fetch="select" 
     column="WIP_ENTITY_ID" /> 
    <property name="operationEndDate" type="java.util.Date" 
     update="true" insert="true" column="OP_END_DATE" /> 
    <property name="operationStartDate" type="java.util.Date" 
     update="true" insert="true" column="OP_START_DATE" /> 
    <many-to-one name="organization" class="Organization" 
     cascade="none" outer-join="false" update="true" insert="true" fetch="select" 
     column="ORGANIZATION_ID" /> 
    <property name="processingStatus" type="java.lang.String" 
     update="true" insert="true" column="PROCESS_FLAG" /> 
    <property name="quantity" type="int" update="true" insert="true" 
     column="TRANSACTION_QUANTITY" /> 
    <property name="reasonId" type="java.lang.Long" update="true" 
     insert="true" column="REASON_ID" /> 
    <property name="reference" type="java.lang.String" update="true" 
     insert="true" column="REFERENCE" /> 
    <property name="scrapAccountId" type="java.lang.Long" update="true" 
     insert="true" column="SCRAP_ACCOUNT_ID" /> 
    <property name="spsaId" type="java.lang.Long" update="true" 
     insert="true" column="SPSA_ID" /> 
    <many-to-one name="to" 
     class="JobOpActivity" cascade="none" 
     outer-join="false" update="true" insert="true" fetch="select" 
     column="TO_JOB_OP_ACTIVITY_ID" /> 
    <property name="toIntraActivityStepType" type="java.lang.Integer" 
     update="true" insert="true" column="TO_INTRAACTIVITY_STEP_TYPE" /> 
    <property name="toIntraOperationStepType" type="java.lang.Integer" 
     update="true" insert="true" column="TO_INTRAOPERATION_STEP_TYPE" /> 
    <property name="toOperationSeqNum" type="java.lang.Integer" 
     update="true" insert="true" column="TO_OPERATION_SEQ_NUM" /> 
    <property name="typeId" type="java.lang.Long" update="true" 
     insert="true" column="TRANSACTION_TYPE_ID" /> 
    <property name="webKeyEntryId" type="java.lang.String" 
     update="true" insert="true" column="WEB_KEY_ENTRY_ID" /> 
    <property name="issueMaterial" type="true_false" update="true" 
     insert="true" column="MATERIAL_ISSUE" /> 
    <property name="createDate" type="java.util.Date" update="true" 
     insert="true" column="CREATION_DATE" /> 
    <property name="createdBy" type="java.lang.Integer" update="true" 
     insert="true" column="CREATED_BY" /> 
    <property name="lastUpdateDate" type="java.util.Date" update="true" 
     insert="true" column="LAST_UPDATE_DATE" /> 
    <property name="lastUpdatedBy" type="java.lang.Integer" 
     update="true" insert="true" column="LAST_UPDATED_BY" /> 
    </class> 
</hibernate-mapping> 

這裏是一個例子交易設置:

<bean id="moldingActivitiesService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    <property name="transactionManager" ref="etrack2ProviderTransactionManager"/> 
    <property name="target" ref="moldingActivitiesServiceTarget"/> 
    <property name="transactionAttributes"> 
    <props> 
     <prop key="*">PROPAGATION_REQUIRED</prop> 
    </props> 
    </property> 
</bean> 
+0

您可以發佈Transactions實體的源代碼(帶有註釋或來自hbm.xml的等效條目)嗎?我懷疑在你的對象圖中,Transactions實體是唯一使用非集合屬性的惰性抓取。 –

+0

啊,懶得取「非集合屬性」?不,我們不這樣做。 –

回答

0

好的,終於找到了問題。這裏有一個更完整的流程:

我有控制器C1,經理M1,經理M2和Persister P1。如上所述,M1和M2使用TransactionProxyFactoryBean管理事務。

  • C1.methodA()調用M1.methodB()它調用P1.methodC()
  • C1.methodA()然後調用M2.methodD(),然後調用M1.methodE()調用其P1.methodF()。

看到問題了嗎?

當M1.methodD調用M1.methodE()時發生。我認爲會發生的是,由於M1和M2都是交易管理,所以創建了兩個交易,每個交易一個交易。這兩筆交易將爭奪一個擁有該系統真實狀態的交易,而這兩筆交易都不會真正獲勝。

0

根據您的FLUSHMODE你會看到這一點,因爲每當你做一個查詢時,hibernate通常會猜測它是否應該FLUSH獲得乾淨一致的讀取。

+0

無論默認值是什麼,刷新模式都是如此。我們沒有改變它。 –

+0

也許我只需要添加一個調用flush()完成後? –

2

從谷歌已http://ajava.org/online/hibernate3api/org/hibernate/FlushMode.html一些休眠的Javadoc文檔:

AUTO

public static final FlushMode AUTO 

在會話查詢執行之前爲了有時沖洗,以確保查詢不會返回已經失效州。這是默認的沖洗模式。

對JPA託管實體所做的每個修改均在持久性上下文中完成。這意味着Hibernate假設您在實體中修改的內容可以安全地提交。所以當你從同一個實體或相關實體中選擇數據時,在這種模式下,Hibernate會將你的改變與其他事物保持一致。所以它會刷新,然後進行讀取以正確反映您的更改。如果你不想有這種行爲,你可以做兩件事:你可以做兩件事:

  • 禁用自動提交(我喜歡,但它是某種JPA約定,所以下定決心)。這種方法的缺點是,您必須手動完成更多工作,具體取決於您的配置。好處是,一切都更加明確,而且不那麼神奇
  • 改變你的代碼,你首先收集你需要的數據。這也會讓你的代碼更清潔。因爲它像大多數基本的計算機科學模式一樣工作:Input,Computation,Output。你將這些東西混合起來,這就是默認模式不起作用的原因。

編輯:關於如何使用Spring的PlatformTransactionManager的情況下儘量使用註釋我會建議TransactionTemplate的:有http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html#tx-prog-template 只需注入你的PlatformTransactionManager(休眠)並從處理事務中使用抽象。

+0

我沒有提到的是,更新是在一個HttpRequest期間,而選擇是下一個HttpRequest的一部分。這有什麼區別嗎? Hibernate應該已經完成​​了一個刷新,對吧? –

+0

我們的架構是三層控制器/管理器/持久存儲器,管理員使用Spring的TransactionProxyFactoryBean進行事務控制。 –

+0

好的,這有幫助。那麼你怎麼使用這個工廠bean呢?你使用哪個TransactionManager?您是否使用註釋來定義事務邊界? –