Reputation: 185
I need to delete a list of employees ignoring any integrity constraints (i.e. successfully delete the entity that doesn't related to any others yet or skip the entity that related to others) using JPA 2.0 and EJB3.0 on glassfish3.0:
I iterated on the list and call entity manager in a require_new transaction within a try/catch, I expect this will open small-nested transactions within the big transaction and I use em.flush() to force the updates.
but within iteration of a related entity it throws;
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails
and continue to the next employee but at the commit of the big transaction it rollbacks and throw the same exception!
I expect to throw/catch the exception with in the new-small transaction and commit the successfully deleted entities of the rest of the list...
do I miss anything?
EDIT:
Here is some code, the code in the Facade to call the entity manager to remove the bean, I annotate the function by required-new:
public void deleteEmployeeData(Set<Employees> deleted) throws DatabaseException {
Iterator itr;
Employees emp;
//delete unused recordes
try {
itr = deleted.iterator();
while (itr.hasNext()) {
emp = (Employees) itr.next();
deleteEmployee(emp);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("DONE");
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private void deleteEmployee(Employees emp){
try {
this.remove(emp);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
Upvotes: 0
Views: 2791
Reputation: 185
To call local method and wrap it with new transaction,
@Stateless
public class UserFacade implements UserFacadeLocal {
@Resource
private SessionContext context;
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
private void create(User user) {
System.out.println("Users Count: "+count()); //invocation#1
System.out.println("Users Count Through Context: "+context.getBusinessObject(UserFacadeLocal.class).count()); //invocation#2
}
@Override
@TransactionAttribute(TransactionAttributeType.NEVER)
public int count() {
return ((Long) q.getSingleResult()).intValue();
}
}
EJB Transactions in local method-calls
Upvotes: 1
Reputation: 3176
deleteEmployee
method is not wrapped into a new transaction because you are referencing method on this
. What you can do is to inject reference to the facade itself and then call deleteEmployee
method on it (it should be public).
More or less something like this:
@Stateless
public class MyFacade {
@EJB
private MyFacade self;
public void deleteEmployeeData(Set<Employees> deleted) throws DatabaseException {
...
try {
self.deleteEmployee(emp);
} catch (Exception ex) {
// ...
}
...
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void deleteEmployee(Employees emp) {
this.remove(emp);
}
}
Upvotes: 5
Reputation: 9102
Your problem seems to be the fact that you want to catch the transaction error programmatically within try catch but your transaction propagation is declarative ( using annotation) which usually creates a stack of proxies and handles the transaction failure through them transparently. You need to use programmatic transaction and wrap that up in your exception handling code.
Upvotes: 1