0

i have a really heavy business logic. I use spring data jpa with microsoft sql server. My code looks like this.

@Transactional(rollbackFor = Exception.class)
public void executeAllFlows() {

    RandomTableObject a = randomTableObjectRepository.findById(1L);
    executeFlow1();
    executeFlow2();
    executeFlow3();
    executeFlow4();
    
    a.setSomeAttribute(true);
    randomTableObjectRepository.save(a);

}

@Transactional(rollbackFor = Exception.class)
private void executeFlow1() {
//read items from tempTable 1 and persist them in other 2 tables after performing logic
}

@Transactional(rollbackFor = Exception.class)
private void executeFlow2() {
//read items from tempTable 2 and persist them in other 2 tables after performing logic
}

@Transactional(rollbackFor = Exception.class)
private void executeFlow3() {
//read items from tempTable 3 and persist them in other 2 tables after performing logic
}

@Transactional(rollbackFor = Exception.class)
private void executeFlow4() {
//read items from tempTable 4 and persist them in other 2 tables after performing logic
}

This process may take up to two minutes because there are thousands of records involved. If something fails all tables go on rollback. Which is what i want.

The problem occurs when i want to do some dirty reads while this process runs. While the process starts running i try to read from the table of RandomTableObject. At the start of the process i get result but after a few seconds it delays the result until the whole process ends.

It seems while hibernate selects from this table and starts modifying the record a read lock is implemented. Default behavior of hibernate is not to enforce read locks so my next suspect are isolation levels of ms sql server.

According to this documentation of ms sql server: Understanding isolation levels Isolation level Read uncommitted allows dirty reads. I tried to enforce this by adding

@Transactional(rollbackFor = Exception.class , isolation = Isolation.READ_UNCOMMITTED)

above each method but this does not solve the problem. The import is from org.springframework.transactions.annotation.

Has anyone had the same problem with me and if yes is there any solution to this.

nick kladis
  • 450
  • 3
  • 7
  • A dirty read skips the DML share lock on the data in the table. It does not skip the DDL locks needed to maintain the query plan. The shared lock on the database and table can be blocked if another transaction is making changes to the database or table. If you optimize the processing by changing the table (e.g., remove and add an index), you will be blocked. A dirty read can also block. For example, a dirty read can block index maintenance. This can result in a huge blocking chain affecting all clients. – Randy in Marin Jul 10 '22 at 21:58
  • @RandyInMarin Thank you for replying and for the information. Is there any way to read from the table in any way? – nick kladis Jul 11 '22 at 06:22
  • Does the processing include alterations to the tables? The type of schema lock makes a difference. Have you tried doing the dirty read from SSMS to see if that works? – Randy in Marin Jul 11 '22 at 15:56
  • There are no changes on the schema. Only saves and updates. Yes i tried from the ssms also. Nothing. – nick kladis Jul 11 '22 at 22:54
  • 1
    It would be good to verify this is a blocking. You can easily use the activity monitor to check the Processes "Blocked By" and "Head Blocker" columns. There is a Wait Type column. You can get the Session ID by querying @@SPID in your session. – Randy in Marin Jul 12 '22 at 21:01
  • Thank you for the info. I confirmed this is a read lock from the activity monitor which happens by a findByCompletedFalse named query with a graph. I still do now know why this lock occurs. It happens once the named query runs. – nick kladis Jul 13 '22 at 08:57
  • It will help to know what the lock is on. There are several ways to approach it. If you are familiar with setting up a blocking alert or an extended event session, those might be helpful in general. You can also run sp_lock to list locks for a session id. Or look at http://whoisactive.com/ for a handy query to run that will provide information. It's not hard to get the wait resource causing the blocking. It might take a query or two to identify what it is (e.g., translate a KEY resource to a db, table, index, and record). – Randy in Marin Jul 13 '22 at 16:08
  • https://learn.microsoft.com/en-us/troubleshoot/sql/performance/understand-resolve-blocking might be of interest. – Randy in Marin Jul 13 '22 at 16:11
  • After many searches the problem was located on an update query triggered internally by hibernate on object a during execution flow 2. The problem was solved by using a dto to avoid the update query to trigger at the end. It can also be saved with saveAndFlush(). – nick kladis Jul 17 '22 at 21:54

0 Answers0