why does #transactional rolls back even when running on a new transaction? - java

I am learning spring transaction propagation. so i have three inner services in Organization Service.
OrganizationService
#Service
public class OrganizationServiceImpl implements OrganizationService {
#Autowired
EmployeeService employeeService;
#Autowired
HealthIsuranceService healthInsuranceService;
#Autowired
InsuranceLogService insuranceLogService;
#Override
#Transactional(propagation = Propagation.REQUIRED)
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
InsuranceLog insuranceLog = new InsuranceLog();
insuranceLog.setInformation("new log information");
insuranceLogService.logIt(insuranceLog);
}
#Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
HealthInsuranceService
#Service
public class HealthInsuranceServiceImpl implements HealthIsuranceService{
#Autowired
HealthInsuranceDao healthInsuranceDao;
#Override
#Transactional(propagation = Propagation.REQUIRED)
public void registerEmployeeHealthInsurance(EmployeeHealthInsurance employeeHealthInsurance) {
healthInsuranceDao.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
#Override
public void deleteEmployeeHealthInsuranceById(String empid) {
healthInsuranceDao.deleteEmployeeHealthInsuranceById(empid);
}
}
EmployeeService
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
EmployeeDao employeeDao;
#Override
#Transactional(propagation = Propagation.REQUIRED)
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
#Override
public void deleteEmployeeById(String empid) {
employeeDao.deleteEmployeeById(empid);
}
}
EmployeeLogService
#Service
public class InsuranceLogServiceImpl implements InsuranceLogService{
#Autowired
private InsuranceLogDao insuranceLogDao;
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void logIt(InsuranceLog logInfo){
int i=0;
int j =0;
int result = i/j;
insuranceLogDao.logIt(logInfo);
}
}
here is my scenario :-
insertEmployee(employee) and registerEmployeeHealthInsurance(employeeHealthInsurance) should run in the same transaction so that either of them commits together or rolls back together. logIt(insuranceLog) is optional when these two transactions commits. failing to log should not roll back above transactions.
logIt(insuranceLog) should all also roll back when either of insertEmployee(employee) , registerEmployeeHealthInsurance(employeeHealthInsurance) fails to commit.
how can i achieve this ?

Related

Spring Batch with Hiberbate , Entity not persisted after flush

I've a job with one Step. The step has the usual setup.
reader: read from a Stock DB-table "instrument"
processor: retrieving the latest price from an external service
writer: writing the latest price in the price DB-table "instrumentprice"
There is a ItemWriteListener which does some calculations on the latest price in db-table "instrumentprice". So, it's important that the writer is persisting the latest price immediately in the DB-table "instrumentprice"
In the writer the methods, persist and flush are called on the EntityManager for the Entity "instrumentprice".
But Hibernate doesn't write into the table "instrumentprice" immediately. It does write into the table "instrumentprice" at a later stage, but I haven't figured out the mechanism yet.
#Configuration
#ComponentScan(basePackages = {"com.chartinvestbatch.alphaVantageHistory"})
public class JobConfig {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private ChartInvestJobListener chartInvestJobListener;
#Bean
public Job jobAlphaVantage(#Qualifier("stepProcessingPrices") Step stepProcessingPrices) throws IOException {
return jobBuilderFactory
.get("JobAlphaVantage")
.listener(chartInvestJobListener)
.incrementer(new RunIdIncrementer())
.start(stepProcessingPrices)
.build();
}
}
#Configuration
public class StepConfig {
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private TaCalcListener taCalcListener;
#Bean
#Qualifier("stepProcessingPrices")
public Step stepProcessingPrices(HibernateCursorItemReader<Instrument> hibernateCursorItemReader, ItemProcessor<Instrument, InstrumentAndPricesDto> itemProcessor, ItemWriter<InstrumentAndPricesDto> itemWriter) throws IOException {
return stepBuilderFactory
.get("stepProcessingPrices")
.<Instrument, InstrumentAndPricesDto>chunk(1)
.listener((ItemWriteListener<InstrumentAndPricesDto>) taCalcListener)
.reader(hibernateCursorItemReader)
.processor(itemProcessor)
.writer(itemWriter)
.build();
}
}
#Scope(value = "step")
#Component
#Transactional
public class StockItemWriter implements ItemWriter<InstrumentAndPricesDto> {
static Logger log = LogManager.getLogger(StockItemWriter.class);
#Autowired
private IntrumentPriceDao intrumentPriceDao;
#Override
public void write(List<? extends InstrumentAndPricesDto> instrumentAndPricesDtoList) throws Exception {
for (InstrumentAndPricesDto dto : instrumentAndPricesDtoList) {
// check some stuff etc ....
InstrumentPrice instrumentPrice = new InstrumentPrice();
instrumentPrice.setDate(dto.getDate());
...
intrumentPriceDao.persist(instrumentPrice);
intrumentPriceDao.flush();
}
}
}
#Transactional(propagation = Propagation.MANDATORY)
public abstract class GenericDao<T> {
#PersistenceContext
protected EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
public T persist(final T t) {
entityManager.persist(t);
return t;
}
public void flush() {
entityManager.flush();
}
}
#Repository
#Transactional(propagation = Propagation.MANDATORY)
public class IntrumentPriceDao extends GenericDao<InstrumentPrice> {
}

FinAll in MongoDb using Spring return only one record

the problem is once i use method findAll using MongoOperation interface, it working fine with no exception but only return One Record, however the collection contain more than 1 record. i tried a different interface like mongotemp and also the same result, List size is return always 1, even when i try it from dao itself
Configuration Spring DATA with mongodb
#Configuration
public class MongodbConfig {
public #Bean MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new MongoClient(), "inSpace");
}
public #Bean MongoTemplate mongoTemplate() throws Exception {
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());
return mongoTemplate;
}
}
DAO Class
#Repository
public class GenericDAOImpl<T> implements GenericDAO<T> {
#Autowired
protected MongoOperations mongoOper;
public <T> void save(T ct) {
mongoOper.save(ct);
}
public <T> void remove(T ct) {
mongoOper.remove(ct);
}
public T getBydId(String id, Class<T> clazz) {
return mongoOper.findById(id, clazz);
}
public List<T> getAll(Class<T> clazz) {
System.err.println(" ''''''' " + mongoOper.findAll(clazz).size());
return mongoOper.findAll(clazz);
}
}
Note: the upper two classs in a single project and used as dependency for the other project who contain the below classes
Service calling DAO
#Service("userService")
public class UserServiceImpl implements UserService {
#Autowired
private GenericDAO<Users> userDAO;
public Users create(Users user) {
userDAO.save(user);
return user;
}
public Users delete(String id) {
Users user = userDAO.getBydId(id, Users.class);
userDAO.remove(user);
return user;
}
public List<Users> findAll() {
System.out.println("inside User Service");
return userDAO.getAll(Users.class);
}
public Users findById(String id) {
return userDAO.getBydId(id , Users.class);
}
}
Controller Class
#RestController
#RequestMapping("/user")
public class UsersController {
#Autowired
UserService userService;
#RequestMapping(method = RequestMethod.GET, value = "/allUsers")
List<Users> getAllRegistedUsers() {
System.out.println("inside UserController");
return userService.findAll();
}
}
Configuration Class
#SpringBootApplication
#ComponentScan(basePackageClasses=
{UsersController.class,UserService.class,GenericDAO.class})
public class UsersConfiguration {
public static void main(String[] args) {
SpringApplication.run(UsersConfiguration.class, args);
}
}
Note: when i try to inject bean in Main methods and use the bean by ApplicationContext it's work fine and return all records in database !?

#Transactional method calling another method without #Transactional annotation works for save but does not work for update

I know this question has been asked before, but I can't still understand what is wrong with the following code:
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void doStuff(User user, Address address) {
userService.save(user);
addressService.update(address);
}
Below the following classes using Spring Data
#Service
public class UserService {
public User save(User user) {
return userRepository.save(user);
}
}
-
public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
}
-
#Service
public class AddressService {
public Address update(Address address) {
return addressRepository.update(address);
}
}
-
public interface AddressRepository extends JpaRepository<Address, Long>, AddressRepositoryCustom {
}
-
public interface AddressRepositoryCustom {
void update(Address address);
}
-
#Repository
public class AddressRepositoryImpl implements AddressRepositoryCustom {
#PersistenceContext
private EntityManager entityManager;
private JPAQueryFactory query;
#PostConstruct
public void setUp(){
query = new JPAQueryFactory(entityManager);
}
#Override
public void update(Address entity) {
QAddress qAddress = QAddress.address;
JPAUpdateClause update = new JPAUpdateClause(entityManager, qAddress);
update.where(qAddress.id.eq(entity.getId())).set(qAddress.number,entity.getNumber()).execute();
}
}
Based on the answer, "When you call a method without #Transactional within a transaction block, the parent transaction will continue to the new method". This actually works with the save method. However, on the update method, the following exception is thrown:
javax.persistence.TransactionRequiredException: Executing an update/delete query
I want to know why this happens, what is the explanation?

Creating BaseDAO for Each Dao class

I created a spring application where i decided to add a BaseDAO to eliminate redundant create,
update,delete,findByid,and findAll methods for every dao. So i created a baseDao and every dao should extend this BaseDAO.
BaseDaoImpl
public class BaseDAOImpl implements BaseDAO{
SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
#Override
public void create(ModelBase modelBase) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(modelBase);
}
#Override
public void update(ModelBase modelBase) {
Session session = this.sessionFactory.getCurrentSession();
session.update(modelBase);
}
#Override
public Collection findAll(Class aClass) {
Session session = this.sessionFactory.getCurrentSession();
Collection modelCols = session.createQuery("from "+aClass.getSimpleName()).list();
return modelCols;
}
#Override
public ModelBase findById(Class aClass, Integer id) {
Session session = this.sessionFactory.getCurrentSession();
ModelBase modelBase = (ModelBase) session.load(aClass, new Integer(id));
return modelBase;
}
}
Then i extends this Dao to each DAO
EmployeeDAOImp
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO{
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
}
I created a BaseService like this. But when i try to access BaseDAO methods from EmployeeDAO it returns null pointer exception.
Why this happen. I dont want to use genericDAO from google. Because we should create DAOs
for each model. I want to eliminate this. So I follow this method.
Have you though about Spring Data project & Spring Data JPA in particular?
This would save you lots of time, since you would no longer need to write your DAO / Repositories from scratch, all you need to do is enable Spring Data JPA, and add needed interfaces. It should save you tons of time.
http://projects.spring.io/spring-data-jpa/
http://spring.io/guides/gs/accessing-data-jpa/ - Sample project
Your are overriding setSessionFactory from base class for no reason, its already available with extending class EmployeeDAOImpl , either remove it or try below:
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO{
//this reference should be from base class,
// the extending class ref is hiding base ref.
// private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
super.setSessionFactory(sf);
}
}
Something like the following should work (note the use of constructor rather than setter injection). In the BaseDAO:
public class BaseDAOImpl implements BaseDAO {
private final SessionFactory sessionFactory;
public BaseDAOImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Then in the Employee DAO:
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO {
#Inject
public EmployeeDAOImpl (SessionFactory sessionFactory) {
super(sessionFactory);
}
}
You can create generic dao.
#Repository("genericDao")
public class GenericDaoImpl<T,PK extends Serializable> implements GenericDao<T, PK> {
protected Class<T> entityClass;
public T create(T t) {
this.entityManager.persist(t);
return t;
}
public T read(PK id,Class<T> c) {
return (T)this.entityManager.find(c, id);
}
public T update(T t) {
return this.entityManager.merge(t);
}
public void delete(T t) {
t = this.entityManager.merge(t);
this.entityManager.remove(t);
}
public List<T> getAll(Class<T> c){
return this.entityManager.createQuery("SELECT o FROM "+ c.getName() +" o").getResultList();
}
}
UPDATED
You can use as following, TimeRange is a pojo class in the following example. If you do not want a service layer. You can use timeRangeDao in controller.
#Service("timeRangeService")
public class TimeRangeServiceImpl implements TimeRangeService{
#Autowired
GenericDao<TimeRange,Long> timeRangeDao;
public List<TimeRange> getAllTimeRanges(){
return timeRangeDao.getAll(TimeRange.class);
}
#Transactional
public void createTimeRange(TimeRange c) {
timeRangeDao.create(c);
}
#Transactional
public void update(TimeRange p) {
timeRangeDao.update(p);
}
#Transactional
public TimeRange getTimeRange(long id) {
return timeRangeDao.read(id, TimeRange.class);
}
#Transactional
public void delete(long id) {
TimeRange timeRange = new TimeRange();
timeRange.setId(id);
timeRangeDao.delete(timeRange);
}
}

Hibernate Transaction Manager - Java configuration

I've been beating my head against a wall for awhile now trying to get this to work. I have created the following data access object:
public interface GenericDAO<T, ID extends Serializable> {
T findById(ID id);
List<T> findAll();
T save(T entity);
void update(T entity);
void delete(T entity);
}
public class GenericHibernateDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {
private final Class<T> persistentClass;
private final SessionFactory sessionFactory;
public GenericHibernateDAO(final SessionFactory sessionFactory) {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
this.sessionFactory = sessionFactory;
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
public Class<T> getPersistentClass() {
return persistentClass;
}
#Override
public T findById(final ID id) {
return (T) getSession().load(getPersistentClass(), id);
}
#Override #SuppressWarnings("unchecked")
public List<T> findAll() {
return findByCriteria();
}
protected List<T> findByCriteria(final Criterion... criterion) {
final Criteria crit = getSession().createCriteria(getPersistentClass());
for (final Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
#Override
public T save(final T entity) {
getSession().saveOrUpdate(entity);
return entity;
}
#Override
public void delete(final T entity) {
getSession().delete(entity);
}
#Override
public void update(final T entity) {
getSession().saveOrUpdate(entity);
}
}
#Repository
public class StockHibernateDAO extends GenericHibernateDAO<Stock, String> implements StockDAO {
#Inject
public StockHibernateDAO(final SessionFactory sessionFactory) {
super(sessionFactory);
}
}
I'm attempting to set this up with Java Configuration, so here is my configuration to setup my service layer:
#Configuration #Profile("hibernate")
#EnableCaching #EnableTransactionManagement
#ComponentScan("reference.dao.hibernate")
public class HibernateServiceConfig implements TransactionManagementConfigurer {
#Inject private StockDAO stockDao; //No extra methods, just the base stuff for now
#Bean(destroyMethod = "shutdown")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).addScript("classpath:schema.sql").build();
}
#Bean
public SessionFactory sessionFactory() {
return new LocalSessionFactoryBuilder(dataSource()).addAnnotatedClasses(Stock.class)
.setProperty("hibernate.show_sql", "true")
.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory")
.setProperty("hibernate.cache.use_query_cache", "true")
.setProperty("hibernate.cache.use_second_level_cache", "true")
.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect").buildSessionFactory();
}
#Override #Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
Here is the TradingService:
#Service
public class TradingServiceImpl implements TradingService {
#Inject private StockDAO stockDAO;
#Override #Transactional
#CachePut(value = "stockCache", key = "#stock.name")
public Stock addNewStock(final Stock stock) {
stockDAO.save(stock);
return stock;
}
#Override #Cacheable(value = "stockCache")
public Stock getStock(final String stockName) {
return stockDAO.findById(stockName);
}
#Override #CacheEvict(value = "stockCache", key = "#stock.name")
public void removeStock(final Stock stock) {
stockDAO.delete(stock);
}
#Override #CacheEvict(value = "stockCache", key = "#stock.name")
public void updateStock(final Stock stock) {
stockDAO.update(stock);
}
#Override
public List<Stock> getAll() {
return stockDAO.findAll();
}
}
The saving of a stock only seems to be completed if I add a session.flush() to the save method. The way I understand things, having the TransactionManager and the #Transactional around the service layer method should in fact cause that call to be made for me. What is this configuration missing?
Because you are injecting a Session
#Bean
public Session session() {
return sessionFactory().openSession();
}
Spring cannot add it's transactional behavior around it. Let Spring open the session and do it's business.
Instead of injecting a Session, inject a SessionFactory. In your DAO, keep a attribute for SessionFactory and use sessionFactory.getCurrentSession() to acquire a session.
When Spring sees the #Transactional, it will get the SessionFactory, call openSession(), begin a transaction on it, then call your method. When your method returns successfully, it will close that transaction.
You should also probably #Autowired the dao in your service class.

Categories