I have an Keyword
and a KeywordType
as entities. There are lots of keywords of few types.
When trying to persist the second keyword of a type, the unique constraint is violated and the transaction is rolled back.
Searching SO i found several possibilies (some of them from different contexts, so I'm not sure of their validity here) - this post and this post advise catching the Exception which would be of no use to me as I end up where I started and still need to somehow persist the keyword.
Same applies to locking proposed for a different situaltion here
Custom insert statements as proposed in this and this posts wouldn't work proper I guess, since I'm using Oracle and not MySQL and woulnd like to tie the implementation to Hibernate.
A different workaround would be trying to retrieve the type first in the code generating the keywords, and set it on the keyword if found or create a new one if not.
So, what would be the best - most robust, portable (for different databases and persistence providers) and sane approach here?
Thank you.
The involved entities:
public class Keyword {
@Id
@GeneratedValue
private long id;
@Column(name = "VALUE")
private String value;
@ManyToOne
@JoinColumn(name = "TYPE_ID")
private KeywordType type;
...
}
and
@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = { "TYPE" }) })
public class KeywordType {
@Id
@GeneratedValue
private long id;
@Column(name = "TYPE")
private String type;
...
}
Your last solution is the right one, IMO. Search for the keyword type, and if not found, create it.
Catching the exception is not a good option because
Note however that with this technique, you might still have two transactions searching for the same type in parallel, and then try to insert it in parallel. One of the transaction will rollback, but it will be much less frequent.
If you're using EJB 3.1 and you don't mind serializing this operation, a singleton bean using container managed concurrency can solve the problem.
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class KeywordTypeManager
{
@Lock(LockType.WRITE)
public void upsert(KeywordType keywordType)
{
// Only one thread can execute this at a time.
// Your implementation here:
// ...
}
@Inject
private KeywordTypeDao keywordTypeDao;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With