0

I have a student table in DB which has name, subject and marks fields in it. 1 student can have multiple records for different subjects in this table.

I have a student DAO class which has an update method like this:

public marks updateStudent(String name, String subject, int marks){
//this method first check if the record of this name and subject is there in DB
    if(getStudentRecordFromDB(name, subject){
        //then return marks for this student

    }else{
        //insert the record in DB and return marks
        insertRecord(name, subject, marks);

    }

}

This method can be called by multiple threads simultaneously for same student name and subject. I want to make it synchronized only in case of multiple threads updating same name and subject. So I thought on synchronizing this method on string of name+subject but as this is a bad practice also not giving me guranteed results due to string constant pool (presence of that string in it), I want to use some better solution. I don't want to synchronize on DAO.class as I want synchronization only in case of same records update. What should be the best way to do this?

Ishan Rastogi
  • 808
  • 2
  • 8
  • 17
  • you should not need to synchronize DB updates - why do you want to do it? – Scary Wombat Jun 01 '16 at 05:24
  • There is no restriction at DB side to insert multiple records for same name and subject. And unfortunately I can't change anything in DB. So I have to synchronize it in my java service only. I know it might be a bad design but I can't help it and I want a solution to make it work from java code only. – Ishan Rastogi Jun 01 '16 at 05:29
  • 4
    You want to use database transactions here, and you want to lock the record for updating in the `getStudentRecordFromDB` method (or use optimistic locking). While technically possible to synchronize on a String (use the `String.intern` method before synchronizing to get a unique instance) it doesn't protect you against another application operating on the same database, or against a cluster deployment where several instances of your application are running. – Erwin Bolwidt Jun 01 '16 at 05:32
  • Thanks @ErwinBolwidt, I will try to put optimistic locking. I have tried String.intern too but somehow that doesn't work all the time. I have seen that sometimes threads with same name/subject don't lock each other. – Ishan Rastogi Jun 01 '16 at 05:44

1 Answers1

1

This method can be called by multiple threads simultaneously for same student name and subject.

One way to do this would be to create a unique restriction on your database that will throw an exception if the database already has the student-name/subject combination. So you would:

  1. query for the student-name/subject
  2. if it didn't exist, try to insert it in the database
  3. if that fails then do the query again to protect against the race condition.
  4. if it still doesn't exist then throw the database exception

You could do this with synchronization although it is non trivial. You could do something like:

  1. Create a object that wraps the student-name/subject where the hashcode() and equals() use those fields.
  2. Use a ConcurrentHashMap and putIfAbsent(...) your StudentNameSubject whenever you go to do your operation. The value can just be some random constant object since you can't use null and there is no ConcurrentHashSet.
  3. Synchronize then on either the StudentNameSubject you created or the one from the map if it already exists.
  4. Do your database operations inside the synchronized block.
  5. You can delete the entry from the map after you complete the synchronized block.
Gray
  • 115,027
  • 24
  • 293
  • 354