No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call, Exception - jpa

Have a list of data need to be saved. Before the save had to delete the existing data and save the new data.
If any of the delete & save is failed that transaction need to roll back, rest of the delete & save transaction should continue.
public LabResResponse saveLabResult(List<LabResInvstResultDto> invstResults) {
LabResResponse labResResponse = new LabResResponse();
List<Long> relInvstid = new ArrayList<Long>();
try{
if(invstResults != null){
List<LabResInvstResult> labResInvstResults = mapper.mapAsList(invstResults, LabResInvstResult.class);
for(LabResInvstResult dto: labResInvstResults){
if(dto != null){
//delete all child records before save.
deleteResult(dto, relInvstid);
}
}
}
labResResponse.setRelInvstids(relInvstid);
}catch(Exception e){
e.printStackTrace();
}
return labResResponse;
}
Here new transaction will added for each delete & save
#Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = { Exception.class })
private void deleteResult(LabResInvstResult dto, List<Long> relInvstid) {
try{
labResultRepo.deleteById(dto.getId());
LabResInvstResult result = labResultRepo.save(dto);
}catch(Exception e){
e.printStackTrace();
}
}
On delete it throws an exception "Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call"
I can solve this by adding a #Transactional for public LabResResponse saveLabResult(List invstResults) method.
But my intial usecase will not work this will roll back entire list of transaction.

Here are two problems.
The first problem is that you call the "real" deleteResult method of the class. When Spring sees #Transactional it creates a proxy object with transactional behavior. Unless you're using AspectJ it won't change the class itself but create a new one, proxy. So when you autowire this bean you will be able use proxy's method that runs transaction related logic. But in your case you're referencing to the method of the class, not proxy.
The second problem is that Spring (again if AspectJ is not used) can't proxy non-public methods.
Summary: make the deleteResult method public somehow and use proxied one. As a suggestion, use another component with deleteResult there.

You are catching exception out of for loop, while your requirement says you want to continue the loop for other objects in list.
Put your try/catch block with-in loop. It should work fine
public LabResResponse saveLabResult(List<LabResInvstResultDto> invstResults) {
LabResResponse labResResponse = new LabResResponse();
List<Long> relInvstid = new ArrayList<Long>();
try{
if(invstResults != null){
List<LabResInvstResult> labResInvstResults = mapper.mapAsList(invstResults, LabResInvstResult.class);
for(LabResInvstResult dto: labResInvstResults){
if(dto != null){
//delete all child records before save.
try {
deleteResult(dto, relInvstid);
} catch(Exception e){
e.printStackTrace();
}
}
}
}
labResResponse.setRelInvstids(relInvstid);
}catch(Exception e){
e.printStackTrace();
}
return labResResponse;
}

Related

#Transactional with handling error and db-inserts in catch block (Spring Boot)

I would like to rollback a transaction for the data in case of errors and at the same time write the error to db.
I can't manage to do with Transactional Annotations.
Following code produces a runtime-error (1/0) and still writes the data into the db. And also writes the data into the error table.
I tried several variations and followed similar questions in StackOverflow but I didn't succeed to do.
Anyone has a hint, how to do?
#Service
public class MyService{
#Transactional(rollbackFor = Exception.class)
public void updateData() {
try{
processAndPersist(); // <- db operation with inserts
int i = 1/0; // <- Runtime error
}catch (Exception e){
persistError()
trackReportError(filename, e.getMessage());
}
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void persistError(String message) {
persistError2Db(message); // <- db operation with insert
}
You need the way to throw an exception in updateData() method to rollback a transaction. And you need to not rollback persistError() transaction at the same time.
#Transactional(rollbackFor = Exception.class)
public void updateData() {
try{
processAndPersist(); // <- db operation with inserts
int i = 1/0; // <- Runtime error
}catch (Exception e){
persistError()
trackReportError(filename, e.getMessage());
throw ex; // if throw error here, will not work
}
}
Just throwing an error will not help because persistError() will have the same transaction as updateData() has. Because persistError() is called using this reference, not a reference to a proxy.
Options to solve
Using self reference.
Using self injection Spring self injection for transactions
Move the call of persistError() outside updateData() (and transaction). Remove #Transactional from persistError() (it will not work) and use transaction of Repository in persistError2Db().
Move persistError() to a separate serface. It will be called using a proxy in this case.
Don't use declarative transactions (with #Transactional annotation). Use Programmatic transaction management to set transaction boundaries manually https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch11s06.html
Also keep in mind that persistError() can produce error too (and with high probability will do it).
Using self reference
You can use self reference to MyService to have a transaction, because you will be able to call not a method of MyServiceImpl, but a method of Spring proxy.
#Service
public class MyServiceImpl implements MyService {
public void doWork(MyService self) {
DataEntity data = loadData();
try {
self.updateData(data);
} catch (Exception ex) {
log.error("Error for dataId={}", data.getId(), ex);
self.persistError("Error");
trackReportError(filename, ex);
}
}
#Transactional
public void updateData(DataEntity data) {
persist(data); // <- db operation with inserts
}
#Transactional
public void persistError(String message) {
try {
persistError2Db(message); // <- db operation with insert
} catch (Exception ex) {
log.error("Error for message={}", message, ex);
}
}
}
public interface MyService {
void doWork(MyService self);
void updateData(DataEntity data);
void persistError(String message);
}
To use
MyService service = ...;
service.doWork(service);

roll back all inserts if an exception occured

i am trying to persist multiple entities to database. but i need to roll back all inserts if one of them faces an exception. how can i do that?
here is what i did:
public class RoleCreationApplyService extends AbstractEntityProxy implements EntityProxy {
#Inject
#Override
public void setEntityManager(EntityManager em) {
super.entityManager = em;
}
#Resource
UserTransaction utx;
public Object acceptAppliedRole(String applyId, Role parentRole, SecurityContext securityContext) throws Exception {
utx.begin();
try {
FilterWrapper filter = FilterWrapper.createWrapperWithFilter("id", Filter.Operator._EQUAL, applyId);
RoleCreationApply roleCreationApply = (RoleCreationApply) getByFilter(RoleCreationApply.class, filter);
Role appliedRole = new Role();
appliedRole.setRoleUniqueName(roleCreationApply.getRoleName());
appliedRole.setRoleName(roleCreationApply.getRoleName());
appliedRole.setRoleDescription(roleCreationApply.getRoleDescription());
appliedRole.setRoleDisplayName(roleCreationApply.getRoleDisplayName());
appliedRole.setCreationTime(new Date());
appliedRole.setCreatedBy(securityContext.getUserPrincipal().getName());
Role childRole = (Role) save(appliedRole);
parentRole.setCreationTime(new Date());
parentRole.setCreatedBy(securityContext.getUserPrincipal().getName());
parentRole = (Role) save(parentRole);
RoleRelation roleRelation = new RoleRelation();
roleRelation.setParentRole(parentRole);
roleRelation.setChildRole(childRole);
RoleRelation savedRoleRelation = (RoleRelation) save(roleRelation);
PostRoleRelation postRoleRelation = new PostRoleRelation();
postRoleRelation.setPost(roleCreationApply.getPost());
postRoleRelation.setRoleRelation(savedRoleRelation);
ir.tamin.framework.domain.Resource result = save(postRoleRelation);
utx.commit();
return result;
} catch (Exception e) {
utx.rollback();
throw new Exception(e.getMessage());
}
}
}
and this is save method in AbstractEntityProxy class:
#Override
#ProxyMethod
public Resource save(Resource clientObject) throws ProxyProcessingException {
checkRelationShips((Entity) clientObject, Method.SAVE, OneToOne.class, ManyToOne.class);
try {
entityManager.persist(clientObject);
} catch (PersistenceException e) {
throw new ResourceAlreadyExistsException(e);
}
return clientObject;
}
but when an exception occures for example Unique Constraint Violated and it goes to catch block, when trying to execute utx.rollback() it complains transaction does not exist and so some entities will persist. but i want all to roll back if one fails.
PS: i don't want to use plain JDBC. what is JPA approach?

org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions

I am working rest services with spring and hibernate,for updating employee data using below code, but when run I got below error
{
"code": 0,
"message": "org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions"
}
DataDaoImpl.java
#Override
public Employee getEntityById(long id) throws Exception {
session = sessionFactory.openSession();
Employee employee = (Employee) session.load(Employee.class,
new Long(id));
tx = session.getTransaction();
session.beginTransaction();
tx.commit();
return employee;
}
RestController.jav
#RequestMapping(value = "/save/{id}", method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
Status saveUser(#PathVariable("id") long id,#RequestBody Employee employee) {
Employee employeeupdate = null;
try {
employeeupdate = dataServices.getEntityById(id);
employeeupdate.setFirstName(employee.getFirstName());
employeeupdate.setLastName(employee.getLastName());
employeeupdate.setEmail(employee.getEmail());
employeeupdate.setPhone(employee.getPhone());
dataServices.updateEntity(employeeupdate);
return new Status(1, "Employee updated Successfully !");
} catch (Exception e) {
// e.printStackTrace();
return new Status(0, e.toString());
}
}
#Override
public boolean updateEntity(Employee employeeupdate) throws Exception {
session = sessionFactory.openSession();
tx = session.beginTransaction();
session.update(employeeupdate);
tx.commit();
session.close();
return false;
}
What mistake have I done here?
In the getEntityById(...) method the session is not closed. Close the session using session.close(); before returning the employee and try.
Don't open 2 sessions. Open just one and use it.
place the
session = sessionFactory.openSession();
tx = session.beginTransaction();
In the beginning of saveUser() and pass the session/transaction to the methods. Actually you don't need transaction in the getEntityById() - you change nothing.
Appart of #StanislavL answer, there are some errors in your code getEntityById() should be (you need close a session and place a transaction above load()).
#Override
public Employee getEntityById(long id) throws Exception {
session = sessionFactory.openSession();
tx = session.getTransaction();
session.beginTransaction();
Employee employee = (Employee) session.load(Employee.class,
new Long(id));
tx.commit();
session.close();
return employee;
}
But this variant is not very correct too, you should catch an exception use a finally block and rollback a transaction. The best way is using this pattern doInTransaction().
Update
It is better to get an entity this way
Employee employee = (Employee) session.get(Employee.class, id);
In short, you should not create session in your DAO.
Given that you are using Spring, you should avoid manually creating the Session/Transaction. Please make use of Spring to manage the transaction and session creation, by relying on Spring's transaction control and things like LocalEntityManagerFactoryBean

JPA #OneToMany not persisting/cascading

I have the following code in UserController in my Session Scoped Bean
public void addItemToBundle(ItemEntity item){
//System.out.println(item.getTitle());
try {
em.getTransaction().begin();
UserEntity user = em.find(UserEntity.class, this.username);
BundleEntity bundle = new BundleEntity();
BundleEntityPK compositePk = new BundleEntityPK();
compositePk.setCheckedOutDate(new Date());
compositePk.setItemId(item.getItemId());
compositePk.setUsername(user.getUsername());
bundle.setId(compositePk);
Set<BundleEntity> bundles = new HashSet<BundleEntity>();
bundles.add(bundle);
user.setBundleEntities(bundles);
em.persist(user);
em.flush();
em.getTransaction().commit();
} finally {
}
}
public String addToBundle(){
try {
addItemToBundle(item);
} catch (NullPointerException e) {
e.getMessage();
}
return null;
}
This code uses private ItemEntity item; which gets passed in by the following JSF markup:
<p:commandLink action="#{itemController.item}">
<f:setPropertyActionListener target="#{itemController.selectedItem}" value="#{movie}" />
</p:commandLink>
(I'm using PrimeFaces in this example) The problem is that the addItemToBundle is not calling any SQL code in the console (I have FINE enabled) and the bundle never gets created or added to the user. I also tried em.persist(user) and em.flush() and setting cascadeType in my UserEntity with no luck.
#OneToMany(mappedBy="userEntity",cascade=CascadeType.PERSIST)
private Set<BundleEntity> bundleEntities;
Thanks!
You know that this:
try {
addItemToBundle(item);
} catch (NullPointerException e) {
e.getMessage();
}
is very bad practice, right? Maybe, that's the problem here, you run into a NPE and never notice it.
You should at least log the exception to know what's going on there (just for demo purposes, I've used stdout, please replace with your favorite logging framework):
try {
addItemToBundle(item);
} catch (NullPointerException e) {
System.err.println(e.getMessage()); //use logger here
}

EJJB Timer Transaction -XA Exception

I am using EJB 3.0 timer.When my Timeout method gets invoked,I use JPA to insert a record in one of the table.I use JPA to persist the data.I defined the persist code in a Stateless Session Bean and invoked the local interface inside my timeout method.I get the following exception when the thread comes out of the timeout method:
javax.transaction.xa.XAException: JDBC driver does not support XA, hence cannot be a participant in two-phase commit.
To force this participation, set the GlobalTransactionsProtocol attribute to LoggingLastResource (recommended) or EmulateTwoPhaseCommit for the Data Source
Our DB does not support XA transaction.We use WL 10.3.1.Here is the code which i do :
#EJB
private MyejbLocal myejbLocal
#Timeout
public void callEjb(timer) {
try {
myejbLocal .store();
} catch (EntityExistsException e) {
e.getMessage();
} catch (Exception ex) {
ex.getCause();
}
}
Here is my implementation:
#Override
public void Store() {
try {
Mytable mytable= new Mytable (new Date());
persist(mytable);
} catch (EntityExistsException e) {
e.getMessage();
} catch (Exception ex) {
ex.getCause();
}
}
I don't call flush() method.
Please let me know if I have missed any?
I also faced the same issue. You need to keep your JPA entity operation in a separate session bean and it will work.
http://prasunejohn.blogspot.in/2014/02/understanding-ejb-timer-service-31.html