creating a generic DAO class for Hibernate - java

In my web application, there are quite a few entities, and most of them require CRUD operations. So I am thinking about writing a generic DAO that can handle CRUD for all of the entities. I've found a tutorial article from IBM, but don't quite understand the generic implementation using the generic type 'T', and 'PK'. The article is at this link
I wrote the following DAO by using Object type in all the methods, and they seem working just fine - all my entities are able to do CRUD with the following CommonDao class. Although it works for my needs, I'm looking for what is the best practice for implementing a generic DAO class for Hibernate.
public class CommonDao
{
private final static SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
public CommonDao() {}
#UnitOfWork
public List findAll(Object className)
{
List types = null;
Session session = sessionFactory.openSession();
Criteria criteria = session.createCriteria(className + ".class");
types = (List <Object>) criteria.list();
session.close();
return types;
}
#Transactional
public void saveObject(Object obj)
{
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.saveOrUpdate(obj);
tx.commit();
session.close();
}
#Transactional
public void saveObjectWithManyEntities(Object obj, Set<Object> objects) /* for OneToMany relationships */
{
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.saveOrUpdate(obj);
for (Object o : objects)
{
session.save(o);
}
tx.commit();
session.close();
}
}

The best way to do it is to include Spring Data into your project. The JPA repositories offer basic CRUD, pagination, sorting and most of your queries could be built automatically from the methods naming convention.
Before Spring Data we'd resort to such Generic Daos but not anymore.

Related

Spring JPA with hibernate: Illegal attempt to associate a collection with two open sessions

I've seen several different architectural approaches to implementing spring jpa with hibernate. At a high level something that we have in place right now is the following:
Service layer
#Service("personService")
public class PersonServiceImpl implements PersonService {
#Autowired
private PersonDao personDao
#Override
#Transactional(readOnly=false, propagation=Propagation.REQUIRES_NEW)
public void save(Person person){
personDao.save(person);
}
#Override
public Person findPerson(BigDecimal id){
return personDao.findPerson(id);
}
...
}
DAO / Repository
import ...
#Repository("personRepository")
public class PersonDaoImpl implements PersonDao {
#Autowired
private SessionFactory sessionFactory;
#Override
public void save(Person person){
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(person);
}
#Override
public Person findPerson(BigDecimal id){
Session session = sessionFactory.getCurrentSession();
return session.get(Person.class, id);
}
...
}
POJO / Entity
import ...
#Entity
#Table(name="PERSON"
)
#Getter
#Setter
public class Person {
#Id
#SequenceGenerator(name="PersonSeq", sequenceName="PERSON_SEQ")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "PersonSeq")
#Column(name="PERSON_ID", nullable=false, precision=22, scale=0)
private BigDecimal id;
...
}
However I've noticed that on rare occasions (hard to reproduce) we get the hibernate exception for an "Illegal attempt to associate a collection with two open sessions". I believe this is happening because we have entities with collections (e.g. ManyToOne mappings) that we retrieve from the db, modify, and later try to call saveOrUpdate but the session we retrieved them from is not the same one as the session we are trying to save them to. Which in the above architecture it seems like we find entities with one session but save them in another even though we make the same call to getCurrentSession.
Is this the best pattern to use with these libraries or is another recommended? What could I do to avoid the hibernate exception?
Would switching to using JPA EntityManager be better than just plain hibernate?
Switching to a transaction scoped EntityManger/Session would help. It seems like you are sharing entity objects between threads and while one thread tries to save such a shared entity, the other thread still has an open session to which the collection of the object is connected.
Don't share entity objects between threads, especially not entities that are still managed i.e. attached to their session.

How to design DAO, REST Service layer

I am working on REST and JPA technology and want to design Service and Dao layer generically.
I want to follow the decouple rule for each layer. So that in future at any point of time these layer can be changed if required without much modification. So to do the same for DAO layer I am following Factory pattern.
Please have a look what i did till now.
public abstract class AbstractDao {
#PersistenceUnit(name = "Services")
private EntityManagerFactory factory;
public AbstractDao() {
this.factory = Persistence.createEntityManagerFactory("Services");
}
public void save(AbstractEntity entity) {
EntityManager em = getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(entity);
tx.commit();
}
public void delete(AbstractEntity entity) {
getEntityManager().remove(entity);
}
public List<AbstractEntity> findAll() {
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<AbstractEntity> cq = cb.createQuery(AbstractEntity.class);
Root<AbstractEntity> from = cq.from(AbstractEntity.class);
cq.select(from);
TypedQuery<AbstractEntity> q = getEntityManager().createQuery(cq);
List<AbstractEntity> allitems = q.getResultList();
return allitems;
}
private EntityManager getEntityManager() {
EntityManager em = factory.createEntityManager();
return em;
}
}
So this the design what I used for DAO layer. But not sure is it the right approach or it can be much better like AbstractFactory patter or etc.
Now come to REST Service layer where I am accessing this DAO layer for CRUD.
So this the way how I am accessing the DAO layer on Service layer. But again I am thinking to way some other better way to access this DAO layer.
One more thing I want to ask, would it be good idea if I introduce business layer and follow like this.
Client -> Service Layer-> Business Layer -> DAO Layer
Could someone help me to design the different layer of project.
Thanks in advance.
please use this type of directory structure:
use Spring framework and use Spring Restful service annotations, for example refer this link :
https://dzone.com/articles/exporting-spring-data-jpa

JPA, when to open and close entityManager

I've setup a spring MVC application for a web application and I'm using Hibernates implementation of JPA 2.1.
I've created my models and am able to interact with the database just fine.
I've also decided to use service classes which will manage returning the entities. What I've done is created a BaseService class, so all other service classes will expand on this, and they'll have access to common functions such as create(), delete(), update() and list().
My problem is I'm unsure as to when I should be creating the EntityManager and when I should be closing it?
Currently, in my controller I'm initiating the required services when the controller loads;
#Controller
#RequestMapping("/mycontroller")
public class TestController {
CarService carService = new CarService();
ShowroomService showroomService = new ShowroomService();
}
}
Here is the BaseService that each other service extends;
public class Service<Ety> {
EntityManager em = null;
public Class<Ety> entityClass;
public Service(Class<Ety> entityClass) {
this.entityClass = entityClass;
em = JPAUtil.getEntityManager();
}
public Ety get(int id) {
Ety object = null;
em.getTransaction().begin();
object = em.find(entityClass, id);
em.getTransaction().commit();
return object;
}
public List list() {
List<Ety> objects;
em.getTransaction().begin();
objects = em.createQuery("SELECT c FROM "+entityClass.getName()+" c").getResultList();
em.getTransaction().commit();
return objects;
}
public void save(Ety object) {
em.getTransaction().begin();
em.persist(object);
em.getTransaction().commit();
}
public void update(Ety object) {
em.getTransaction().begin();
em.merge(object);
em.getTransaction().commit();
}
public void delete(Ety object) {
em.getTransaction().begin();
em.remove(object);
em.getTransaction().commit();
}
}
Here's an example Service which expands the above;
public class CarService extends Service<Car> {
public CarService() {
super(Car.class);
}
}
As you can see, I'm creating an EntityManager when the service is created, but at the moment I'm not closing it anywhere.
I'm I creating the entity manager in the correct place? when should I close it.
I had considered putting the entity manager in a static property and creating it within a filter, and then closing it at the end of the application, however I do believe this wouldn't be thread safe and would cause issues?
Any advice would be appreciated.
your CarService should be a spring bean and the instance is created from spring. NOT from your code. The same with the EntityManager. You can use the entityManager with the #autowired annotation.
You open a new EntityManager for each transaction.
This EntityManager is like a Bag mapped to the database, but with zero entity managed inside when it's just opened.
When you work with it, this Bag will be filled with some entities and Hibernate will work to create the adequate requests.
You will close this Bag to save memory at the end of the transaction.
Of course there is some tricks to have many transactions for a given EntityManager, but you have the most general idea. As always it depends...
If you use a framework like Spring or JavaEE, it will open and close the EntityManager, as well starting and committing transactions for you. You have only your business work to write.

Using Hibernate to fetch a generic object

I'm trying to use hibernate to build up a local cache of data that I pull from source websites. I have the the objects configured with JPA (if it makes a difference) and can read/write them fine in a test application.
Now I want to move the code into a generic "Caching" class so that I can request an object from the Cache and process it as normal. I can read the object from the database and pass it back to the calling class, but when I try and access the collections in the object I get the dreaded lazy initialization exception.
I know what causes this, the class that I read the object from commits the transaction after it's read the object from the database and before it returns the object to the calling class.
I have tried various methods to work around this, and the simplest (for me) seems to be to try and access all of the collections in the object to ensure they are loaded before closing the transaction and returning the object.
The problem with that approach is that I don't know the structure of the object that I am retrieving from the database (part of the benefit of Hibernate for me) and therefore I can't call the appropriate methods to load the data. How do I overcome this? I don't really want to do eager fetching of the objects as they may be used by other applications. I don't want to use hbm files if I can avoid it.
This is the call to the Cache class:
Series series = (Series) Cache.getFromCache(id, Series.class)
In the Cache class:
public static Object getFromCache(String key, Class clazz) {
Object dbObject = HibernateUtil.loadObject(clazz, key);
if (dbObject != null) {
logger.debug("Cache (Get): Got object (" + clazz.getSimpleName() + ") for " + key);
return dbObject;
}
}
And HibernateUtil does:
public static Object loadObject(Class clazz, Serializable key) {
Session session = sessionFactory.getCurrentSession();
Object dbObject;
try {
session.beginTransaction();
dbObject = clazz.cast(session.get(clazz, key));
} finally {
session.getTransaction().commit();
}
return dbObject;
First of all, you could avoid a type cast by making your loadObject method parameterized:
public static <T> T loadObject(Class<T> clazz, Serializable key) {
Session session = sessionFactory.getCurrentSession();
T dbObject;
try {
session.beginTransaction();
dbObject = clazz.cast(session.get(clazz, key));
}
finally {
session.getTransaction().commit();
}
return dbObject;
}
Second: why do you open and commit the transaction in this method? Letting the caller open a transaction and commit it when he has finished using the object it has loaded from the cache would solve the problem.
Third: if you really want to let this method open and close the transaction, let it take an Initializer<T> instance as parameter. This initializer would have the responsibility to initialize all the necessary associations before returning the entity.
public static <T> T loadObject(Class<T> clazz,
Serializable key,
Initializer<T> initializer) {
Session session = sessionFactory.getCurrentSession();
T dbObject;
try {
session.beginTransaction();
dbObject = clazz.cast(session.get(clazz, key));
initializer.initialize(dbObject);
}
finally {
session.getTransaction().commit();
}
return dbObject;
}

implementing a dao class properly to manage transactions

I am working on a java web application that calls database backend through hibernate.I use servlets,jsp and tomcat for test/deployment.Most books on java-ee suggested using Dao classes for database calls.As per examples given in books(Hibernate Recipes by Gary Mak),I created a generic base class and a specific subclass as below.
class BaseDao{
private Class persistentClass;
public BaseDao(Class persistentClass) {
super();
this.persistentClass = persistentClass;
}
public Object findById(Long id) {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Object object = null;
try {
object = (Object) session.get(persistentClass, id);
return object;
}
finally {
session.close();
}
}
#Override
public void saveOrUpdate(Object obj) {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.saveOrUpdate(obj);
tx.commit();
}catch(HibernateException e){
if (tx != null) {
tx.rollback();
}
throw e;
}finally {
session.close();
}
}
}
class SaleOrderDao extends BaseDao{
public SaleOrderDao() {
super(SaleOrder.class);
}
#Override
public SaleOrder findSaleOrderById(Long saleOrderId){
SaleOrder so = (SaleOrder)findById(saleOrderId);
return so;
}
#Override
public void saveOrUpdateSaleOrder(SaleOrder so){
saveOrUpdate( so);
}
}
While going through the posts in this forum ,I came across Ryan Stewart's advice that beginning and ending transactions in a dao method is not recommended..Sadly, my project does not use any web framework that supports transaction management..and I am limited to using jsp,servlets and a servlet container..
Is there some way I can rewrite my dao implementations sothat transactions can be managed properly..I couldn't find anything in this regard from those books I read..
Hope somebody helps me with suggestions
sincerely,
Jim
Normally transactions should not be handled in the DAO. They should be handled by the service layer. One service method may include multiple DAO calls that are all in the same transaction.
Spring (as well as other DI frameworks) allows you to do that by simply annotating your service methods with #Transactional. Without spring you can still do that manually in the service layer

Categories

Resources