Java – How to refresh updated entity data without restarting the server

eclipselinkjavajpa

I am using EclipseLink JPA as ORM and web logic 10.3 as an application server in my project. Everything working fine until i got a bug for data refresh. Here is the case one of my entity table row is updated to new value but my entity manager or JPA did not pick that value. For this we have lite rely re started the server. then it picked up the value.

Here is my persistence.xml file and here is the way i am using entity manager in my class.

<persistence-unit name="BasePersistenceUnit" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/CTH_DS</jta-data-source> 
    <class>org.test.partyrequest.model.dataobject.RqstTrc</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>

    <properties>
        <property name="eclipselink.target-server" value="WebLogic_10" />
        <!-- Logging level is set to INFO, Need to change in Production -->
        <property name="eclipselink.logging.level" value="FINE" />
        <property name="eclipselink.persistence-context.flush-mode" value="COMMIT" />
        <property name="eclipselink.persistence-context.close-on-commit" value="true" />
        <property name="eclipselink.cache.shared.default" value="false" />      
    </properties>
</persistence-unit>

SPRING JPA XML FILE

<context:load-time-weaver aspectj-weaving="on" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="BasePersistenceUnit" />
</bean>

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" />

<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" /> 

<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->

<!-- Instruct Spring to perform declarative transaction management automatically on annotated classes. -->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>

<!-- Post-processor to perform exception translation on @Repository classes
    (from native exceptions such as JPA PersistenceExceptions to Spring's DataAccessException hierarchy).
-->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

My Entity calss

@Entity

@Table(name = "PRTY_RQST")
public class PrtyRqst implements Serializable {

private static final long serialVersionUID = -4679712398918736694L;

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PRTY_RQST_PRTYRQSTID_GENERATOR")
@SequenceGenerator(name = "PRTY_RQST_PRTYRQSTID_GENERATOR", allocationSize = 1, sequenceName = "PRTY_RQST_SEQ")
@Column(name = "PRTY_RQST_ID")
private Long prtyRqstId;

@Column(name = "CHLD_RQST_IND")
private String chldRqstInd;

@Column(name = "PARNT_PRTY_RQST_ID")
private BigDecimal parntPrtyRqstId;

@Column(name = "PROCES_REFR")
private String procesRefr;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "RQST_DT_TM")
private Date rqstDtTm;

@Column(name = "UPDT_BY")
private String updtBy;

// bi-directional many-to-one association to PrtyKey
@OneToMany(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<PrtyKey> prtyKeys;

// bi-directional many-to-one association to PrtyRqstHist
@OneToMany(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@OrderBy("rqstDtTm DESC")
private List<PrtyRqstHist> prtyRqstHists;

@OneToOne(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private RqstPayload rqstPayload;

// bi-directional many-to-one association to RqstTrc
@OneToMany(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<RqstTrc> rqstTrcs;

// bi-directional many-to-one association to AddtnRqstInfo
@OneToMany(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<AddtnRqstInfo> addtnRqstInfos;

// bi-directional many-to-one association to BusnApplc
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinColumn(name = "BUSN_APPLC_ID")
private BusnApplc busnApplc;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinColumn(name = "INTN_PROCES_TYP_ID")
private IntnProcesTyp intnProcesTyp;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinColumn(name = "INTN_STATS_ID")
private IntnStat intnStat;

@Column(name = "ORCHESTRATION_ID")
private String orchestrationId;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinColumn(name = "ALLW_CHNL_ID")
private AllwChnl allwChnl;

// bi-directional many-to-one association to RqstTyp
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinColumn(name = "RQST_TYP_ID")
private RqstTyp rqstTyp;

@Column(name = "TRACK_RQST_IND")
private String trackRqstInd;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "SUBMIT_DT_TM")
private Date submitDtTm;

@Temporal(TemporalType.DATE)
@Column(name = "EFFECTIVE_DT")
private Date effectiveDt;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "RQST_CREATE_DT_TM")
private Date rqstCreateDtTm;

In my DAO IMPL class I have this.persist(prtyRqstDO);

@Transactional(readOnly = true, propagation=Propagation.REQUIRED)
    private PartyRequestBO createRequest(PartyRequestBO partyRequestBO, boolean isParent) throws RuntimeException {
        if (log.isDebugEnabled()) {
            log.debug("Enter: PartyRequestsDAOImpl:createRequest()");
        }
        partyRequestBO.setOrchestrationID(generateOrchestrationId());
        PrtyRqst prtyRqstDO = PartyRequestEntityMapper.partyRequestMapper(partyRequestBO, isParent, true);
        try {
            this.persist(prtyRqstDO);
            partyRequestBO.setRequestIdentifier(prtyRqstDO.getPrtyRqstId());
        } catch (Exception e) {
            if(log.isDebugEnabled()) {
                log.debug("PartyRequestsDAOImpl:createRequest : " + PartyRequestConstants.UNABLE_TO_INSERT, e);
            }
            throw new PartyRequestDataException(PartyRequestConstants.UNABLE_TO_INSERT, e);
        }
        if (log.isDebugEnabled()) {
            log.debug("Exit: PartyRequestsDAOImpl:createRequest()");
        }
        return partyRequestBO;
    }


@Transactional(readOnly = true, propagation=Propagation.REQUIRED)
public void persist(T entity) {
    if (log.isDebugEnabled()) {
        log.debug("Enter: BaseDAO:persist() : " + entity);
    }
    this.getEntityManager().persist(entity);
    if (log.isDebugEnabled()) {
        log.debug("Exit: BaseDAO:persist()");
    }
}
public EntityManager getEntityManager() {
    if (log.isDebugEnabled()) {
        log.debug("Enter: BaseDAO:getEntityManager() : " + this.entityManager);
    }
    return this.entityManager;
}

Here the problem is, if i update the row in one of the table through back end my application container is not picking the change.

Can any one Tell me? thank you in advance.

EDIT:

Thank you both of you. I have modified according to your comments added following lines of code.

this.entityManager.clear();
this.entityManager.close();
//this.getEntityManager().refresh(entityManager);

Here i could able to get the update value what i have done it through backend with out restarting server. But the problem is it hold all the changed values.

for example i have changed value to FulOrderWSA it was working. changed to FulorderWSB it was working again.Now i have tried for FulOrderWSZ it didn't work(DB values is FulorderWSB ).

Finally i tried here with old value that is FulorderWSA as per DB it should not work but it worked for me. what i noticed that it is holding all the DB changed values here.

How to get ride of this. I have used both clear and close for entityManager. can any one help me on this.

thank you.

Vijay.

Best Answer

You have turned off the EclipseLink shared cache (AKA second level cache), so the issue is likely that you are holding onto long lived EntityManagers. Once an entity becomes managed by the EM, JPA requires that EM to return that exact instance from every find/query operation as it was when first read and any changes your app might have made to it.

There are a number of options. The best is to look at your EntityManager lifecycle and only obtain an EntityManager when needed, and close it when done. Or, just call em.clear() at points to prevent them from filling up, which will detach all entities associated to the em. Make sure to flush changes though if you wish to keep the changes before calling clear.

If there is a specific entity you need to refresh, em.refresh(entity) will work. This will clear any changes the application might have made though, and can be dangerous with cascade refresh settings mixed with lazy access - so use carefully or you may unintentionally wipe out changes to a whole tree at a later time.

Related Topic