shardingsphere use Spring Transactional change isolation not work - java

shardingsphere-jdbc 5.0.0 LOCAL Transaction
Spring framework 5.2.12
mysql default Transaction isolation : REPEATABLE-READ
spring use : #Transactional(rollbackFor = Exception.class,isolation = Isolation.READ_UNCOMMITTED)
I've been debugging spring change isolation code
if (currentIsolation != definition.getIsolationLevel()) false no changes made
org.springframework.jdbc.datasource.DataSourceUtils.prepareConnectionForTransaction:
spring_change_isolation_code
ShardingSphereConnection default isolation TRANSACTION_READ_UNCOMMITTED
ShardingSphereConnection.java
sql session isolation still REPEATABLE-READ
How to solve it?

Related

Java JPA, setting transaction isolation level using an entity manager

I'm trying to set a transaction isolation level for the connection associated with a given entity manager (TRANSACTION_SERIALIZABLE etc.).
I have scoured the internet for a solution and found a few. However, none of them seem to work.
When I try to do the following :
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory("BankingPU");
public EntityManager em = emfactory.createEntityManager();
java.sql.Connection connection = (java.sql.Connection) em.getDelegate();
connection.setTransactionIsolation(TRANSACTION_SERIALIZABLE);
I get the following exception:
Exception in thread "main" java.lang.ClassCastException:
org.eclipse.persistence.internal.jpa.EntityManagerImpl cannot be cast to java.sql.Connection
When I do
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory("BankingPU");
public EntityManager em = emfactory.createEntityManager();
java.sql.Connection connection = em.unwrap(java.sql.Connection.class);
The value stored to connection is null.
I ran the following in order to find out more:
Object obj = em.getDelegate();
The class type stored in obj is org.eclipse.persistence.internal.jpa.EntityManagerImpl
Edit: (oops, guess I could have told that from the exception)
Edit2:
I have managed to obtain the session (i think) by calling :
Session session = ((EntityManagerImpl) em).getSession();
However, neither the connection(), nor the DoWork() methods are present in it.
Any idea how to follow up on this and set the transaction isolation level?
JPA API does not have transaction (TX) isolation level management API. So it is not possible do it via entity manager.
If you want to use the same entity manager than you need, as it already mentioned in Neil Stockton comment, your JPA provider specific code to get JDBC access for changing TX isolation level.
Adam Bien almost answered on your question at his blog post.
Isolation Levels can be set on java.sql.Connection level. In a Java EE environment isolation levels can be configured on Data Source / Connection Pool (see e.g. Glassfish).
As workaround, if you want use only JPA API, you may create in your application server the several data sources for the same database with required isolation level.
However you need to understand that you will have the several 1st level caches (in different entity managers) and you should manage your entities state in appropriate way.
I have found the solution:
emfactory = Persistence.createEntityManagerFactory("BankingPU");
em = emfactory.createEntityManager();
Session session = ((EntityManagerImpl) em).getSession();
DatabaseLogin databaseLogin = (DatabaseLogin) session.getDatasourceLogin();
databaseLogin.setTransactionIsolation(DatabaseLogin.TRANSACTION_SERIALIZABLE);

Is none transaction faster than setting #Transactional(readOnly = true) for read methods?

If we have a service that only gets data from database via Hibernate, is there any advantage adding the annotation #Transactional(readOnly = true) or in this case we shouldn't use any transaction for the methods/service?
Enabling readOnly=true informs Hibernate to set FlushMode as NEVER, but if our service does not have all CRUD operations is there any meaning for it?
Does any service that access a repository should be transactional?

how to set jpa transaction isolation to read_commited

I am trying to set jpa transaction isolation level to read_committed. I am using hibernate 4.1.6. there was a time we could do
Connection connection = session.connection();
connection.setTransactionIsolation(Connection.READ_COMMITTED);
But now that session.connection is not available any more, i am a bit confused. what is the best way of setting isolation on jpa? I am using seam 2.3.
thanks in advance
apparently this is one way of doing it:
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
}
});
but in seam it will break if you are change the transation isolation level once the transaction started already.

Why can I insert/update data with hibernate even when there's no transaction involved?

As we all know that in Hibernate if no transaction commit, the changes won't affect in database. But I found something weird. And the code as follows:
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring.xml");
SessionFactory sessionFactory = (SessionFactory) ctx.getBean("sessionFactory");
Session session = sessionFactory.openSession();
Model model = new Model();
...
session.save(model);
session.flush();
session.close();
And the model was saved to database even there's no transaction, anyone can explain this?
Any comments would be appreciated! Thanks!
PS: I am using mysql.
The session.flush command saved the transaction. If it's wrong, you should use transaction.
usually hibernate needs the line session.beginTransaction(); to work. You didn't write that and your application worked, I guess your application runs in an Application server, which provides transaction management. e.g. jboss, weblogic...
However it doesn't mean that there is no transaction. Did you set auto-commit true?
btw, session.flush() and txn.commit() are different.
Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory.
After session.flush(), you still can call txn.rollback() to rollback all changes.
edit
oh I saw you used spring. did you configured txnmanager in spring?
Hibernate doesn't need transactions, the most common problems in database-based applications are just easier to solve with transactions which is why usually everyone uses transactions with Hibernate. But that's mere coincidence/convention/laziness.
All Hibernate needs is a java.sql.Connection and if your container provides one even though there is no current transaction manager configured, Hibernate is fine with that.
In fact, Hibernate has no idea that there might be a transaction manager. So session.flush() will use the ApplicationContext to get a connection, generate the SQL and use JDBC to send the generated SQL code to the database.
From Hibernate's point of view, that's all that happens.
There can be several reasons why the data is committed to the database:
You forgot to turn of auto commit on the connection.
Your web container / spring config automatically wires a transaction manager that synchronizes with HTTP requests.
Your code is called form another method which is annotated with #Transactional; in this case, you inherit the existing transaction.

using JdcbTemplate standalone

We are looking into using the JdbcTemplate for accessing the DB - but we have many different DB-connections, that each class could use, so injecting the jdbcTemplate is not an option atm. So if we do a
jdbcTemplate = new JdbcTemplate(dataSource);
what will the transaction policy be? Auto-commit is off in the DB.
You can configure each javax.sql.DataSource object to enable auto-commit if that does the job, or disable auto-commit and write the transaction logic programatically.
Both the java.sql.Connection and the javax.sql.DataSource class have methods for enable/disable auto-commit.
Regarding dependency injection and Spring, you can still inject a datasource object into your repository. If you also let each repository extend the org.springframework.jdbc.core.support.JdbcDaoSupport class, then you have a JdbcTemplate object available for you with the derived getJdbcTemplate() method.
You can also let Spring handle the transaction handling for you. Without a XA transaction manager, you need one transaction manager for each datasource. With many transaction managers, declarative transaction support with the #Transactional annotation is impossible. You can however, inject the transaction manager into your service class. This is described in the reference documentation here.

Categories

Resources