I use Kundera-Cassandra 3.2 and want to use the transaction management from Kundera.
My handling looks like this:
EntityManager manager = repo.getEntityManagerFactory().createEntityManager(CassandraRepository.getProperties());
try{
manager.getTransaction().begin();
this.repo.update(account1, manager); //calls the merge method of the Entitymanager
this.repo.save(account2, manager); //calls the persist method of the Entitymanager
manager.getTransaction().commit();
} catch(Exception e){
if(manager.getTransaction().isActive()){
manager.getTransaction().rollback();
}
} finally {
manager.clear();
manager.close();
}
When an error in the this.repo.save(account2, manager); occurs, the manager rollbacks the transaction, but does not do a update statement, he makes a delete statement for the merge method. The reason for this is, when calling the merge methode, kundera creates an insert statement and not an update. But how to say Kundera to make an update to rollback the transaction also with an update.
Logs:
12:42:41.185 [http-bio-8080-exec-3] INFO com.impetus.client.cassandra.CassandraClientBase - Returning delete query DELETE FROM "account" WHERE "id" = 'MCSP-000000000004'.
12:42:41.211 [http-bio-8080-exec-3] INFO com.impetus.client.cassandra.CassandraClientBase - Returning delete query DELETE FROM "account" WHERE "id" = 'MCSP-000000000005'.
EDIT (my repository):
public class CassandraRepository<T> {
#PersistenceUnit
private EntityManagerFactory entityManagerFactory;
public static Map<String, String> getProperties() {
final Map<String, String> properties = new HashMap<String, String>();
properties.put(CassandraConstants.CQL_VERSION, CassandraConstants.CQL_VERSION_3_0);
return properties;
}
public void update(T entity, EntityManager manager) throws Exception{
try {
manager.merge(entity);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
public void save(T entity, EntityManager manager) throws Exception{
try {
manager.persist(entity);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
According to JPA, to update an entity you have to first bring it into managed state (by fetching it)
Example:-
PersonCassandra p = entityManager.find(PersonCassandra.class, "2");
entityManager.getTransaction().begin();
p.setMonth(Month.JAN);
entityManager.merge(p);
entityManager.persist(p3);
entityManager.getTransaction().commit();
Issue is not with INSERT and UPDATE statements since both are similar for Cassandra, under the hood.
Related
I am unable to catch ConstraintViolationException
public BigDecimal createSubBoard(SubBoard subBoardObj, Users user) {
EntityManager em = EMFUtility.getEntityManager();
EntityTransaction et = null;
SubBoards subBoard = null;
SubBoard subBoards = null;
Boards board = null;
BigDecimal subBoardId = new BigDecimal(0);
try {
logger.debug(" #### BoardsDao - createSubBoard"+subBoardObj.toString());
et = em.getTransaction();
et.begin();
try{
subBoardObj.setCreateDate(new Date());
subBoardObj.setCreatedBy(user.getEdipi());
em.persist(subBoardObj);
subBoardId = subBoardObj.getId();
et.commit();
} catch(EJBTransactionRolledbackException ce) {
System.out.println("!!!");
Throwable t = ce.getCause();
while ((t != null) && !(t instanceof ConstraintViolationException)) {
t = t.getCause();
}
if (t instanceof ConstraintViolationException) {
System.out.println("...........");
// Check here if the delete date is also null
}
}
///TODO..///
} catch (Exception e) {
et.rollback();
e.printStackTrace();
System.out.println("!!!! "+e.getCause() );
logger.debug(" #### BoardsDao - createSubBoard :Exception is " + e.getMessage());
throw new PersistenceException("Error persisting entity in createSubBoard "+ e.getMessage());
} finally {
em.close();
}
return subBoardId;
}
in this code em.persist(subBoardObj); throws ConstraintViolationException. I tried using getCause() and identify if constraintViolation but the code control doesnt goto that catch block. It goes to generic Exception block. Can someone suggest whats wrong.
First of all, I would not recommend doing transaction handling manually but instead use declarative transaction management. If you use EJBs, you just need to annotate the bean as #Stateless or if you want to change the transaction demacration strategy use the #TransactionAttribute annotation on the method. If you really must use manual transaction management you should use the UserTransaction interface. This is because EJB works with the JTA specification which you probably also configured as transaction strategy in your persistence unit.
Having said that, EntityManager.persist and EntityManager.flush throw javax.persistence.PersistenceException that wrap a org.hibernate.exception.ConstraintViolationException. So you need to catch the PersistenceException and then use getCause to get the constraint violation.
I have SpringBoot application which uses hibernate to communicate with database. Flow of application is
read xml -> extract entities from xml -> load entities to database. Some of theese entities are not valid so i would like to just skip them. Im using following code
public <T extends BaseEntity> long bulkInsert(Collection<T> entities) {
long count = 0;
try {
for (T t : entities) {
if (t.getId() == null) {
entityManager.merge(t);
count++;
}
if (count > 0 && count % 1000 == 0) {
log.debug("Zapisano {}. Przeslanie do bazy.", count);
entityManager.flush();
entityManager.clear();
}
}
entityManager.flush();
entityManager.clear();
} catch (Exception e) {
for (T ent: entities) {
entityManager.remove(ent);
}
for (T ent: entities) {
try{
entityManager.merge(ent);
entityManager.flush();
entityManager.clear();
} catch (Exception ex){
entityManager.remove(ent);
}
}
}
return count;
}
But i alwaysget errorrs in first catch block. Right now i get
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not prepare statement
in line where i try to merge. I also tried persisting again but it generated different error - detached entity passed to persist. Maybe my approach is completely wrong (i`m new with hibernate). What is right way to do this?
It's because your entity have Persist state. Just read more about Entity Manager in Hibernate. Example of diagram: https://www.baeldung.com/wp-content/uploads/2016/07/2016-07-11_13-38-11-1024x551.png
I want to log the time taken by the JPA repository to save the data into the database.
Currently, I have used the Spring around Aspect to log it but it seems not so accurate because it doesn't commit until the end of #Transactional method.
#Timed(metricName = "inmtPersistence")
public void persistInmt(final List<T> inmtList) {
if (inmtList.size() == 0) {
return;
}
Map<String, E> inmtEntityMapFromDb = getInmtEntitiesFromDb(inmtList);
List<E> inmtEntities = getInmtEntities(inmtList, inmtEntityMapFromDb);
try {
inmtRepository.saveAll(inmtEntities);
} catch (Exception e) {
log.error("Exception ");
throw e;
}
}
You could use P6Spy , which will log out execution time for all individual queries.
I have got a problem with transaction rollback.
I need to first insert a user into the database, and then insert into another table some kind of log of who inserted the user.
If there is an exception when inserting this log-message, the whole transaction should be rolled back (i.e. user needs to be removed again).
The .ear is deployed on Wildfly 8.1, persistence is achieved through Hibernate with MySQL.
My class looks like this
#Stateless
#Remote(AdministratorBiznesowyService.class)
#Transactional(rollbackOn = Exception.class)
public class AdministratorBiznesowyServiceBean implements AdministratorBiznesowyService {
The method looks like this
#Override
#Transactional(rollbackOn = Exception.class)
public void insertUser(String userSessionId, User user) throws AdministratorBiznesowyException {
checkPermission(userSessionId);
try {
userBusiness.insertUser(user);
log.insertLog(
authenticationObjectBusiness.getUserIdForSessionId(userSessionId),
LogEnum.CREATE, user);
} catch (AuthenticationException e) {
ServerLogModule.logActionError(Messages
.getErrorMessage("server.authorization.noPermission"));
throw new AdministratorBiznesowyException();
} catch (Exception e1) {
ServerLogModule.logActionError(Messages
.getErrorMessage("server.exception"));
throw new AdministratorBiznesowyException();
}*/
}
The insertUser implementation in userBusiness:
#Override
public void insertUser(User user) throws AdministratorBiznesowyException {
try {
UserEntity userEntity = adminConvertUtils.convertUserToEntity(user);
userEntityFacade.create(userEntity);
} catch (Exception e) {
throw new AdministratorBiznesowyException();
}
}
And my log.insertLog currently for test-purposes just throws an exception.
throw new LogException();
and its implementation is like this:
#ApplicationException(rollback=true)
public class LogException extends RuntimeException {
AdministratorBiznesowyException:
#ApplicationException(rollback = true)
public class AdministratorBiznesowyException extends CommunicationException {
CommunicationException:
public class CommunicationException extends Exception {
So now, when I successfully call insertUser and directly after that get an exception, the new user still gets added to the database (I check through MySQL Workbench).
What else can I do to get this to rollback?
If any other code is needed, please comment, thank you in advance.
Now I am using jpa with hibernate , when i was done getEntityManager.persist(objects) then i will ask for user confirmation like continue and rollback using user interface
private List<TempCustomers> tempCustomer =new ArrayList<TempCustomers>();
#Begin(join = true)
public String migrateData() {
log.info("Mobee Migrate Customer Size :"+doTempCustomers.size());
for(DoTempCustomers tempCustomers:doTempCustomers){
try {
TempCustomers temp=new TempCustomers();
BeanUtils.copyProperties(temp, tempCustomers);
tempCustomer.add(temp);
getEntityManager().persist(temp);
}catch (Exception e) {
// TODO: handle exception
return "null";
}
}
log.info("Size........."+tempCustomer.size());
return "null";
}
#Begin(join = true)
public String updatedData(){
log.info("Size of Customers :"+tempCustomer.size());
log.info("Decision ..."+decision);
try{
if(decision.equals("Continue")){
for(TempCustomers tempCust:tempCustomer){
TempCustomers temp=new TempCustomers();
BeanUtils.copyProperties(temp, tempCust);
log.info("updated Sucessfully");
getEntityManager().getTransaction().commit();
}}else{
getEntityManager().getTransaction().rollback();
}
}
catch(Exception e){
}
}
please help me how to do continue and rollback in jpa with hibernate when getEntityManager().persist() is done.
To commit with JPA:
entityManager.getTransaction().commit();
To rollback with JPA:
entityManager.getTransaction().rollback();
Call either of these methods after your call to persist to perform the desired action. In your case entityManager would be replaced with the call to retrieve the entityManager, getEntityManager()
Reference: http://www.objectdb.com/java/jpa/persistence/store