How to implement a method in a DAO? - java

I'm using a DAO pattern and Hibernate for my simple JavaFX project for performing CRUD operations. Since I'm new to Hibernate I want to ask you how to implement a particular method.
Firstly I have a solid DAO interface:
import java.util.List;
import org.hibernate.Session;
import java.util.List;
import org.hibernate.Session;
public interface Dao<T, ID> {
public T findById(ID id);
public List<T> findAll();
public T save(T entity);
public void delete(T entity);
public void flush();
public void clear();
public void setSession(Session session);
}
Then I have another interface (more specific):
public interface FotoDao extends Dao<Foto, Integer> {
public List<Foto> findByCarId(Integer id);
}
Followed by another class:
import dao.interfaces.Dao;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import utils.HibernateUtil;
public class AbstractDao<T, ID extends Serializable> implements Dao<T, ID> {
private Class<T> persistentClass;
private Session session;
#SuppressWarnings("unchecked")
public AbstractDao() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public void setSession(Session session) {
this.session = session;
}
protected Session getSession() {
if (this.session == null) {
this.session = HibernateUtil.getSessionFactory().getCurrentSession();
}
return this.session;
}
public Class<T> getPersistentClass() {
return persistentClass;
}
#SuppressWarnings("unchecked")
#Override
public T findById(ID id) {
return (T) getSession().load(this.getPersistentClass(), id);
}
#Override
public List<T> findAll() {
return this.findByCriteria();
}
protected List<T> findByCriteria(Criterion... criterion) {
Criteria crit = this.getSession().createCriteria(this.getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
return (List<T>) crit.list();
}
#Override
public T save(T entity) {
this.getSession().saveOrUpdate(entity);
return entity;
}
#Override
public void delete(T entity) {
this.getSession().delete(entity);
}
#Override
public void flush() {
this.getSession().flush();
}
#Override
public void clear() {
this.getSession().clear();
}
}
Then finally I have a concrete class:
public class FotoHibernateDao extends AbstractDao<Foto, Integer> implements FotoDao {
#Override
public List<Foto> findByCarId(Integer id) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
How do I implement the findByCarId(Integer id) method?
In my data model I have a table which stores foto urls of cars. And I want this
method to return only images associated with a carId (which is a foreign key).

Related

interface (mock) repository pattern java spring

I am a beginner in Java and in the Spring environment. At the moment I have to implement a CustomerRepository. The CustomerRepository implements a CrudRepository interface. The purpose is that in the repository, customer objects should be stored and retrieved.
I have to use a Mock implementation of the Spring class CrudRepository.
The classdiagram looks like this:
classdiagram
CrudRepository interface:
public interface CrudRepository<Customer, String> {
<S extends Customer> S save( S entity );
...
}
The complete CustomerRepository class:
public class CustomerRepository implements CrudRepository<Customer, String> {
private CrudRepository crudrepository;
/*long count();*/
#Override
public long count() {
long count = crudrepository.count();
return count;
}
/*<S extends Customer> S save( S entity );*/
#Override
public <S extends Customer> S save(S entity) {
crudrepository.save(entity);
return entity;
}
/*<S extends Customer> Iterable<S> saveAll( Iterable<S> entities );*/
#Override
public <S extends Customer> Iterable<S> saveAll(Iterable<S> entities) {
Iterable<S> response = crudrepository.saveAll(entities);
return (Iterable<S>) response;
}
/*Optional<Customer> findById(String id );*/
#Override
public Optional<Customer> findById(String id) {
Optional<Customer> customerResponse = crudrepository.findById(id);
return customerResponse;
}
/*Iterable<Customer> findAllById(Iterable<String> ids );*/
#Override
public Iterable<Customer> findAllById(Iterable<String> ids) {
Iterable<Customer> customerResponse = crudrepository.findAllById(ids);
return customerResponse;
}
/*Iterable<Customer> findAll();*/
#Override
public Iterable<Customer> findAll() {
Iterable<Customer> customerResponse = (Iterable<Customer>) crudrepository
.findAll();
return customerResponse;
}
/*boolean existsById(String id );*/
#Override
public boolean existsById(String id) {
return crudrepository.existsById(id);
}
/*void deleteById(String id );*/
#Override
public void deleteById(String id) {
crudrepository.deleteById(id);
}
/*void delete(Customer entity );*/
#Override
public void delete(Customer entity) {
crudrepository.delete(entity);
}
/*void deleteAllById(Iterable<? extends String> ids );*/
#Override
public void deleteAllById(Iterable<? extends String> entities) {
crudrepository.deleteAll(entities);
}
/*void deleteAll();*/
#Override
public void deleteAll() {
crudrepository.deleteAll();
}
/*void deleteAll(Iterable<? extends Customer> entities );*/
#Override
public void deleteAll(Iterable<? extends Customer> entities) {
crudrepository.deleteAll(entities);
} }
How does that look for you ? Any suggestions ?
I think you are misunderstanding some concepts.
CrudRepository is a Spring object and it's an interface you don't need to implement. You have to extend it and Spring provides you all the magic.
You can achieve your goal simply in the following way:
Repository
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface CustomerRepository extends CrudRepository<Customer, String> {
}
Service
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class CustomerService {
#Autowired
private CustomerRepository customerRepository;
public Customer save(Customer customer) {
Customer response = customerRepository.save(customer);
return response;
}
}

How to implement generic service-layer class in Spring Framework?

I try to implement generic service-layer class for basic CRUD operations.
public abstract class AbstractService<T, R extends JpaRepository> {
protected R repository;
public AbstractService(R repository) {
this.repository = repository;
}
public T getOne(final Long id){
return repository.findById(id); // error Required: T, Found: Optional<>
}
}
Why couldnt I use type T without wrapping it to Optional?
You should always follow the good practices that are recommended for JPA and hibernate, so you must create a respository per entity, as this will allow you to develop more scalable applications, however if you want not to have to do this and want an abstract class that allows you To do this, I recommend doing an abstract Dao class that allows you to perform CRUD operations as follows:
import java.io.Serializable;
import java.util.List;
/**
* #author Edy Huiza
* #version 1.0
* Created on 23/11/2018
*/
public interface Dao<T> {
void persist(Object entity);
void persist(Object[] entities);
void update(Object entity);
void delete(Object entity);
void delete(Class entityClass, Serializable id);
List findAll(Class entityClass);
Object get(Class entityClass, Serializable id);
}
And their respective implementation
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
/**
* #author Edy Huiza
* #version 1.0
* Created on 23/11/2018
*/
#Repository
public class SpringHibernateDao implements Dao {
#PersistenceContext
private EntityManager entityManager;
#Override
#Transactional
public void persist(Object entity) {
entityManager.persist(entity);
entityManager.flush();
entityManager.clear();
}
#Override
#Transactional
public void update(Object entity) {entityManager.merge(entity);
}
#Override
#Transactional
public void persist(Object[] entities) {
for (Object entity : entities) {
persist(entity);
}
}
#Override
#Transactional
public void delete(Object entity) {
entityManager.remove(entity);
}
#Override
#Transactional
public void delete(Class entityClass, Serializable id) {
Object entity = get(entityClass, id);
entityManager.remove(entity);
}
#SuppressWarnings("unchecked")
#Override
#Transactional(readOnly = true)
public List findAll(Class entityClass) {
return entityManager.createQuery("from " + entityClass.getName()).getResultList();
}
#Override
#Transactional(readOnly = true)
public Object get(Class entityClass, Serializable id) {
return entityManager.find(entityClass, id);
}
}
And their respective use
#Autowired
Dao dao;
#Override
#Transactional(readOnly = true)
public Dispositivo get(long id) {
return (Dispositivo) dao.get(Dispositivo.class, id);
}
You can try something like this:
public abstract class AbstractService<T, ID, R extends JpaRepository<T, ID>> {
protected R repository;
public AbstractService(R repository) {
this.repository = repository;
}
public Optional<T> getOne(ID id){
return repository.findById(id);
}
}

Autowiring a Class<T extends BaseEntity> when Autowiring a DAO bean

So I have tried searching all over for this blocker and tried many different ways of finding a solution but I cannot wrap my head around it. I am a beginner in Spring and I have created a generic DAO that takes in any T which extends BaseEntity. I have the following code:
private Class<T> clazz;
#Autowired
public void setClazz(Class<T> clazz){
System.out.println("In class Autowired Setter");
this.clazz = clazz;
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Class<T> getClazz(){
return clazz;
}
Which I have put inside my BaseDAOImpl. Then I use this constructor:
public BaseDAOImpl() {
this.collection = MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz);
}
to create a JacksonDbCollection for MongoDB. In my CustomerServiceImpl I Autowire my BaseDAO bean so that I can use my DAO for persistance.
#Autowired
public void setBaseDAO(BaseDAO<CustomerEntity> baseDAO) {
this.baseDAO = baseDAO;
}
So when I run a method that uses my BaseDAOImpl, I get a NullPointerException and I am pretty sure it is because of the Class that is not picking up my CustomerEntity. My question is how can I get Class to pick up CustomerEntity when I Autowire my baseDao bean? Or what suggestions do you have for me to solve my problem? I just need a different point of view and thought I would ask for it here.
Thank you in advanced for you assistance.
Update
BaseDAOImpl
package za.co.thekeeper.dao;
import org.mongojack.DBCursor;
import org.mongojack.DBQuery;
import org.mongojack.JacksonDBCollection;
import org.mongojack.WriteResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import za.co.thekeeper.entities.BaseEntity;
import za.co.thekeeper.mongo.MongoConnection;
import za.co.thekeeper.mongo.MongoDbUtil;
import java.util.ArrayList;
import java.util.List;
#Repository
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class BaseDAOImpl<T extends BaseEntity> implements BaseDAO<T> {
private JacksonDBCollection<T, String> collection;
/**Dependency Injections**/
private MongoConnection mongoConnection;
#Autowired
public void setMongoConnection(MongoConnection mongoConnection) {
System.out.println("In autowired setter");
this.mongoConnection = mongoConnection;
}
private Class<T> clazz;
#Autowired
public void setClazz(Class<T> clazz){
System.out.println("In class Autowired Setter");
this.clazz = clazz;
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Class<T> getClazz(){
return clazz;
}
public BaseDAOImpl() {
this.collection = MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz);
}
#Override
public T create(T entity) {
entity.activate();
entity.beforePersist();
WriteResult<T, String> inserted = this.collection.insert(entity);
return inserted.getSavedObject();
}
#Override
public void delete(T entity) {
deactivate(entity);
}
#Override
public T activate(T entity) {
entity.activate();
return update(entity);
}
#Override
public T deactivate(T entity) {
entity.deactivate();
return update(entity);
}
#Override
public void activate(String id) {
T entity = getById(id);
if (entity == null) {
throw new NullPointerException("Entity not found with id: " + id);
}
activate(entity);
}
#Override
public void deactivate(String id) {
T entity = getById(id);
if (entity == null) {
throw new NullPointerException("Entity not found with id: " + id);
}
deactivate(entity);
}
#Override
public T update(T entity) {
entity.beforePersist();
WriteResult<T, String> saved = this.collection.save(entity);
return saved.getSavedObject();
}
#Override
public void deleteById(String id) {
deactivate(id);
update(getById(id));
}
#Override
public T getById(String id) {
return this.collection.findOneById(id);
}
#Override
public List<T> findByField(String field, Object o) {
DBQuery.Query query = DBQuery.is(field, o);
DBCursor<T> cursor = this.collection.find(query);
return readCursor(cursor);
}
#Override
public void createDBRef(String databaseName, String collectionName, String id) {
}
#Override
public List<T> findAll() {
return findByField("activate", Boolean.TRUE);
}
/**
* Cursor
**/
private List<T> readCursor(DBCursor<T> cursor) {
if (cursor.size() > 0) {
List<T> found = new ArrayList<>();
while (cursor.hasNext()) {
found.add(cursor.next());
}
return found;
}
return null;
}
}
CustomerServiceImpl
package za.co.thekeeper.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import za.co.thekeeper.dao.BaseDAO;
import za.co.thekeeper.dao.BaseDAOImpl;
import za.co.thekeeper.entities.CustomerEntity;
import za.co.thekeeper.entities.MerchantEntity;
import za.co.thekeeper.entities.ReceiptEntity;
import za.co.thekeeper.mongo.MongoConnection;
import java.util.List;
import java.util.UUID;
#Service
public class CustomerServiceImpl implements CustomerService {
private BaseDAO<CustomerEntity> baseDAO;
#Autowired
public void setBaseDAO(BaseDAO<CustomerEntity> baseDAO) {
this.baseDAO = baseDAO;
}
#Override
public CustomerEntity registerNewCustomer(CustomerEntity customer) {
if (customer.getId() == null) {
customer.setId(UUID.randomUUID().toString());
}
CustomerEntity entity = baseDAO.create(customer);
System.out.println(entity.toString());
return entity;
}
#Override
public CustomerEntity getCustomer(String cellNumber) {
List<CustomerEntity> entities = baseDAO.findByField("cellNumber", cellNumber);
return entities.get(0);
}
#Override
public CustomerEntity updateCustomerDetails(CustomerEntity customer) {
return baseDAO.update(customer);
}
#Override
public void deleteCustomer(CustomerEntity customer) {
baseDAO.delete(customer);
}
}
Application Context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="za.co.thekeeper"/>
As requested.
New Update
BaseDAO
package za.co.thekeeper.dao;
import za.co.thekeeper.entities.BaseEntity;
import za.co.thekeeper.mongo.MongoConnection;
import java.util.List;
public interface BaseDAO<T extends BaseEntity> {
T create(T entity);
void delete(T entity);
T activate(T entity);
T deactivate(T entity);
void activate(String id);
void deactivate(String id);
T update(T entity);
void deleteById(String id);
T getById(String id);
List<T> findByField(String id, Object o);
void createDBRef(String databaseName, String collectionName, String id);
List<T> findAll();
}
You existing BaseDAOImpl:
private MongoConnection mongoConnection;
#Autowired
public void setMongoConnection(MongoConnection mongoConnection) {
System.out.println("In autowired setter");
this.mongoConnection = mongoConnection;
}
private Class<T> clazz;
#Autowired
public void setClazz(Class<T> clazz){
System.out.println("In class Autowired Setter");
this.clazz = clazz;
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Class<T> getClazz(){
return clazz;
}
public BaseDAOImpl() {
this.collection = MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz);
}
This is not the right way to initialize this bean.
You are doing a setter injection on mongoConnection and accessing that in the default constructor. MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz); The constructor gets called before the setter is invoked. This is going to result in NPE.
Nobody is setting the clazz variable.
#Autowired on a setter and #Bean on a getter is meaningless.
#Repository annotation is not required. You can use #Component
The right way to do things would be this.
BaseDAOImpl class - Including only a part of the class for brevity
package za.co.thekeeper.dao;
import org.mongojack.DBCursor;
import org.mongojack.DBQuery;
import org.mongojack.JacksonDBCollection;
import org.mongojack.WriteResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import za.co.thekeeper.entities.BaseEntity;
import za.co.thekeeper.mongo.MongoConnection;
import za.co.thekeeper.mongo.MongoDbUtil;
import java.util.ArrayList;
import java.util.List;
public class BaseDAOImpl<T extends BaseEntity> implements BaseDAO<T> {
private JacksonDBCollection<T, String> collection;
/**Dependency Injections**/
private MongoConnection mongoConnection;
public void setMongoConnection(MongoConnection mongoConnection) {
System.out.println("In autowired setter");
this.mongoConnection = mongoConnection;
}
private Class<T> clazz;
public void setClazz(Class<T> clazz){
System.out.println("In class Autowired Setter");
this.clazz = clazz;
}
public Class<T> getClazz(){
return clazz;
}
public BaseDAOImpl(MongoCollection mongoCollection, Class<T> clazz) {
this.mongoCollection = mongoCollection;
this.clazz = clazz;
this.collection = MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz);
}
}
Spring configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="za.co.thekeeper"/>
<bean class="za.co.thekeeper.dao.BaseDAOImpl">
<constructor-arg index="0" ref="mongoCollection"/>
<constructor-arg index="1">
<value type="java.lang.Class">CustomerEntity</value>
</constructor-arg>
</bean>
Spring will detect the type T from the second constructor injection and allow you to autowire beans of type BaseDAOImpl<CustomerEntity>.
Note: I assume mongoCollection is declared as a spring bean elsewhere. Otherwise you need to add that in the spring configuration file.
private BaseDAO<CustomerEntity> baseDAO;
#Autowired
public void setBaseDAO(BaseDAO<CustomerEntity> baseDAO) {
this.baseDAO = baseDAO;
}
Try using constructor-injection instead. Check if it helps
private BaseDAO<CustomerEntity> baseDAO;
#Autowired
public CustomerServiceImpl(BaseDAO<CustomerEntity> baseDAO) {
this.baseDAO = baseDAO;
}

How to retrieve,update,delete data from database using DAO method in Hibernate

How to retrieve,update,delete data from database using DAO method in Hibernate.
My DAO look like this:
package com.sample.common.impl;
import java.util.List;
import com.sample.common.Employee;
public interface EmployeeDao {
public List<Employee> getAllEmployee();
public void updateEmployee(Employee emp);
public void deleteEmployee(Employee emp);
}
My implementation class look like this:
package com.sample.common.impl;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.SessionFactory;
import com.sample.common.Employee;
public class EmployeeDaoImpl implements EmployeeDao {
private SessionFactory sessionFactory;
public List<Employee> getAllEmployee() {
return null;
}
public void updateEmployee(Employee emp) {
}
public void deleteEmployee(Employee emp) {
}
}
How to create the query for select,update and delete. can you please suggest any possible solution
You have to update the code as below
public void deleteEmployee(Employee emp) {
Session session = sessionFactory.getCurrentSession();
session.delete(emp);
logger.debug(emp.getClass());
}
public void updateEmployee(Employee emp) {
Session session = sessionFactory.getCurrentSession();
session.update(emp);
logger.debug(emp.getClass());
}
public List<Employee> getAllEmployee(){
String query ="SELECT e FROM EMPLOYEE e";
List<Employee> empList = session.createQuery(query);
return empList;
}
Hope this stuff works.

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