catch ConstraintViolationException - doesnt work - java

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.

Related

why jpa not save data at a time

i want save data and check the data after call save method
but the value is not present in same request
i have two method depend each other
the two function communcation with each other by kafka
the first method save the data and after save using jpa call second method
find the recourd from database using jpa
and check the instanse using isPresent()
but in the second method i cant find the data save
but after this request i can find data
return exciption NoSuchElement
Try out several ways like:
1-use flush and saveAndFlush
2-sleep method 10000 milsec
3-use entityManger with #Transactional
but all of them not correct
i want showing you my two method from code:
i have producer and consumer
and this is SaveOrder method (first method):
note : where in the first method have all ways i used
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void saveOrder(Long branchId,AscOrderDTO ascOrderDTO) throws Exception {
ascOrderDTO.validation();
if (ascOrderDTO.getId() == null) {
ascOrderDTO.setCreationDate(Instant.now());
ascOrderDTO.setCreatedBy(SecurityUtils.getCurrentUserLogin().get());
//add user
ascOrderDTO.setStoreId(null);
String currentUser=SecurityUtils.getCurrentUserLogin().get();
AppUser appUser=appUserRepository.findByLogin(currentUser);
ascOrderDTO.setAppUserId(appUser.getId());
}
log.debug("Request to save AscOrder : {}", ascOrderDTO);
AscOrder ascOrder = ascOrderMapper.toEntity(ascOrderDTO);
//send notify to branch
if(!branchService.orderOk())
{
throw new BadRequestAlertException("branch not accept order", "check order with branch", "branch");
}
ascOrder = ascOrderRepository.save(ascOrder);
/*
* log.debug("start sleep"); Thread.sleep(10000); log.debug("end sleep");
*/
entityManager.setFlushMode(FlushModeType.AUTO);
entityManager.flush();
entityManager.clear();
//ascOrderRepository.flush();
try {
producerOrder.addOrder(branchId,ascOrder.getId(),true);
stateMachineHandler.stateMachine(OrderEvent.EMPTY, ascOrder.getId());
stateMachineHandler.handling(ascOrder.getId());
//return ascOrderMapper.toDto(ascOrder);
}
catch (Exception e) {
// TODO: handle exception
ascOrderRepository.delete(ascOrder);
throw new BadRequestAlertException("cannot deliver order to Branch", "try agine", "Try!");
}
}
in this code go to producer :
producerOrder.addOrder(branchId,ascOrder.getId(),true);
and this is my producer:
public void addOrder(Long branchId, Long orderId, Boolean isAccept) throws Exception {
ObjectMapper obj = new ObjectMapper();
try {
Map<String, String> map = new HashMap<>();
map.put("branchId", branchId.toString());
map.put("orderId", orderId.toString());
map.put("isAccept", isAccept.toString());
kafkaTemplate.send("orderone", obj.writeValueAsString(map));
}
catch (Exception e) {
throw new Exception(e.getMessage());
}
}
and in this code go to consumer:
kafkaTemplate.send("orderone", obj.writeValueAsString(map));
this is my consumer:
#KafkaListener(topics = "orderone", groupId = "groupId")
public void processAddOrder(String mapping) throws Exception {
try {
log.debug("i am in consumer add Order");
ObjectMapper mapper = new ObjectMapper(); Map<String, String> result = mapper.readValue(mapping,
HashMap.class);
branchService.acceptOrder(Long.parseLong(result.get("branchId")),Long.parseLong(result.get("orderId")),
Boolean.parseBoolean(result.get("isAccept")));
log.debug(result.toString());
}
catch (Exception e) {
throw new Exception(e.getMessage());
}
}
**and this code go to AcceptOrder (second method) : **
branchService.acceptOrder(Long.parseLong(result.get("branchId")),Long.parseLong(result.get("orderId")),
Boolean.parseBoolean(result.get("isAccept")));
this is my second method :
public AscOrderDTO acceptOrder(Long branchId, Long orderId, boolean acceptable) throws Exception {
ascOrderRepository.flush();
try {
if (branchId == null || orderId == null || !acceptable) {
throw new BadRequestAlertException("URl invalid query", "URL", "Check your Input");
}
if (!branchRepository.findById(branchId).isPresent() || !ascOrderRepository.findById(orderId).isPresent()) {
throw new BadRequestAlertException("cannot find branch or Order", "URL", "Check your Input");
}
/*
* if (acceptable) { ascOrder.setStatus(OrderStatus.PREPARING); } else {
* ascOrder.setStatus(OrderStatus.PENDING); }
*/
Branch branch = branchRepository.findById(branchId).get();
AscOrder ascOrder = ascOrderRepository.findById(orderId).get();
ascOrder.setDiscount(50.0);
branch.addOrders(ascOrder);
branchRepository.save(branch);
log.debug("///////////////////////////////Add order sucess////////////////////////////////////////////////");
return ascOrderMapper.toDto(ascOrder);
} catch (Exception e) {
// TODO: handle exception
throw new Exception(e.getMessage());
}
}
Adding Thread.sleep() inside saveOrder makes no sense.
processAddOrder executes on a completely different thread, with a completely different persistence context. All the while, your transaction from saveOrder might still be ongoing, with none of the changes made visible to other transactions.
Try splitting saveOrder into a transactional method and sending the notification, making sure that the transaction ends before the event handling has a chance to take place.
(Note that this approach introduces at-most-once semantics. You have been warned)

Hibernate Remove faulty entity from transaction

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

Spring data JPA logging

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.

Kundera cassandra - Transaction rollback and Entity update

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.

How to commit and rollback data after getEntityManager.perist(object)

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

Categories