views:

453

answers:

3

Hello... I have a collumn as unique=true.. in Exam class.... I found that because transactions are commited automaticaly so to force the commit i use em.commit()

However i would like to know how to check if it is unique.Running a query isnt a solution because it may be an instert after checking because of the concurency....

Which is the best way to check for uniqness?

List<Exam_Normal> exam_normals = exam.getExam_Normal();
    exam.setExam_Normal(null);

    try {
        em.persist(exam);
        em.flush();

        Long i = 0L;
        if (exam_normals != null) {
            for (Exam_Normal e_n : exam_normals) {
                i++;
                e_n.setItem(i);
                e_n.setId(exam);
                em.persist(e_n);
            }
        }
    } catch (Exception e) {
        System.out.print("sfalma--");
    }
}

d

A: 

However I would like to know how to check if it is unique. Running a query isn't a solution because it may be an insert after checking because of the concurrency....

JPA 2.0 permits pessimistic locking and adds three lock modes for that. This might be an option for your use case.

Some references:

Pascal Thivent
so you mean i should lock and then check if the value exists and then persist and unlock?
Parhs
@Parhs I you want to avoid an exception (and thus to start again because the transaction would be marked for rollback), yes.
Pascal Thivent
A: 

I assume that the column is not a primary key (@Id) in which case your application have to guarantee uniqueness. Guarantee of Uniqueness of the field will probably have to come from elsewhere. What type of value is the field? Here are some ideas

If it is a counter then you can probably use @Singleton stateful bean (JavaEE 6. See this.

If you are using EE5, then a stateless bean with an @Entity that maps to a auto generated key.

Chuk Lee
I am using java ee 6Unluckily it isnt a counter it is a string...It isnt a primary key but it must be unique as bussiness rule.
Parhs
Then you will have to guarantee uniqueness in your application. If I may be inquisitive, what is the nature of the String viz. how is the value generated?
Chuk Lee
How to guarantee it? It is a "name" somehow ... it is generated by user input..
Parhs
If it is like creating a login name, then you will probably have to query
Chuk Lee
how to do it safe? e.g 2 users at the same time use the same String
Parhs
Well I think one of them will probably get an exception. There is nothing much really you can do about it. The problem is you cannot lock the record/entity because your field is not a primary key. You may want to consider adding the name field to make it a composite/compound primary key.
Chuk Lee
What if you have more unique keys?
pihentagy
+2  A: 

Unfortunately with JPA there is no way to avoid a transaction rollback upon a Unique Constraint violation as the specification requires this Exception to mark the transaction for rollback. Also, because the row may not exist when you issue the 'lock' call using JPA 2.0 APIs the 'lock' call will not ensure that only the locking thread can insert the object. A 'lock' would prevent the update of the Entity but not the insert.

You would need to perform the 'persist' as you have in your code but keep it as close to the beginning of the transaction as possible or have the operation occur in its own transaction.

If the 'persist' must be part of a larger transaction and the failure to persist does not preclude this part of your application from succeeding then you should store the Entity instances from this transaction and you will be able to 'merge' them into any subsequent transaction once your application recovers from the rollback.

Gordon Yorke
thank you for the response...So what would you do in my case?Locking doesnt help as you say..exam object has the unique collumn staff.How to catch the error and inform the user that unique violation occured?
Parhs
Ah yes, of course, didn't think about the fact that the row may not exist. Thanks for pointing that out.
Pascal Thivent
It really depends on your application but some things to keep in mind are: If you can isolate the creation of the row to a single transaction or using JPA EntityManager.flush() API cause the row to be inserted at the beginning of the transaction you will save loosing the other changes in the transaction. If you are concerned about loosing the information in the Exam entity you can always keep a reference to the managed Entity. Once the transaction rolls back have the user fix the uniqueness issue in the same instance and merge the same instance into a new EntityManager in a new TXN.
Gordon Yorke
To report the issue to the user simply catch the PersistenceException and check all of the 'causes' until you get to the SQL level. If it is a Unique Constraint violation then report the conflict the user in the UI and instruct them on how to remedy the issue and 'replay' the transaction.
Gordon Yorke