Question

I'm getting java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint error while running oracle function using mybatis. I configured spring transaction to run in Serializable with readOnly false. Below is the my mapper class

public interface ILockMapper {

    @Transactional(isolation=Isolation.SERIALIZABLE, readOnly=false)
    String aquireLock(final SpInOutFields input);

    @Transactional(isolation=Isolation.SERIALIZABLE, readOnly=false)
    String releaseLock(final SpInOutFields input);

}

My aquireLock method runs my oracle function, The oracle function has two insert statements. before inserting the data I check for whether the data is present or not using select count(*) for the given data. if present I would not insert the data the sample pl sql statement is here below

SELECT COUNT(*) INTO rowcount FROM kp_lock WHERE device_id = deviceId; 


   if rowcount = 0 then
      INSERT INTO kp_lock(device_id,lock_flag,request_time) values ( deviceId, 'YES', CURRENT_TIMESTAMP);
  status := threadSysId;
   else
  status := '';
   end if;

When I run the function from oracle it works fine. And it works fine when I run a single thread but fails when I run multi threaded.

My JUNIT test class is below,

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"classpath:config/spring-context.xml"})
    public class TestSerialization {

        @Autowired
        ApplicationContext context;

        @Test
        public void testSerialize() throws InterruptedException{

            MultiThread multithread = context.getBean(MultiThread.class);
            MultiThread multithread1 = context.getBean(MultiThread.class);

            Thread thread = new Thread(multithread);
            Thread thread1 = new Thread(multithread1);

            thread.start();

            if(multithread == multithread1){
                System.out.println("Both refer same instance");
            }

            thread1.start();

try {
                thread.join();
                thread1.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

Could some please help me to configure transaction to run in synchronous way. Not sure where I'm going wrong

Was it helpful?

Solution

The problem is with non-atomicity of the function which leads to race condition. In multi-threaded environment some other thread may be executed between check if record exists and insert happens.

You cannot resolve this problem solely by transaction configuration. What you need to do is to insert conditionally.

It looks like you are trying to implement custom locks. Consider using User Defined Locks

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top