1

I'm developing a spring mvc webapp with spring data and hibernate.

I've an entity composed by a boolean field and by an Integer field.

At beginning the boolean field is false and Integer field is null.

When boolean field become true I need to assign to the Integer field a unique value equals to MAX(seq) +1

To do it, I write my service method in this way:

@Override public synchronized Obj save(Obj entry) { if (entry.getBool() && entry.getSeq() == null){ Integer seq = objRepository.getLastSeq(); if (seq == null){ seq = 1; } entry.setSeq(seq); } return entry.save(entry); } 

And in my Reposiroty:

@Query("select MAX(seq)+1 FROM Obj") Integer getLastSeq(); 

I put synchronized keyword to service method in order to be sure that only a thread at a time can get an unique MAX+1 number.. but I'm not sure if it works in all situation and if it is the right way.

Can I be sure that it guarantee unicity of seq?

Thank you Marco

5
  • Only UK to seq column will guarantee you unicity. Commented Mar 21, 2013 at 8:34
  • I cannot set it UK because some entity must have integer value null. Integer become not null only when boolean become true! Commented Mar 21, 2013 at 8:37
  • Ok, can user explicity call obj.setSeq()? Commented Mar 21, 2013 at 8:46
  • No.. it is passed to and from the view with an input type hidden.. Commented Mar 21, 2013 at 8:52
  • 1
    Syncronizing at the method is basically syncronizing on "this", which in your case is the service class. Although I usually prefer not to do that, what you are essentially doing is saying that only one thread will execute that method for each instance of your service class. If you are guaranteed only one copy of the service class exists, then I believe you are OK. However, if you have multiple application servers, each with its own copy, or you are creating multiple references to your service object, then you are not. Commented Mar 21, 2013 at 12:20

2 Answers 2

2

It seems like your Integer is entry id or isn't it ? So why not to use database sequence, with @id adnotation for example :

@Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; 
Sign up to request clarification or add additional context in comments.

6 Comments

No.. it isn't the entity id. Is an integer given only to the entity for which the boolean propery become true. To be more rehalistic this entity represent an Exam.. I give a sequence number only when I successfully pass the Exam! Thank you for your answer
So check this workaround in answer to this question.
Meybe better soultion is to add initialazingbean interface to your service and check max sequence number in table and then use AtomicInteger in your save method. Every time you want next integer you query database witch is not optimal solution.
It is one of solutions that I've thinked about after post this question! But before I will try to find something less intricate.
Can you tell me where I can find an example or something about your comment?
|
1

Example how to use initializing bean for that purpose.

@Service public class SequenceInitializer implements InitializingBean{ @Autowired private ObjRepository objRepository; @Autowired private Service service; @Override public void afterPropertiesSet() throws Exception { try { Integer max = objRepository.getLastSeq(); service.setLastSeq(max); } catch(Exception e){...} } 

In your service setLastSeq will set AtomicInteger field.

2 Comments

I don't understand if this method could be useful in my case. Could it work if in a firts attempt I create the entity and save it with boolean false (so integer is null). Then I update the entity setting boolean true (so integer = maxValue +1)?
So lets be clear. You want to have a field which has naxt integer value on save if some condition is true. In your solution every time you save entity you make additional query to database(It is not good idea). In solution above You make that query only once on application started and write max value to AtomicInteger field in your service. Now when next time you invoke save method you could get next integer value from atiomicInteger..getAndIncrement(). That solution is much faster and synchronized block is out.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.