Hibernate vs Spring connection acquisition strategy - java

I'm trying to understand when exactly a database connection is aquired in an application that uses hibernate as an ORM & Spring for transaction management.
In this article, it says:
If the transaction manager decides to create a new transaction, then it will:
create a new entity manager
bind the entity manager to the current thread
grab a connection from the DB connection pool
bind the connection to the current thread
However here it says :
Hibernate defers the database connection acquisition until the current transaction has to execute its first SQL statement (either triggered by a read or a write operation). This optimization allows Hibernate to reduce the physical transaction interval, therefore increasing the chance of getting a connection from the pool.
I can't understand how can Hibernate delay the connection aquisition if Spring decides to aquire it before.

I can't understand how can Hibernate delay the connection aquisition
if Spring decides to aquire it before.
The decision is taken by the transaction manager and so potentially by the JpaTransactionManager/HibernateTransactionManager
Hibernate 5.2.0 introduces new property hibernate.connection.provider_disables_autocommit
With this Hibernate can delay the database connection acquisition until there is a JDBC Statement to execute. otherwise the database connection is acquired when entering the #Transactional service method.
So to allow Spring wires this property into the JPATransactionManager during the setup of spring context you have to set this property in your application.properties/yaml -->
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true
Last thing required to do this --> setAutoCommit to false on the connection pool provider (by default HikariCP since Spring boot 2)
spring.datasource.hikari.auto-commit=false

Related

Hibernate late lazy loading in Java

If I load a City object from DB using Hibernate session, and then using the same session which has not been used for an hour, if I do a city.getCountry() which should lazy load the Country object, I get an Exception (Connection marked as broken because of SQLSTATE(08003)). I got two general questions:
Is lazy loading just another new JDBC connection and totally
independent connection under the hood?
What kind of parameters in hibernate connection pool configuration I
need to tune to increase the timeout for these kind of situations?
I'm not using transactions.
I'm using HikariCP and my DB is Postgrsql.

EJB3 DataSource DataSource.getConnection

In a CMT J2EE environement (Container Managed Transaction) what transaction / connection is used when I JDNI-lookup for a DataSource object and invoke DataSource.getConnection?
Is this connection part of the (potentially distributed) transaction? Does getConnection() return the same Connection every time I call it for the same DataSource object? I only know using Connections by the same EntityManager using native SQL statements.
It is something that keeps me puzzling. As I understood the SessionContext defines a transactional system that is used throught every time I use a datasource. I have the problem that inside a session bean a DataSource.getConnection() is used and this connection is then closed. If a problem is encountered SessionContext.setForRollBack(true) is issued.
Therefore how does the transactional context of a service relate to a DataSource?
If we spawn a new Connection each time a datasource is used or at least looked up, I have problems to understand things I already know. Any clarification would be wonderful. I know container managed transaction and other systems, but the actual behavior of DataSource is totally beyond me.
In Java EE a transaction is a concept that is not exclusive to databases, for example JMS connection sessions can also be part of container managed transaction. The idea is if one or more than one method is running under container managed transaction boundary, the container will commit or rollback the transaction as needed.
In data base related data source, there are multiple layers, fist is the managed pool of connection which is maintained by the container, second is the actual connection management of the database driver with the database, in Java a Connection is an abstraction for a session with a database and not a physical connection, that is managed by the driver.
With the above context, your questions could be addressed viz.:
what transaction / connection is used when I JDNI-lookup for a DataSource object and invoke DataSource.getConnection.
Under container managed transaction, though it is implementation dependent, a connection/session with the database is associated that is marked with the transaction boundary. The actual physical connection could be shared with the database by the driver but that is transparent to application as well as the container.
Is this connection part of the (potentially distributed) transaction? Does getConnection return the same Connection every time I call it for the same DataSource object?
Refer above, a Connection has no relation with the underlying socket to the database as opened by the driver. It is logically a separate session and if within transaction boundary, the same session is associated with the connection retrieved from the data source, how this is implemented is part of the container design
I have the problem that inside a session bean a DataSource.getConnection is used and this connection is then closed
In a pooled implementation for connection a Connection.close() has no impact, the connection is returned to the pool(http://commons.apache.org/proper/commons-dbcp/api-1.3/org/apache/commons/dbcp/PoolableConnection.html), this behaviour is similar for all pools. So clsing a connection does not necessarily disassociate it from container transaction boundary, though a connection should not be closed within container managed transaction. Similarly, commit, setAutoCommit, rollback must not be called from within CMT as this will issue the following command equivalent to the actual database and the behaviour of the transaction after that will undefined.
Have a look at the declaration of the #Resource annotation.
It includes a shareable attribute that allows you to specify connection sharing behaviour. It defaults to true, which means that you will get connection sharing automatically if you do nothing.
This attribute is also included in the XML schema for any resource-ref defined datasources that you may lookup using JNDI.
All resources (JDBC, JMS, ResourceManager) that are included during an invocation are enrolled in the current transaction. You may sometimes need to specify the use of XA for this to work correctly.

Open Session in View vs #Transactional

I had been using #Transactional annotations in my Service Layer. But to resolve an error due to Lazy Loading in View I had to use Open Session in View Filter. After this, without use of #Transaction itself a Session gets opened and transaction starts. So does that mean #Transactions are not required? How will transactions and roll-backs be handled, then in Service Layers?
The javadoc explains it:
This filter makes Hibernate Sessions available via the current thread, which will be autodetected by transaction managers. It is suitable for service layer transactions via HibernateTransactionManager or JtaTransactionManager as well as for non-transactional execution (if configured appropriately).
NOTE: This filter will by default not flush the Hibernate Session, with the flush mode set to FlushMode.NEVER. It assumes to be used in combination with service layer transactions that care for the flushing: The active transaction manager will temporarily change the flush mode to FlushMode.AUTO during a read-write transaction, with the flush mode reset to FlushMode.NEVER at the end of each transaction. If you intend to use this filter without transactions, consider changing the default flush mode (through the "flushMode" property).

JPA persistence.xml flushmode with Hibernate 3.0

I understand that Hibernate uses transparent write behind by default for committing the transactions.
However, I would like my entity-manager to commit my transaction on the database immediately after the transaction is committed. Is there anyway I can configure this in persistence.xml of JPA ?
Hibernate would have to commit in the database at the time is made commits the transaction. You can also find it helpful to have two additional options:
Define the Session and autocommit (entering the property "hibernate.connection.autocommit" in the properties of the connection)
Forcing hibernate transaction synchronize with the database transaction in the middle of the transaction (by session.flush ())
Regards,

Writing messages with Spring JmsTemplate using a TransactionManager

Using Spring-JMS it is possible to receive messages within an external transaction context via the DefaultMessageListenerContainer.
However the only documented way to write a message is via JmsTemplate.send(…) and I can't see how this can be coerced to use a given TransactionManager.
Can anyone point me in the right direction?
More info: Ensuring a transaction manager is available (WebSphereUowTransactionManager), using JmsTemplate.write against an Oracle AQjmsFactory.getQueueConnectionFactory(dataSource) results in:
org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is oracle.jms.AQjmsException: could not use local transaction commit in a global transaction
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:168)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:469)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:534)
Caused by: oracle.jms.AQjmsException: could not use local transaction commit in a global transaction
at oracle.jms.AQjmsSession.commitNoCheck(AQjmsSession.java:1053)
at oracle.jms.AQjmsSession.commit(AQjmsSession.java:1021)
at org.springframework.jms.support.JmsUtils.commitIfNecessary(JmsUtils.java:217)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:573)
at org.springframework.jms.core.JmsTemplate$3.doInJms(JmsTemplate.java:536)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:466)
... 24 more
Caused by: java.sql.SQLException: could not use local transaction commit in a global transaction
at oracle.jdbc.driver.PhysicalConnection.disallowGlobalTxnMode(PhysicalConnection.java:6647)
at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:3635)
at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:3680)
at oracle.jdbc.OracleConnectionWrapper.commit(OracleConnectionWrapper.java:133)
at oracle.jms.AQjmsSession.commitNoCheck(AQjmsSession.java:1049)
... 29 more
So whilst I have no reason to doubt the advise below, I am not able to test it as I can't figure out how to get AQ JMS to not attempt a commit. Will update as I learn more.
My understanding is that JMS producers are inherently transacted via JTA. By sending a message via JMS MessageProducer, the thread-local JTA transaction is used (if one is present).
This is hinting at by the Spring manual (section 21.2.5):
JmsTemplate can also be used with the JtaTransactionManager and an XA-capable JMS ConnectionFactory for performing distributed transactions. Note that this requires the use of a JTA transaction manager as well as a properly XA-configured ConnectionFactory.
This is also suggested by JmsAccessor.setSessionTransacted (the superclass of JmsTemplate) (javadoc):
Set the transaction mode that is used when creating a JMS Session. Default is "false".
Note that within a JTA transaction, the parameters passed to create(Queue/Topic)Session(boolean transacted, int acknowledgeMode) method are not taken into account. Depending on the J2EE transaction context, the container makes its own decisions on these values. Analogously, these parameters are not taken into account within a locally managed transaction either, since the accessor operates on an existing JMS Session in this case.
Setting this flag to "true" will use a short local JMS transaction when running outside of a managed transaction, and a synchronized local JMS transaction in case of a managed transaction (other than an XA transaction) being present. The latter has the effect of a local JMS transaction being managed alongside the main transaction (which might be a native JDBC transaction), with the JMS transaction committing right after the main transaction.
So by start a JTA transaction (i.e. by using Spring's transaction API with JtaTransactionManager) and calling JmsTemplate.send(...), you will be sending the message bound to that transaction.

Categories