Manual rollback Spring MVC + Hibernate - java

I am using Spring MVC + Hibernate
//Class for Generic Methods for **save and update**
#Service("PersistenceTemplate")
#Transactional
public class PersistenceTemplate {
#Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
// SAVE
public <T> long save(T entity) throws DataAccessException {
Session session = sessionFactory.getCurrentSession();
long getGenVal=(Long) session.save(entity);
return getGenVal;
}
//UPDATE
public <T> void update(T entity) throws DataAccessException {
sessionFactory.getCurrentSession().update(entity);
}
}
AT Controller
#Resource(name = "PersistenceTemplate")
private PersistenceTemplate pt;
long result=pt.save(receiveTrxObj1);
pt.Update(receiveTrxObj2);
Problem statement
How to roll back save statement if Update fails to update the entity in database ?

You could use application level exception to rollback your entity operations. When this custom exception thrown the related operations rollback. Please see following documents to see how to define custom rollback in Spring.

first your #Service("PersistenceTemplate") should be marked as #Repository because its doing the work of DAO layer.
from the controller you should call a Service which should be annotated with #service and #Transactional and inside this service you create a method which will call a DAO layer.
if save or Update fails to update the entity in database the method from which it is called (ie. the method in service layer) will not complete and the transaction is cancelled automatically because persistence objects are synchronized with database near the end of the completion of method of service layer once the control comes back to it.
See the below example.
#Service("authorLoadService")
#Transactional
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS,value="request")
public class AuthorEntityLoadService implements EntitiesLoadService{
private AuthorDAO authorDao;//this is my DAO
#Autowired
#Qualifier("authorDAO")
public void setAuthorDao(AuthorDAO authorDao) {
this.authorDao = authorDao;
}
#Override
public void deleteEntities(Object o) {
// TODO Auto-generated method stub
}
#Override
public void loadEntities(Object o) {
Set<author_pojo> author=(Set<author_pojo>)o;
Iterator<author_pojo> itr=author.iterator();
while (itr.hasNext()) {
author_pojo authorPojo = (author_pojo) itr.next();
authorDao.save(authorPojo);
}
}
#Override
#Transactional(readOnly=true)
public List getEntities() {
// TODO Auto-generated method stub
return null;
}
#Override
#Transactional(readOnly=true)
public Object getEntity(Object o) {
String author=(String)o;
author_pojo fetAuthor=authorDao.findOneByName(author);
return fetAuthor;
}
}
My Abstract Generic DAO
public abstract class AbstractHibernateDAO<T extends Serializable> {
public Class<T> clazz;//class object reference
protected SessionFactory mysessionFactory;
#Autowired
public void setMysessionFactory(SessionFactory mysessionFactory) {
this.mysessionFactory = mysessionFactory;
}
public T findOneByName(final String name){
return (T) getCurrentSession().createQuery("from "+clazz.getName()).uniqueResult();
}
public void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public T findOne(final Long id) {
return (T) getCurrentSession().get(clazz, id);
}
#SuppressWarnings("unchecked")
public List<T> findAll() {
return getCurrentSession().createQuery("from " + clazz.getName()).list();
}
public void save(final T entity) {
getCurrentSession().merge(entity);
}
public void update(final T entity) {
getCurrentSession().update(entity);
}
public void delete(final T entity) {
getCurrentSession().delete(entity);
}
public void deleteById(final Long entityId) {
final T entity = findOne(entityId);
delete(entity);
}
protected Session getCurrentSession() {
return mysessionFactory.getCurrentSession();
}
}
my concerete DAO
#Repository("authorDAO")
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS,value="request")
public class AuthorDAO extends AbstractHibernateDAO<author_pojo> {
public AuthorDAO() {
setClazz(author_pojo.class);
}
public author_pojo findOneByName(final String name){
System.out.println(clazz);
return (author_pojo) getCurrentSession().createQuery("from "+clazz.getName() +" where authorName=:name").setParameter("name", name).uniqueResult();
}
}

For you to be able to rollback the save if the update fails, the save and update have to occur within the same transaction. Services are a natural place to put DAO calls that need to execute within the same transaction.
Putting a #Transactional annotation on the controller method would create complications due to proxying the controller, see the Spring MVC documentation, 17.3.2:
A common pitfall when working with annotated controller classes
happens when applying functionality that requires creating a proxy for
the controller object (e.g. #Transactional methods). Usually you will
introduce an interface for the controller in order to use JDK dynamic
proxies. To make this work you must move the #RequestMapping
annotations, as well as any other type and method-level annotations
(e.g. #ModelAttribute, #InitBinder) to the interface as well as the
mapping mechanism can only "see" the interface exposed by the proxy.
Alternatively, you could activate proxy-target-class="true" in the
configuration for the functionality applied to the controller (in our
transaction scenario in ). Doing so indicates
that CGLIB-based subclass proxies should be used instead of
interface-based JDK proxies. For more information on various proxying
mechanisms see Section 9.6, “Proxying mechanisms”.
See this question for what goes in a service as opposed to in a controller.

Related

check if entity exist and then delete it in one transaction in spring app

i have a services layer and a repository layer in my spring boot application (i use also spring data, mvc etc)
before deleting an entity from the database, I want to check if such an entity exists and if not, then throw an EntityNotFoundException
for example my repository:
public interface RoomRepository extends CrudRepository<Room, Long> {
#Query("from Room r left join fetch r.messages where r.id = :rId")
Optional<Room> findByIdWithMessages(#Param("rId") long id);
#Override
List<Room> findAll();
}
and service:
#Service
#Loggable
public class RoomService implements GenericService<Room> {
private final RoomRepository roomRepository;
private final RoomDtoMapper roomMapper;
public RoomService(RoomRepository roomRepository, RoomDtoMapper roomMapper) {
this.roomRepository = roomRepository;
this.roomMapper = roomMapper;
}
#Override
public Room getById(long id) {
return roomRepository.findById(id).orElseThrow(
() -> new EntityNotFoundException(String.format("room with id = %d wasn't found", id)));
}
#Override
public void delete(Room room) {
getById(room.getId());
roomRepository.delete(room);
}
}
In this example in the delete method, I call the
getById(room.getId())
(so that it throws an EntityNotFoundException if the entity does not exist.)
before
roomRepository.delete(room);
it seems to me that such code is not thread-safe and the operation is not atomic
(because at the moment when in this thread at the moment of checking another request from another thread may already delete the same entity)
and I don't know if I'm doing the right thing
maybe i should add the #Transactional annotation?
would it allow me to make the method atomic?
like this:
#Override
#Transactional
public void delete(Room room) {
getById(room.getId());
roomRepository.delete(room);
}
maybe i should set some kind of isolation level?
you can test if your object needed, exist or not by autowiring the repository injected (in your case is RoomRepository e.g) and (insted User in my exmaple you can use Room): for example:
public ResponseEntity<Object> deletUserById(Long id) {
if (userrRepository.findById(id).isPresent()) {
userrRepository.deleteById(id);
return ResponseEntity.ok().body("User deleted with success");
} else {
return ResponseEntity.unprocessableEntity().body("user to be deleted not exist");
}
}

Spring Boot. #Transactional method calling a #Transactional(readonly=true) method

I have the next problem. When a controller invokes a service method with #Transactional annotation and this method invokes a #Transactional(readonly=true) method, the changes in the object doesn't get saved in the database. I don't know why. I thought that the first method begins a 'read and write' transaction and the second method uses the same transaction.
Example :
/** Controller class **/
#RestController
#RequestMapping("/path1")
public class MyObjectRestController {
...
#Autowired
MyObjectService myObjectService;
#PostMapping(value = "/path2")
#ResponseStatus(HttpStatus.CREATED)
public void save(#RequestBody MyObject myObject) {
myObjectService.save(myObject);
}
...
}
/** Service class **/
public interface MyObjectService {
public MyObject save(MyObject myObject);
public MyObject findOne(long id);
}
/** Service implementation class **/
#Service
public class MyObjectServiceImpl implements MyObjectService {
/**
* Save Object
*/
#Override
#Transactional
public Object save(Object newObject) {
Object myObject = this.findOne(newObject.getId());
// Modify Object
myObject.setAttribute1(...)
myObject.setAttribute2(...)
// Save Object (using Repository)
return MyObjectDao.save(myObject);
}
/**
* Get Object by Id
*/
#Override
#Transactional(readOnly = true)
public MyObject findOne(long id) {
Optional<MyObject> myObject = MyObjectDao.findById(id);
return myObject.isPresent() ? myObject.get() : null;
}
}
This example doesn't update the object attributes. But if I remove the #Transactional annotation in save(..) method ... this example works successfully! (the object is modified).
Why is this happening?
I see save method is annotated with #Transactional and calls findOne method which is also #Transactional. So in this case the same transaction is getting propagated to findOne method and it applies readonly behaviour to the current transaction. And thus it does not perform Flush and you see entity is not modified.
So in this case, you should use a separate transaction for read and writes.
findOne method can be annotated with below -
#Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)

Autowired annotation not working with #PostLoad

I want to use it for manipulating data from the repository with catalog service, but Autowired annotation is not injecting dependency.
#Service
public class PostEntityListener {
#PostLoad
public <T> void onPrePersist(T obj) {
if (obj != null) {
String type = obj.getClass().getSimpleName();
switch (type) {
case "Order":
break;
case "OrderItem":
try {
OrderItem orderItem = (OrderItem) obj;
if (orderItem != null) {
catalogService.save(orderItem);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
#Autowired
private CatalogService catalogService;
}
Here are my CatalogService details:
public interface CatalogService {
void save(OrderItem orderItem);
}
#Service
public class CatalogServiceImpl implements CatalogService {
public void save(OrderItem orderItem) {
catalogRepository.save(orderItem);
}
#Autowired
private CatalogRepository catalogRepository;
}
First of all, have in mind that, according to the JPA specification, you should not mess (either directly or indirectly) with the same persistence context that is invoking your lifecycle method:
In general, the lifecycle method of a portable application should not invoke EntityManager or query operations, access other entity instances, or modify relationships within the same persistence context [46] . [47] A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.
So your call to catalogService.save(orderItem); looks suspicious.
Regarding your main question, the problem is that EntityListener instances are instantiated by the JPA provider and not by Spring, so you cannot directly use Spring goodies in them. You can implement some workarounds, though, read this question for more details, specially Den B's answer looks easily adaptable to your code.
i have tried it , just follow below snippet code.
#Component
public class DeptItemTransferBean {
#Autowired
private CatalogRepository catalogRepository;
public void save(OrderItem orderItem) {
catalogRepository.save(orderItem);
I have solved this issue with setter-injection. I used the following code to inject dependency:
#Autowired
public void setCatalogService(CatalogService catalogService) {
this.catalogService = catalogService;
}

Open new transaction when already inside ejb

Consider the following situation:
#Stateless
#Clustered
public class FacadeBean implements Facade {
#EJB
private Facade facade;
#Override
public void foo(List<Integer> ids) {
// read specific id's from the db
for (Integer id : ids) {
facade.bar(id);
}
}
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void bar(Integer id) {
// save something to the db
}
}
Method foo gets called from outside the ejb. I want each id to be executed in its own transaction, so that data get's persisted directly to the database. It is not possible to have the foreach outside of this class. I am wondering what is the best way to do this? At the moment I am injecting the interface again, to step over the ejb boundaries (so that the TransactionAttribute get's evaluated).
Your approach as to circular reference is perfectly fine. Circular reference in EJBs is allowed. This is even mandatory in order to start out a new transaction, or an #Asynchronous thread (otherwise the current thread would still block).
#Stateless
public class SomeService {
#EJB
private SomeService self; // Self-reference is perfectly fine.
// Below example starts a new transaction for each item.
public void foo(Iterable<Long> ids) {
for (Long id : ids) {
self.fooInNewTransaction(id);
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void fooInNewTransaction(Long id) {
// ...
}
// Below example fires an async thread in new transaction.
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void bar(Iterable<Long> ids) {
for (Long id : ids) {
self.fooAsynchronously(id);
}
}
#Asynchronous
public void fooAsynchronously(Long id) {
// ...
}
}
Only in older containers, this did not work, most notably JBoss AS 5 with the ancient EJB 3.0 API. That's why people invented workarounds like SessionContext#getBusinessObject() or even manually grabbing via JNDI.
Those are unnecessary these days. Those are workarounds not solutions.
I'd personally only do it the other way round as to transactions. The foo() method is clearly never intented to be transactional.
#Stateless
public class SomeService {
#EJB
private SomeService self;
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void foo(Iterable<Long> ids) {
for (Long id : ids) {
self.foo(id);
}
}
public void foo(Long id) {
// ...
}
}
Depending on the concrete functional requirement, you could even make the foo(Long id) #Asynchronous, hereby speeding up the task.
Do you really have to have both methods in one class? You can move bar() to an own bean and make it transactional. Then you don't have to use this kind of self-injection.
You can also try to use SessionContext#getBusinessObject() method.
#Resource
SessionContext sessionContext;
#Override
public void foo(List<Integer> ids) {
Facade facade = sessionContext.getBusinessObject(Facade.class);
// read specific id's from the db
for (Integer id : ids) {
facade.bar(id);
}
}

Accessing external source from DAO implementation

Consider following simple DAO example:
public abstract class DAOFactory
{
public abstract AccountDAO getAccountDAO();
public abstract MessageDAO getMessageDAO();
public static DAOFactory getDAOFactory(int whichFactory)
{
// depending on whichFactory
return new SpecificDAOFactory();
}
}
public interface AccountDAO
{
public void add(Account account);
public void delete(Account account);
public int authenticate(Account account); // another source!
}
public interface MessageDAO
{
//other methods
}
All above mentioned methods have to be implemented using the same data source, except AccountDAO.authenticate().
Authentication information available at the other data source and should be pluggable in turn (e.g. could be SQL, LDAP, etc.). At the same time, authentication data source is independent from the DAO data source, i.e. whichFactory could be A, B or C while authentication source X or Y.
From interface design point of view, authenticate fits nicely into AccountDAO. But from implementation point of view I feel uncomfortable.
What would be better design which will provide clear data access layer interface and implementation?
Data access objects tend to follow the same structure and pattern, so you might want to consider creating a higher level class encapsulating this shared logic. I will highlight with an example, please note that I am omitting interfaces because I rarely find them useful at the DAO level.
Base DAO class:
public class BaseDAO<T> {
private Class<T> clazz;
public BaseDAO(Class<T> clazz) {
super();
this.clazz = clazz;
}
public T find(Long id) { ... }
public List<T> findAll() { ... }
public T create(T entity) { ... }
public T update(T entity) { ... }
public void delete(T entity) { ... }
}
A derived DAO for a hypothetical Account object
public class AccountDAO extends BaseDAO<Account> {
public AccountDAO() {
super(Account.class);
}
public List<Account> findByAccountStatus(String status) { ... }
}
As you can see, you greatly minimize the amount of code in derived DAO's. With this setup you do not need to use a factory, just initialize your DAO's directly.
As far as your second question, I would not place an authenticate method on the Account DAO. Authentication should be dealt with at a higher level of abstraction (fits very nicely in the service layer), even if it eventually retrieves some information from the data access layer.

Categories