views:

2004

answers:

3

I have a table and two databases which have the same table, but one is a symlink of the other one and only read is permitted on this table.

I have mapped the table to Java using Hibernate and I use spring to set the Entity Manager's data source as one of the two databases based on some input criteria.

I call only read only operations (selects) when I am connected to the second database, but it seems Hibernate tries to flush something back to the database and it fails telling update is not allowed on this view.

How do I disable this update only for the second datasource and keep it normal for the first one?

Update: Looking at the stack trace, the flush seems to be started here:


          at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
          at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
          at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
          at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
          at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:504)
          ... 55 more

Is this related to hibernate.transaction.flush_before_completion property? Can I set it to false for the second data source?

+1  A: 

First you need to determine if this is DDL or DML. If you don't know, then I recommend you set *hibernate.show_sql=true* to capture the offending statement.

If it is DDL, then it's most likely going to be Hibernate updating the schema for you and you'd want to additionally configure the hibernate.hbm2ddl.auto setting to be either "update" or "none", depending on whether you're using the actual db or the symlinked (read-only) one, respectivley. You can use "validate" instead of none, too.

If it is DML, then I would first determine whether your code is for some reason making a change to an instance which is still attached to an active Hibernate Session. If so, then a subsequent read may cause a flush of these changes without ever explicitly saving the object (Grails?). If this is the case, consider evicting the instance causing the flush ( or using transport objects instead ).

Are you perhaps using any aspects or Hibernate lifecycle events to provide auditing of the objects? This, too, could cause access of a read-only to result in an insert or update being run.

It may turn out that you need to provide alternative mappings for the offending class should the updatability of a field come into play, but the code is doing everything exactly as you'd like ( this is unlikely ;0 ). If you are in an all-annotation world, this may be tricky. If working with hbm.xml, then providing an alternative mapping is easier.

Darren Hicks
It is not DDL, it is issuing a DML only, I am in using only annotations and no hbm.xml.Looking at the stacktrace, the update seems to be started because of this: 375400 at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365) 375401 at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:504) 375402 ... 55 moreIs this related to the hibernate.transaction.flush_before_completion setting?
Arvind
+3  A: 

Most probably your entities become "dirty" the same moment they are loaded from the database, and Hibernate thinks that it needs to store the changes. This happens, if your accessors (get and set methods) are not returning the exact same value or reference that had been set by Hibernate.

In our code, this happened with lists, developers created new list instances because they didn't like the type they got in the setter.

If you don't want to change the code, change the mapping to field access.

You can also prevent Hibernate of storing changes by setting FlushMode to never on the session, but this only hides the real problem which will still occur in other situations an will lead to unnecessary updates.

Stefan Steinegger
A: 

I am facing a similiar problem with Spring Transaction management. I am using hibernate as ORM framework. And below is the excerpt of spring configuration file of my application which uses spring transaction management.

<context:annotation-config/>
    <context:property-placeholder location="classpath:spring.properties"/>

    <tx:annotation-driven transaction-manager="transactionManager"/>
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="create*" rollback-for="Exception"/>
            <tx:method name="update*" rollback-for="Exception"/>
            <tx:method name="remove*" rollback-for="Exception"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="ServiceOperation" expression="execution(* com.shaikh.demo.*Service.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="ServiceOperation"/>
    </aop:config>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

All my *Service Classes are annotated by @Transactional annotation.

In my hibernate DTO classes I am modifying return value for each get* method as below because I want to remove all the non-ascii characters. The data in the database is for read-only purpose just for listing down the records ,before this I need to remove non-ascii characters which are creating problems. Database is Oracle 11g.

e.g. For attribute accountNumber

public String getAccountNumber(){
      return StringHelper.removeNonAscii(this.accountNumber);
}

I have read that we are changing the state of the DTO object and making it dirty so hibernate is flushing this dirty objects into the db. I can see the update statements in logs.

Here my questions are :

1.) I am making DTO objects dirty but I have marked get* related methods as Read-only so how can hibernate is flushing changes to the db.

2.) How can I solve my problem related to this Non Ascii character without changing my database data. Am I missing something ?

Shaikh Mohammed Shariq