Mix of Read/Write entity and readOnly query

I was wondering, how an entity, that is used mostly in READ/WRITE mode, behaves when one specific query use the hint READ_ONLY.

The entity contains static data, that is almost never changed. The existing code is a 20 year old project and uses the entity lots of places So if a single query would have a hint of READ_ONLY, how would that affect how Hibernate treats the presumably already loaded copies of the entity?

I have a problem with a dirty-checking operation spinning out oc control in one service call, so I was thinking, making the specific query READ_ONLY, would fix the problem, as the data is mostly static.

My current suggested version of the code is as follows:

 /* The documentation for the class states that it should not use HQL */
	SQLQuery codesQuery = getSession().createSQLQuery("select * from code where disabled = 0 order by type, value");
	codesQuery.addEntity(Code.class);
//	codesQuery.setFlushMode(FlushMode.MANUAL);
	codesQuery.setReadOnly(true);
	return codesQuery.list();

Both flush mode and the readOnly query hint solves my problem, so it seems. But reading up on the details in articles and books, I get more uncertain whether I understand the consequences of the alternatives properly or not.

I was assuming the query hint only affects the result of that single query and not every other use in the application, since the hint its not set on the session.

Any help would be appreciated.

The main sources of information I have used are, along with some books, other articles anb searches on the net:

https://www.baeldung.com/java-hibernate-entity-dirty-check

Entities that are already in the persistence context retain their status, but newly loaded entities are going to be loaded in “read-only” mode, which means that no initial state copy is made and no dirty checking will happen at flush time.
Note that these entities are loaded into the persistence context i.e. your Session, which may or may not be shared with other code that does queries within a transaction.
I don’t know how your code looks like and how you do transactions, but if all you do is open the session, start a transaction, run that query and then commit the transaction as well as close the session, then all the effects are isolated.
Changing the flush mode simply disables auto-flushing and hence requires that you call session.flush() manually, in case you want changes to be flushed to the database.

Hope that helps.

Can you share a bit more details about the “dirty-checking operation spinning out of control” situation? I’m curious how you come to that conclusion and what you think is the problem.

Thank you for the answer. ( I will answer the question about “dirty-checking spinning out of control” in a separate thread, as its a complex issue )

So what you are saying is that every entity(object) instance has each its own mode depending on which query mode it was retrieved with and thus operate independent of each others mode state.

So a global setting of e.g. READ_ONLY mode, affects all read entities, giving them the READ_ONLY state (its a silly example but underlines the point). While at the same time if a single query with a READ_WRITE mode, it would give only those loaded entities the different mode from those loaded with the global setting.

What happens if the same entity (same ID) is loaded as READ_WRITE and later (still Managed) queried with the hint of READ_ONLY, does it flush and throw out the already existing instance and reload it in the new mode

The details of the connection setup is approx as follows:

The app is a WildFly WAR file, with a class extended from HibernateDaoSupport, initialised in Spring XML with a sessionFactory of type org.springframework.orm.hibernate3.LocalSessionFactoryBean which reads in all .hbm.xml entity descriptions.

A connection is based on with the following code.

DbConnection.initSimple(getSession(), getHibernateTemplate());

DBConnection is an Nth level of indirections and abstractions, but basically returns a Session from the LocalSessionFactory the class was initialised with in the XML config.

No, it just uses the entity as it is from the persistence context.

Sorry, but I have no idea what that means. You know, since you’re using Wildfly (a Jakarta EE server), you could also make use of CDI/EJB to do the transaction management and inject the session into your beans instead. That way, the instance will be bound to the transaction and people can help you more easily, because you’re using a standard mechanism instead of a custom one that you’d first have to explain in depth.

Now, if you want me to help you with this, you will have to show a bit more code, ideally an end-to-end interaction so I can see what layers are involved and how you’re creating and sharing the session.

No, it just uses the entity as it is from the persistence context.

I understand, thank you so much for all your help.