How to optimize the insert query time using hiberate? - java

I have about 1.4 million records of data but it is taking more than 3hr to insert them. I cannot seems to find the problem to it.
I read up and change from identity to sequence. It only improved by a little but it still take quite a long time to finish insert.
I am using:
Hibernate 5
Spring 4
mssql 2014
Wildfly 10
applicationContext-hibernate.xml
<tx:advice id="txAdvice">
<!-- the transactional semantics... -->
<tx:attributes>
<tx:method name="*_TransNew" propagation="REQUIRES_NEW" />
<tx:method name="*_NoTrans" propagation="NEVER" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="generate*" propagation="REQUIRED" />
<tx:method name="get*" propagation="REQUIRED" />
<tx:method name="is*" propagation="REQUIRED" />
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution of
an operation defined by the following -->
<aop:config>
<aop:pointcut id="demoServiceOperations"
expression="execution(* com.test.*.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="demoServiceOperations" />
</aop:config>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2012Dialect</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.jdbc.batch_size">50</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.order_updates">true</prop>
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">20</prop>
<prop key="hibernate.c3p0.timeout">1800</prop>
<prop key="hibernate.c3p0.max_statements">50</prop>
</props>
</property>
</bean>
Umts.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Nov 22, 2016 11:36:21 AM by Hibernate Tools 5.2.0.Beta1 -->
<hibernate-mapping>
<class name="com.test.domain.Umts" table="TBLDM_UMTS" schema="dbo" catalog="DEMO" optimistic-lock="version" dynamic-update="true">
<id name="umtsId" type="java.lang.Integer">
<column name="UMTS_ID" />
<generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
<param name="optimizer">pooled-lo</param>
<param name="increment_size">1</param>
<param name="sequence_name">UMTS_SEQ</param>
</generator>
</id>
<property name="cid" type="java.lang.Integer">
<column name="CI" not-null="true" />
</property>
<property name="channelNo" type="java.lang.Integer">
<column name="UARFCN" />
</property>
<property name="signalStrength" type="java.lang.Double">
<column name="EC_IO" precision="53" scale="0" />
</property>
<property name="sc" type="java.lang.Integer">
<column name="SC" />
</property>
<property name="latitude" type="java.lang.Double">
<column name="LATITUDE" precision="53" scale="0" />
</property>
<property name="longitude" type="java.lang.Double">
<column name="LONGITUDE" precision="53" scale="0" />
</property>
<property name="mcc" type="java.lang.Integer">
<column name="MCC" not-null="true" />
</property>
<property name="mnc" type="java.lang.Integer">
<column name="MNC" not-null="true" />
</property>
<property name="recvDate" type="date">
<column name="RECV_DATE" length="10" />
</property>
<property name="recvTime" type="time">
<column name="RECV_TIME" length="16" />
</property>
</class>
</hibernate-mapping>
Service class:
public void process(List<Umts> umtsList)
{
for (int i = 0; i < umtsList.size(); i = i + PropertiesUtil.MAX_COMMIT_COUNT)
{
int min = i;
int max = i + PropertiesUtil.MAX_COMMIT_COUNT;
if (max > umtsList.size())
{
max = umtsList.size();
}
createUmts_TransNew(umtsList.subList(min, max));
}
}
#Override
public void createUmts_TransNew(Collection list)
{
// TODO Auto-generated method stub
umtsDAO.saveAll(list);
}
DAO class:
#Transactional
public void saveAll(Collection collection)
{
log.debug("** save all");
try
{
if (collection != null && collection.size() > 0)
{
for (Object obj : collection)
{
sessionFactory.getCurrentSession().saveOrUpdate(obj);
}
}
}
catch (RuntimeException re)
{
log.error("** save all failed", re);
throw re;
}
}
** Edited
Does connection pool plays a part here? Meaning does connection pool helps with the performance? Do i need to add the jar file to the wildfly 10 or to application itself?

First off, try increasing the pooled-lo value. Since you set it to 1, there is no optimisation/pooling going on - since every ID that needs to be fetched needs a call to the DB to get the actual value. If you have a bigger increment size, hibernate will pre-fetch/reserve a block of ID's to use for new entities, without a per-entity round-trip.
Not sure how the code you posted is executed, but I'm assuming you're inserting them sequentially in a single thread. You can:
Use a thread-pool in which each thread takes a number of items from the list/queue to insert.
The items inserted in a single transaction by one thread has ideally same size as the configured hibernate batch size to again, minimize roundtrips.
Ensure the number of threads in the pool is in par with the connection pool size, so you don't end up blocking the worker threads when waiting for a connection.
Ensure connection pool size is reasonable for the load your server can take and use a good connection pool (eg. HikariCP). Here is an interesting writeup on connection pool size.

Related

Hibernate : why createQuery() appends package name to the Entity Name?

I am trying to query database from two Different Tables i.e.
query = "select rbt.rbtCode, rbt.maskedName, cmas.catId, cmas.maskedName " +
"from CrbtRbt rbt, CrbtCategoryMaster cmas " +
"where rbt.playable='Y' and rbt.showOnWeb='Y' and rbt.rbtCode!=0 " +
"and rbt.catId=cmas.catId";
but when I pass this query through session.createQuery(query);
It appends package name to the next in coming Entity Name i.e.
select rbt.rbtCode, rbt.maskedName, cmas.catId, cmas.maskedName
from CrbtRbt rbt, com.telemune.toolGeneratedPojos.CrbtCategoryMaster cmas
where rbt.playable='Y' and rbt.showOnWeb='Y' and rbt.rbtCode!=0 and rbt.catId=cmas.catId
and gives the following Exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: CrbtRbt is not mapped [select rbt.rbtCode, rbt.maskedName, cmas.catId, cmas.maskedName from CrbtRbt rbt, com.telemune.toolGeneratedPojos.CrbtCategoryMaster cmas where rbt.playable='Y' and rbt.showOnWeb='Y' and rbt.rbtCode!=0 and rbt.catId=cmas.catId]
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.java:180)
at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement(FromElementFactory.java:110)
at org.hibernate.hql.internal.ast.tree.FromClause.addFromElement(FromClause.java:93)
at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromElement(HqlSqlWalker.java:325)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3252)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3141)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:694)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:550)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:287)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:235)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:248)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:183)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:101)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:119)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:214)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:192)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1537)
at com.telemune.generator.TestQuery.select(TestQuery.java:114)
at com.telemune.generator.PojoGenerator.main(PojoGenerator.java:191)
But if I query the Entities One By One it shows the desired result successfully.
i.e.
select rbt.rbtCode, rbt.maskedName
from CrbtRbt rbt
where rbt.playable='Y' and rbt.showOnWeb='Y' and rbt.rbtCode!=0;
gives desired result.
Can anyone Explain what I can do?
here is some example code:
Query Code
hql = session.createQuery(query);
hql.setMaxResults( querySchema.getMaxRes() );
list=hql.list();
For information I have done All the Mappings and included all the libraries very carefully no chance of any mistake.
UPDATE
As I said I have done the mappings carefully but someone may have doubts so here is the mapping:
<hibernate-mapping>
<class name="com.telemune.toolGeneratedPojos.CrbtCategoryMaster" schema="SDP" table="CRBT_CATEGORY_MASTER">
<id name="catId" type="java.lang.Integer">
<column name="CAT_ID" precision="4" scale="0" />
<generator class="assigned" />
</id>
<property column="SHOW_IN_SMS" name="showInSms" type="java.lang.String" />
<property column="SHOW_ON_WEB" name="showOnWeb" type="java.lang.String" />
<property column="PLAYABLE" name="playable" type="java.lang.String" />
<property column="STATUS" name="status" type="java.lang.String" />
<property column="IMAGE_PATH" name="imagePath" type="java.lang.String" />
<property column="DESCRIPTION" name="description" type="java.lang.String" />
<property column="MASKED_NAME" name="maskedName" type="java.lang.String" />
<property column="IVR_FILEPATH_1" name="ivrFilepath1" type="java.lang.String" />
<property column="IVR_FILEPATH" name="ivrFilepath" type="java.lang.String" />
<property column="MASKED_NAME_1" name="maskedName1" type="java.lang.String" />
</class></hibernate-mapping>
and for CRBT_RBT:
<hibernate-mapping>
<class name="com.telemune.toolGeneratedPojos.CrbtRbt" schema="SDP" table="CRBT_RBT">
<id name="rbtCode" type="java.lang.Integer">
<column name="RBT_CODE" precision="10" scale="0" />
<generator class="assigned" />
</id>
<property column="PLAYABLE" name="playable" type="java.lang.String" />
<property column="OTHER" name="other" type="java.lang.Integer" />
<property column="IMAGE_PATH" name="imagePath" type="java.lang.String" />
<property column="RBT_ORDER" name="rbtOrder" type="java.lang.Integer" />
<property column="VALIDITY_PERIOD" name="validityPeriod" type="java.lang.Integer" />
<property column="LYRICIST" name="lyricist" type="java.lang.String" />
<property column="APPROVED_BY" name="approvedBy" type="java.lang.String" />
<property column="PREV_CAT_ID" name="prevCatId" type="java.lang.Integer" />
<property column="RELEASE_YEAR" name="releaseYear" type="java.lang.Integer" />
<property column="COMPOSER" name="composer" type="java.lang.String" />
<property column="SHOW_ON_WEB" name="showOnWeb" type="java.lang.String" />
<property column="MASKED_NAME" name="maskedName" type="java.lang.String" />
<property column="CONTENT_PROVIDER_CODE" name="contentProviderCode" type="java.lang.Integer" />
<property column="CREATE_DATE" name="createDate" type="java.sql.Date" />
<property column="IVR_FILEPATH" name="ivrFilepath" type="java.lang.String" />
<property column="CORP_ID" name="corpId" type="java.lang.Integer" />
<property column="SHOW_IN_SMS" name="showInSms" type="java.lang.String" />
<property column="ALBUM_NAME" name="albumName" type="java.lang.String" />
<property column="NOKIA" name="nokia" type="java.lang.Integer" />
<property column="STATUS" name="status" type="java.lang.String" />
<property column="FILE_PATH" name="filePath" type="java.lang.String" />
<property column="REFERENCE_ID" name="referenceId" type="java.lang.Integer" />
<property column="CHARGING_CODE" name="chargingCode" type="java.lang.Integer" />
<property column="RBT_NICK" name="rbtNick" type="java.lang.String" />
<property column="APPROVAL_DATE" name="approvalDate" type="java.sql.Date" />
<property column="CAT_ID" name="catId" type="java.lang.Integer" />
<property column="RBT_SCORE" name="rbtScore" type="java.lang.Integer" />
<property column="ARTIST_NAME" name="artistName" type="java.lang.String" />
</class>
</hibernate-mapping>
I don't think there is any mistake in the mapping.
Hibernate.cfg.xml :
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.password">sdp</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:#10.168.2.127:1521:mastera</property>
<property name="hibernate.connection.username">sdp</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<mapping resource="com/telemune/toolGeneratedPojos/CrbtRbt.hbm.xml"/>
<mapping resource="com/telemune/toolGeneratedPojos/CrbtCategoryMaster.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Well, I got this.
SessionFactory getSessionFactory(className) {
try {
configuration.addResource( className + ".hbm.xml" );
}catch (Exception e) {
e.printStackTrace();
}
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
return configuration.buildSessionFactory(serviceRegistry);
here is the code to add .hbm.xml file,programatically, for each class while creating session factory.
try {
sessionFactory = ...getSessionFactory(className);
session = sessionFactory.openSession();
}
catch (Exception e) {
e.printStackTrace();
}
the problem with this code was that:
1. It was building a new session factory for each call(of getSessionFactory(classname)).
2. a new session was opened every time.
So, only the mapping of last class added to configuration was added as a resource and that's why its was searching the other classes by appending the packageName to it's name.
What I did is:
I just counted the no of mapping files in the package and added them with the help of a loop in the same session factory.
And it worked.
Here is the way:
File file = new File(packageName.replace(".", "/"));
for(File file1 : file.listFiles()){
if(file1.getName().trim().substring(file1.getName().trim().lastIndexOf("."),
file1.getName().trim().length()).equalsIgnoreCase(".xml")){
configuration.addResource( packageName.replaceAll("\\.", "/") + "/" + file1.getName() );
}
}
It was just a silly mistake.

Lazy=true ignored for Hibernate + H2, but ok for Hiberante + MySQL

H2 1.4.191.
Hibernate: 5.1.0.Final.
All Spring modules: 4.2.5.RELEASE.
How fix this?
Next code gives me result with children:
getSessionFactory().getCurrentSession().createQuery(
"from Category where categoryParentId = :parentId").setLong("parentId", parentId).list();
//------------------------------------------------
<class name="com.domain.Category" table="Category">
<id name="id" type="long" access="property">
<column name="categoryId" length="20"/>
<generator class="identity"/>
</id>
<property name="name" column="categoryName" type="string"/>
<property name="parentId" column="categoryParentId" type="long"/>
<bag name="children" table="Category" inverse="true" lazy="true" fetch="select">
<key>
<column name="categoryParentId" not-null="true"/>
</key>
<one-to-many class="com.domain.models.Category"/>
</bag>
</class>
//----------------------------...
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.globally_quoted_identifiers=true">true</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>

Hibernate performance issue with updates more than 10K records

I am presently trying to do a bulk upload operation where in i need to parse an excel and update the details into the database. The problem is the data needs to be stored into multiple tables and the relationship is maintained. The problem is not when i have about 50-100 records to updated, but hugely affected when i have around 50000 records to be updated. It takes ages to upload and sometimes the browser gives up waiting for the response to arrive. Please find below the code and the mapping files. Please let me know what i can do to increase the performance and complete the processing quicker.
Note: The cascades are all required.
***.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.****.****.hibernate.****" table="V_ACCOUNT_DIM">
<id name="acctDimIdN" type="long">
<column name="ACCT_DIM_ID_N" precision="10" scale="0" />
<generator class="sequence">
<param name="sequence">ACCOUNT_DIM_SEQ</param>
</generator>
</id>
<property name="gdwIdN" type="long">
<column name="GDW_ID_N" precision="38" scale="0" not-null="true" />
</property>
<property name="pycisInstnIdN" type="java.lang.Long">
<column name="PYCIS_INSTN_ID_N" precision="10" scale="0" />
</property>
<property name="acctNotesC" type="string">
<column name="ACCT_NOTES_C" length="4000" />
</property>
<property name="trdSysShrtNmC" type="string">
<column name="TRD_SYS_SHRT_NM_C" length="100" />
</property>
<property name="reimbAuthorizeD" type="date">
<column name="REIMB_AUTHORIZE_D" length="7" />
</property>
<property name="reimbInitD" type="date">
<column name="REIMB_INIT_D" length="7" />
</property>
<property name="reimbEffD" type="date">
<column name="REIMB_EFF_D" length="7" />
</property>
<property name="acctGainLossAmtN" type="java.lang.Double">
<column name="ACCT_GAIN_LOSS_AMT_N" precision="15" />
</property>
<property name="buySellIndC" type="string">
<column name="BUY_SELL_IND_C" length="10" />
</property>
<property name="navImpcN" type="java.lang.Double">
<column name="NAV_IMPC_N" precision="15" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" not-null="true" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" not-null="true" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" not-null="true" />
</property>
<set name="incidentAcctSecFacts" table="V_INCIDENT_ACCT_SEC_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.****.***.***.I***Fact" />
</set>
<set name="incidentAcctFacts" table="V_INCIDENT_ACCT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.****.***.***.I***Fact" />
</set>
<set name="accountAttachmentFacts" table="V_ACCOUNT_ATTACHMENT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.****.***.***.A****Fact" />
</set>
</class>
</hibernate-mapping>
I****Dim.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.****.***.***.I****Dim" table="V_****_DIM">
<id name="incidentDimIdN" type="long">
<column name="INCIDENT_DIM_ID_N" precision="10" scale="0" />
<generator class="sequence">
<param name="sequence">INCIDENT_DIM_SEQ</param>
</generator>
</id>
<property name="errMemoIdC" type="string">
<column name="ERR_MEMO_ID_C" length="60" not-null="true" unique="true" />
</property>
<property name="errMemoD" type="date">
<column name="ERR_MEMO_D" length="7" />
</property>
<property name="idD" type="date">
<column name="ID_D" length="7" not-null="true" />
</property>
<property name="incidentD" type="date">
<column name="INCIDENT_D" length="7" not-null="true" />
</property>
<property name="ntfcD" type="date">
<column name="NTFC_D" length="7" not-null="true" />
</property>
<property name="totGainLossN" type="java.lang.Double">
<column name="TOT_GAIN_LOSS_N" precision="18" scale="2"/>
</property>
<property name="ovrdAttachedAcctC" type="string">
<column name="OVRD_ATTACHED_ACCT_C" length="1" />
</property>
<property name="gainLossCalcMthdC" type="string">
<column name="GAIN_LOSS_CALC_MTHD_C" length="4000" />
</property>
<property name="deemedAnErrC" type="string">
<column name="DEEMED_AN_ERR_C" length="1" not-null="true" />
</property>
<property name="errRatifiedC" type="string">
<column name="ERR_RATIFIED_C" length="1" not-null="true" />
</property>
<property name="errAcctUsedC" type="string">
<column name="ERR_ACCT_USED_C" length="1" not-null="true" />
</property>
<property name="aprvPrcsC" type="string">
<column name="APRV_PRCS_C" length="4000" />
</property>
<property name="incidentShrtDescC" type="string">
<column name="INCIDENT_SHRT_DESC_C" length="4000" />
</property>
<property name="incidentSumC" type="string">
<column name="INCIDENT_SUM_C" length="4000" />
</property>
<property name="incidentNotesC" type="string">
<column name="INCIDENT_NOTES_C" length="4000" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" not-null="true" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" not-null="true" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" />
</property>
<set name="incidentAttachmentFacts" table="V_****FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="10" scale="0" not-null="true" />
</key>
<one-to-many class="com.****.***.***.I***Fact" />
</set>
<set name="incidentActionItemFacts" table="V_****_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" />
</key>
<one-to-many class="com.****.***.***.I****Fact" />
</set>
<set name="incidentAcctSecFacts" table="V_****FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.***.***.****.IncidentAcctSecFact" />
</set>
<set name="irgMemberAssignmentFacts" table="V_IRG_MEMBER_ASSIGNMENT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" />
</key>
<one-to-many class="com.***.***.****.IrgMemberAssignmentFact" />
</set>
<set name="incidentAcctFacts" table="V_INCIDENT_ACCT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.***.***.****.IncidentAcctFact" />
</set>
<set name="acctAttachmentFacts" table="V_ACCOUNT_ATTACHMENT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.***.***.****.AccountAttachmentFact" />
</set>
</class>
</hibernate-mapping>
CerSecurityDim.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.***.***.****.CerSecurityDim" table="V_CER_SECURITY_DIM">
<id name="cerSecuDimIdN" type="long">
<column name="CER_SECU_DIM_ID_N" precision="22" scale="0" />
<generator class="sequence">
<param name="sequence">CER_SECURITY_DIM_SEQ</param>
</generator>
</id>
<property name="fmrCusipC" type="string">
<column name="FMR_CUSIP_C" length="30" not-null="true" />
</property>
<property name="tckrC" type="string">
<column name="TCKR_C" length="30" />
</property>
<property name="secuNmC" type="string">
<column name="SECU_NM_C" not-null="true" />
</property>
<property name="numOfShrTrdN" type="java.lang.Long">
<column name="NUM_OF_SHR_TRD_N" precision="10" scale="0" />
</property>
<property name="secuGainLossN" type="java.lang.Double">
<column name="SECU_GAIN_LOSS_N" precision="15" />
</property>
<property name="buySellIndC" type="string">
<column name="BUY_SELL_IND_C" length="10" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" not-null="true" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" not-null="true" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" not-null="true" />
</property>
<set name="incidentAcctSecFacts" table="V_INCIDENT_ACCT_SEC_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="SECU_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.***.***.****.IncidentAcctSecFact" />
</set>
</class>
</hibernate-mapping>
IncidentAcctFact.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.***.***.****.IncidentAcctFact" table="V_INCIDENT_ACCT_FACT">
<id name="incidentAcctFactIdN" type="long">
<column name="INCIDENT_ACCT_FACT_ID_N" precision="22" scale="0" />
<generator class="sequence">
<param name="sequence">INCIDENT_ACCT_FACT_SEQ</param>
</generator>
</id>
<many-to-one name="accountDim" class="com.***.***.****.AccountDim" fetch="select">
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<many-to-one name="incidentDim" class="com.***.***.****.IncidentDim" fetch="select">
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<!-- <many-to-one name="attachmentTypeDim" class="com.***.***.****.AttachmentTypeDim" fetch="select">
<column name="ATTACHMENT_TYPE_DIM_ID_N" precision="22" scale="0" not-null="false" />
</many-to-one> -->
<property name="relEffFromD" type="date">
<column name="REL_EFF_FROM_D" length="7" />
</property>
<property name="relEffThruD" type="date">
<column name="REL_EFF_THRU_D" length="7" />
</property>
<property name="ltstRelIndC" type="string">
<column name="LTST_REL_IND_C" length="1" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" not-null="true" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" />
</property>
</class>
</hibernate-mapping>
IncidentAcctSecFact.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.***.***.****.IncidentAcctSecFact" table="V_INCIDENT_ACCT_SEC_FACT">
<id name="incidentAcctSecIdN" type="long">
<column name="INCIDENT_ACCT_SEC_ID_N" precision="22" scale="0" />
<generator class="sequence">
<param name="sequence">INCIDENT_ACCT_SEC_FACT_SEQ</param>
</generator>
</id>
<many-to-one name="accountDim" class="com.***.***.****.AccountDim" fetch="select">
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<many-to-one name="cerSecurityDim" class="com.***.***.****.CerSecurityDim" fetch="select">
<column name="SECU_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<many-to-one name="incidentDim" class="com.***.***.****.IncidentDim" fetch="select">
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<property name="relEffFromD" type="date">
<column name="REL_EFF_FROM_D" length="7" />
</property>
<property name="relEffThruD" type="date">
<column name="REL_EFF_THRU_D" length="7" />
</property>
<property name="ltstRelIndC" type="string">
<column name="LTST_REL_IND_C" length="1" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" />
</property>
</class>
</hibernate-mapping>
The method where the actual processing is as follows.
public boolean retrieveDataAndParseFile(IncidentDetailsForm incidentDetailsForm, BaseViewBean baseViewBean$Session,
ActionMessages errors) throws Exception {
boolean savedStatus = false;
boolean deletedstatus = false;
/*List<AccountDim> accountsList = new ArrayList<AccountDim>();
List<CerSecurityDim> cerSecuList = new ArrayList<CerSecurityDim>();
List<IncidentAcctSecFact> inciAcctSecFactList = new ArrayList<IncidentAcctSecFact>();
List<IncidentAcctFact> inciAcctFactList = new ArrayList<IncidentAcctFact>();
List<IncidentDim> incidentList = new ArrayList<IncidentDim>();*/
try {
double totalSecGL= 0.00;
double secTrdNetTotal= 0.00;
DecimalFormat twoDForm = new DecimalFormat("#.##");
String loginUser = baseViewBean$Session.getLoggedInUser().getUserId();
List<Long> addedElementList = new ArrayList<Long>();
CerSecurityDim cerSecDim = null;
AccountDim account = null;
IncidentAcctSecFact iasFact = null;
IncidentAcctFact iaFact = null;
long incidentId = baseViewBean$Session.getIncidentDim$Session().getIncidentDimIdN();
IncidentDim incident = (IncidentDim)incidentDimDao.findById(IncidentDim.class, incidentId);
ExcelListenerBean beanDetails;
List<AccountDim> acctList = new ArrayList<AccountDim>();
List <CerSecurityDim> cerSecList = new ArrayList<CerSecurityDim>();
List <IncidentAcctSecFact> iasFactList = new ArrayList<IncidentAcctSecFact>();
for (Map.Entry<Integer, ExcelListenerBean> entry : baseViewBean$Session.getExcelRecords().entrySet())
{
beanDetails = entry.getValue();
//Initialize the net amounts for incorrect trade and correction trade.
secTrdNetTotal= 0;
cerSecDim = new CerSecurityDim();
account = new AccountDim();
iasFact = new IncidentAcctSecFact();
iaFact = new IncidentAcctFact();
//
Object[] pycisDet = investmentDimDao.getPyCISIdByShrtName(beanDetails.getShortName());
if(pycisDet != null && pycisDet.length > 0){
account.setPycisInstnIdN((Long)pycisDet[0]);
account.setGdwIdN((Long)pycisDet[1]);
account.setTrdSysShrtNmC(beanDetails.getShortName());
if(!addedElementList.contains((Long)pycisDet[0])){
addedElementList.add((Long)pycisDet[0]);
}
}
//
cerSecDim.setFmrCusipC(beanDetails.getFmrCusip());
SecurityDim sec = getSecDetailsByCusip(beanDetails.getFmrCusip());
if(sec != null){
cerSecDim.setSecuNmC(sec.getSecuNmC());
cerSecDim.setTckrC(sec.getTckrC());
}else {
cerSecDim.setSecuNmC("UNKNOWN");
cerSecDim.setTckrC("UNKNOWN");
}
//
cerSecDim.setNumOfShrTrdN(beanDetails.getIncorrectTrdShares().longValue());
//
cerSecDim.setBuySellIndC(beanDetails.getIncorrectTrdBuySell().toUpperCase());
account.setBuySellIndC(beanDetails.getIncorrectTrdBuySell().toUpperCase());
//
secTrdNetTotal = Double.valueOf(twoDForm.format(beanDetails.getIncorrectTrdNet())) +
Double.valueOf(twoDForm.format(beanDetails.getCorrectionTrdNet()));
//
totalSecGL = totalSecGL + secTrdNetTotal;
boolean updatedStatus = false;
// create the relationship and then add to the respective lists.
cerSecDim.setInsUsrC(loginUser);
cerSecDim.setInsTsD(AppGlobalUtil.getCurrentTimeStamp());
cerSecDim.setDelIndC(AppGlobalConstants.HardCodedValues.No);
if(!acctList.isEmpty()){
for( AccountDim olderAccount :acctList){
if(olderAccount.getPycisInstnIdN().compareTo(account.getPycisInstnIdN()) == 0) {
double newAcctGainLossAmt=0;
double oldAcctGainLossAmt=0;
if(account.getAcctGainLossAmtN() != null){
newAcctGainLossAmt = account.getAcctGainLossAmtN();
}
if(olderAccount.getAcctGainLossAmtN() != null){
oldAcctGainLossAmt = olderAccount.getAcctGainLossAmtN();
}
double newGLAmt = newAcctGainLossAmt + oldAcctGainLossAmt;
account = olderAccount;
account.setAcctGainLossAmtN(newGLAmt);
updatedStatus = true;
}
}
}
if(!cerSecList.isEmpty()){
for(CerSecurityDim olderCerSecDim : cerSecList){
if(olderCerSecDim.getFmrCusipC().equals(cerSecDim.getFmrCusipC())) {
cerSecDim = olderCerSecDim;
double newSecuGainLoss = 0;
double oldSecuGainLoss = 0;
if(cerSecDim.getSecuGainLossN() != null){
newSecuGainLoss = cerSecDim.getSecuGainLossN();
}
if(olderCerSecDim.getSecuGainLossN() != null){
oldSecuGainLoss = olderCerSecDim.getSecuGainLossN();
}
cerSecDim.setSecuGainLossN(newSecuGainLoss + oldSecuGainLoss);
for(IncidentAcctSecFact olderIASFact : iasFactList){
if(olderIASFact != null && olderIASFact.getCerSecurityDim() != null
&& olderIASFact.getCerSecurityDim().getFmrCusipC().equals(cerSecDim.getFmrCusipC())){
iasFact = olderIASFact;
}
}
}
}
}
if(!deletedstatus){
deleteAllImpactedAccounts(baseViewBean$Session);
deletedstatus = true;
}
totalSecGL = Double.valueOf(twoDForm.format(totalSecGL));
account.setInsUsrC(loginUser);
account.setInsTsD(AppGlobalUtil.getCurrentTimeStamp());
account.setDelIndC(AppGlobalConstants.HardCodedValues.No);
accountDimDao.saveOrUpdate(account);
iasFact.setAccountDim(account);
iasFact.setIncidentDim(incident);
iasFact.setCerSecurityDim(cerSecDim);
iasFact.setInsUsrC(loginUser);
iasFact.setInsTsD(AppGlobalUtil.getCurrentTimeStamp());
iasFact.setDelIndC(AppGlobalConstants.HardCodedValues.No);
cerSecDim.getIncidentAcctSecFacts().add(iasFact);
account.getIncidentAcctSecFacts().add(iasFact);
incident.getIncidentAcctSecFacts().add(iasFact);
if(!updatedStatus){
iaFact.setAccountDim(account);
iaFact.setIncidentDim(incident);
iaFact.setInsUsrC(loginUser);
iaFact.setInsTsD(AppGlobalUtil.getCurrentTimeStamp());
iaFact.setDelIndC(AppGlobalConstants.HardCodedValues.No);
incident.getIncidentAcctFacts().add(iaFact);
account.getIncidentAcctFacts().add(iaFact);
}
incident.setTotGainLossN(totalSecGL);
cerSecurityDimDao.saveOrUpdate(cerSecDim);
incidentAcctSecFactDao.saveOrUpdate(iasFact);
if(!updatedStatus){
accountDimDao.saveOrUpdate(account);
}
if(!acctList.contains(account)){
acctList.add(account);
}
if(!cerSecList.contains(cerSecDim)){
cerSecList.add(cerSecDim);
}
if(!iasFactList.contains(iasFact)){
iasFactList.add(iasFact);
}
if(!updatedStatus){
incidentAcctFactDao.saveOrUpdate(iaFact);
}
incidentDimDao.saveOrUpdate(incident);
NumberFormat formatter = new DecimalFormat("#0.00");
incidentDetailsForm.setTotalGainLoss(formatter.format(totalSecGL));
savedStatus = true;
/*accountsList.add(account);
cerSecuList.add(cerSecDim);
inciAcctSecFactList.add(iasFact);
inciAcctFactList.add(iaFact);
incidentList.add(incident);*/
}
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
throw e;
}
finally{
baseViewBean$Session.getExcelRecords().clear();
baseViewBean$Session.setExcelRecords(null);
}
/*accountDimDao.saveOrUpdateAll(accountsList);
cerSecurityDimDao.saveOrUpdateAll(cerSecuList);
incidentAcctSecFactDao.saveOrUpdateAll(inciAcctSecFactList);
incidentAcctFactDao.saveOrUpdateAll(inciAcctFactList);
incidentDimDao.saveOrUpdateAll(incidentList);*/
return savedStatus;
}
The dao functions are accessed from another file.
Please let me know how i can increase my performance.
The problem is that you are trying to do this from a browser, where the default timeout for a page is 30 seconds. You should be doing this from an application so that you can control the amount of time you wait to upload the records.
I am having lookalike problems.
Make sure that you have all keys for join and search fields.
May be you can store your file in temporary location and then handle it by paralell thread.
Another option is to use Stateless Sessions (there is almost no info on the net, see hibernate manual) I am not sure if there is an option to fill ManyToMany collections.
Caching getOrCreate queries by saving copy of table in memory may help you (but you may run into OutOfMemory exception, so pass -Xmx param to your app).
All these may not solve your problem. I've decided to implement these inserts using native sql queries.
There are multiple issues that should be looked at:
Long-running operations should be run asynchronously. If you are using Spring, you can annotate #Async, for instance. Then your transaction is not beholden to network connectivity or browser/HTTP timeouts.
Batch operations in Hibernate can be very slow. Even if you set up JDBC batching, and even if you follow the instructions in the Hibernate documentation, you are still beholden to the fact that you are using an ORM. ORMS are best used for maintaining state for object-oriented operations, not for batch operations, where any individual object's state is less relevant.
Batch operations in Hibernate can be very finicky. For instance, the Hibernate batching documentation fails to note that you need to set additional flags in the configuration to make sure that it batches correctly. See this post for details.
At the end of the day, ORMs will always be slower than base SQL. Consider swtiching over to base SQL, maybe concatenating SQL statements so that you have fewer database trips, or using a stored proc, passing bactches of data to the proc and have it run the inserts.
when you open session use openStatelessSession and call session.update at the end. this way persistentcontext cannot have 10000 object in cache and all the updates happens in db.

hibernate is updating in the middle of selects

I have a legacy web app that I am maintaining. It started out as Java 1.4, but I've compiled it to Java5. We're using Spring+Hibernate. I'm not using annotations yet. I'm sticking with XDoclet for now. In it, I have an object graph that looks like this:
Job 1:m Operations 1:m Activities 1:m Transactions
Those Transactions are NOT J2EE transactions. We're just documenting the workflow from one Activity to another.
In HttpRequest#1, I update a couple of Activities and create a new Transaction. Then in HttpRequest#2, I redisplay the entire Job. What I am seeing at this point is the usual SELECT statements for the Job, Operations and Activities, but then I'm seeing some UPDATE statements for the Transactions. It turns out those updates are reverting the Transactions back to their previous states, discarding the latest updates.
Why in the world is Hibernate doing this?
As requested, here's the .hbm.xml file:
<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>
And here's an example transaction setup:
<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>
From some Hibernate Javadoc document on Google http://ajava.org/online/hibernate3api/org/hibernate/FlushMode.html:
AUTO
public static final FlushMode AUTO
The Session is sometimes flushed before query execution in order to ensure that queries never return stale state. This is the default flush mode.
Every modification you are doing on a JPA-managed entity is done in a persistent context. That means Hibernate is assuming that the things that you modify in your entity are safe to be committed. So when you select data from the same entity or related entities, in this mode Hibernate puts consistency of your changes over everything else. So it flushes and then does the read to reflect your changes correctly. If you do not want to have this behavior you can do two things:
disable auto-commit (which I prefer, but it is some kind of a JPA convention, so make up your mind). The downside of this approach is that you have to do more by hand depending on your configuration. The upside is, that everything is much more explicit and less magic
change your code that you collect the data you need first. Also this would make your code much cleaner. Because it would work like the basic computer science pattern everybody understands: Input, Computation, Output. Your mixing those things up, which is the reason why the default mode does not work.
Edit: On how to use Spring's PlatformTransactionManager best without using annotations I would recommend the TransactionTemplate: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html#tx-prog-template
Just inject your PlatformTransactionManager (Hibernate) there and use it to abstract from the transaction handling.
Depending on your FLUSHMODE you will see this, because whenever you do a query, hibernate will normally guess as to whether it should FLUSH to get a clean and consistent read.
Ok, finally found the problem. Here's a more complete flow:
I have Controller C1, Manager M1, Manager M2 and Persister P1. M1 and M2 have managed transactions as I stated above, using TransactionProxyFactoryBean.
C1.methodA() calls M1.methodB() which calls P1.methodC()
C1.methodA() then calls M2.methodD(), which then calls M1.methodE() which calls P1.methodF().
See the problem yet?
It happens when M1.methodD calls M1.methodE(). What I think happens is that since both M1 and M2 are transaction managed, two transactions are created, one for each call. Those two transactions battle it out for which one has the true state of the system, with neither one truly winning.

How to make service use particular txAdvice in Spring?

I'm trying to upgrade my project and so I've come to transactions. This is how I did it up to now.
<bean id="userServiceTarget" class="com.forgin.service.UserServiceImpl">
<property name="userDAO" ref="userDAO" />
</bean>
<bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="userServiceTarget" />
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_SUPPORTS</prop>
<prop key="is*">PROPAGATION_SUPPORTS</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
I changed the transaction attributes like this bellow, but I'm not quite sure how could I link the service with exactly this txAdvice. Cause I generally have different transaction attributes for different services so there I guess should be more than one txAdvice. Is there a way how to say the #Transactional to use this particular txAdvice?
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="is*" read-only="true" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
Alright, I figured out it.. it just came to me. Haha.. I just need to provide additional aop:advisor and aop:pointcut. As simple as that.
<aop:config>
<aop:pointcut id="userOperation"
expression="execution(* com.forgin.service.UserServiceImpl.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
<aop:pointcut id="differentOperation"
expression="execution(* com.forgin.service.DifferentServiceImpl.*(..))" />
<aop:advisor advice-ref="txAdviceDifferent" pointcut-ref="differentOperation" />
</aop:config>

Categories

Resources