I'm trying to commit JPA manually
var tx = em.getTransaction();
for(var key : aggrFornitore.keySet()){
tx.begin();
try {
var righe = aggrFornitore.get(key);
jpaOperatingOnRepositories(key, righe, mSchede, mSettings);
tx.commit();
} catch (Exception ex){
ex.printStackTrace();
tx.rollback();
}
}
em is:
#PersistenceContext
EntityManager em;
JPA thorws an exception
Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
Is it possible to control JPA transaction manager manually?
Thanks to xerx593 comment I changed my code into
for(var key : aggrFornitore.keySet()){
var txDef = new DefaultTransactionDefinition();
txDef.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_COMMITTED);
TransactionStatus transactionStatus = transactionManager.getTransaction(txDef);
try {
var righe = aggrFornitore.get(key);
creaSingoloOrdine(key, righe, mSchede, mSettings);
transactionManager.commit(transactionStatus);
} catch (Exception ex){
ex.printStackTrace();
transactionManager.rollback(transactionStatus);
}
}
Related
I have an EntityManager associated with my persistence unit (myPU).
I have the following code which represents a generic DataAccessObject which I want to use in order to execute tasks in a new transaction (requires-new).
This DataAccessObject gets injected into an EJB and its unique method gets invoked in a while loop.
Another EntityManager instance referencing the same persistence unit exists in the EJB.
I'm expecting that at every method invocation of my DataAccessObject instance, a new transaction gets created and committed (or rollbacked) according to the following code.
The problem is that i get a transaction required exception. What am i missing?
#Dependent
#ManagedBean
public class DataAccessObject {
private static final Logger logger = Logger.getLogger(DataAccessObject.class);
#PersistenceContext(unitName = "scheduler")
private EntityManager entityManager;
#Transactional(value = TxType.REQUIRES_NEW, rollbackOn = Exception.class)
public void executeInNewTransaction(TransactionalTask transactionalTask) throws TransactionalException {
Throwable exception = null;
try {
logger.debug(" A new transaction has been created for transactional task: \"", transactionalTask, "\".");
transactionalTask.onExecute(entityManager);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
exception = e;
} catch (ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolation = e.getConstraintViolations();
logger.error("Exception during bean validation:");
if (constraintViolation != null) {
for (ConstraintViolation<?> violation : constraintViolation) {
logger.error(String.format("%s=\"%s\" error: %s", violation.getPropertyPath(), violation.getInvalidValue(), violation.getMessage()));
}
}
exception = e;
} catch (Throwable e) {
exception = e;
} finally {
if (exception != null || transactionalTask.mustRollBack()) {
throw new TransactionRolledBackException("Transaction is being rolled back for transactional task: \"" + transactionalTask + "\".", exception);
} else {
logger.debug(" Transaction has been committed successfully for transactional task: \"", transactionalTask, "\".");
}
}
}
}
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?
I've just begun working with JPA and hibernate, and I have been able to insert query and update on one table, but I cannot seem to delete an entity. Even after I attach the entity with the merge function, the program insists it is detached. Here is the relevant code:
public User getUserByEmail(String email) throws DAOException{
User user = null;
EntityManager em = null; //declare here for use in finally block
try{
//get em for use
EntityManagerFactory factory = JPAUtil.getEntityManagerFactory();
em = factory.createEntityManager();
//setup return type as user
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> criteriaQuery = cb.createQuery(User.class);
Root<User> userRoot = criteriaQuery.from(User.class);
//populate the where clause
criteriaQuery.where(cb.equal(userRoot.get("email"), cb.parameter(String.class, "email")));
Query query = em.createQuery(criteriaQuery);
query.setParameter("email", email);
//actually run the query on db
user = (User) query.getSingleResult();
}catch(Exception ex){
DAOException dE = new DAOException(2, "getUserByEmail failed", ex);
//TODO log
throw dE;
}
//cleanup
finally{
if(em != null && em.isOpen()){
em.close();
}
}
return user; //if not found, will still be null
}
#Override
/*
* (non-Javadoc)
* #see dao.IUserDAO#deleteUser(java.lang.String)
*/
public void deleteUser(String email) throws DAOException {
EntityManagerFactory entityManagerFactory;
EntityManager em = null;
EntityTransaction trans = null;
try{
//search user on email
User user = getUserByEmail(email);
//check we found user with specified email
if(user != null){
//setup for interaction with database
entityManagerFactory = JPAUtil.getEntityManagerFactory();
em = entityManagerFactory.createEntityManager();
//alterations of db must occur in scope of transaction
trans = em.getTransaction();
trans.begin();
em.merge(user); //TODO update find to take transaction as parameter
em.remove(user);
trans.commit();
//explicitly flush here
em.flush();
}else{
//TODO we didn't find the user
}
}catch(Exception ex){
DAOException dE = new DAOException(6, "delete failed", ex);
//TODO log
trans.rollback();
throw dE;
}finally{
if(em != null && em.isOpen()){
em.close();
}
}
}
And here is the output from the eclipse console:
"Removing a deattached instance of User#1".
Could someone explain why this bean is still deattached after I explicitly called merge? Also, how would I fix this problem? Thanks.
The content of the specified detached entity object is copied into an
existing managed entity object with the same identity (i.e. same type
and primary key). If the EntityManager does not manage such an entity
object yet a new managed entity object is constructed. The detached
object itself, however, remains unchanged and detached.
Even after merge the detached object itself remains detached, merge will return the new created merged entity
user = em.merge(user); //TODO update find to take transaction as parameter
em.remove(user);
Is there a way to test below code.Here I am connecting to database with JNDI.I am new to mockito and not getting a way to test the same.
#SuppressWarnings("unused")
public Connection getJNDIConnection() {
Connection result = null;
try {
InitialContext initialContext = new InitialContext();
if (initialContext == null) {
LOGGER.info("JNDI problem. Cannot get InitialContext.");
}
DataSource datasource = (DataSource) initialContext.lookup(jndiName);
if (datasource != null) {
result = datasource.getConnection();
} else {
LOGGER.info("Failed to lookup datasource.");
}
} catch (NamingException ex) {
LOGGER.error("Cannot get connection: " + ex);
} catch (SQLException ex) {
LOGGER.error("Cannot get connection: " + ex);
}
return result;
}
Of course, you can to do it, but I think you should read the documentation yourself. The main points here is:
InitialContext initialContext = mock(InitialContext.class);
DataSource dataSource = mock(DataSource.class);
Connection expected = mock(Connection.class);
whenNew(InitialContext.class).withNoArguments().thenReturn(initialContext);
when(initialContext.lookup(jndiName)).thenReturn(dataSource);
when(initialContext.getConnection()).thenReturn(connection);
Connection result = intatnceOfCalss.getJNDIConnection();
assertSame("Should be equals", expected, result);
Also you should use PowerMock to mock constructors and static methods. To have deal with Logger, just add this code:
#BeforeClass
public static void setUpClass() {
mockStatic(LoggerFactory.class);
Logger logger = mock(Logger.class);
when(LoggerFactory.getLogger(ApplySqlFileIfExistsChange.class)).thenReturn(logger);
}
Don't forget about annotations:
#RunWith(PowerMockRunner.class)
#PrepareForTest({LoggerFactory.class})
Try to read this doc http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html
This doesn't work -- I always get the IllegalArgumentException thrown with the advice to "try merging the detached and try the remove again."
#PersistenceContext private EntityManager em;
#Resource private UserTransaction utx;
public void delete(EN entity) {
if (entity == null) return; // null-safe
EN target = entity;
try {
if (!em.contains(entity)) {
System.out.println("delete() entity not managed: " + entity);
utx.begin();
target = em.merge(entity);
utx.commit();
System.out.print("delete() this entity should now be managed: " + em.contains(target));
}
utx.begin();
em.remove(target);
utx.commit();
} catch (RollbackException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (HeuristicMixedException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (HeuristicRollbackException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (IllegalStateException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (NotSupportedException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (SystemException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
}
}
The output log shows the following:
INFO: delete() entity not managed: com.database.SomeTable[ id=2 ]
INFO: delete() this entity should now be managed: false
In other words the merge() does not return a managed entity. Can anyone spot what I did wrong?
Second question: is there a way to do this in one transaction rather than two?
This is with EclipseLink inside GlassFish 3.1.
This snippet of code creates two transactions:
if (!em.contains(entity)) {
System.out.println("delete() entity not managed: " + entity);
utx.begin();
target = em.merge(entity);
utx.commit();
System.out.print("delete() this entity should now be managed: " + em.contains(target));
}
utx.begin();
em.remove(target);
utx.commit();
While it is true that the entity is merged into the persistence context, it is true only of the first transaction, and not for both. In the second transaction, the persistence context associated with the transaction will again find a detached object passed as an argument, in the following line:
em.remove(target);
since, the previous utx.commit() would have detached the reference to target.
To fix this, you must merge the entity into the persistence context, and delete the entity in the same transaction, before the reference is detached:
if (!em.contains(entity)) {
System.out.println("delete() entity not managed: " + entity);
utx.begin();
target = em.merge(entity);
em.remove(target);
utx.commit();
System.out.print("delete() this entity should now be deleted: " + (!em.contains(target)) );
}
After commiting your persistence context should be gone. So your println test after the commit will fail, because the "target" object is not managed anymore.
Do all your stuff within one transaction and it should work. You just have to start your transaction after your "try" begins.