【问题标题】:Some doubts about how implement Hibernate DAO in Spring applicationsSpring应用中如何实现Hibernate DAO的一些疑惑
【发布时间】:2013-02-24 20:31:36
【问题描述】:

我是 Spring 世界的新手,我正在尝试开发一个将 Spring 与 Hibernate 集成的 DAO。我已经创建了一个工作项目,但我对它有一些架构上的疑问。

我基于以下独立的 Hibernate 教程创建了我的 Spring + Hibernate 项目(独立,因为它不使用 Spring 或其他框架,它是一个简单的 Java + Hibernate 项目):http://www.tutorialspoint.com/hibernate/hibernate_examples.htm

在我的项目中,我有一个接口,我在其中定义了我需要的所有 CRUD 方法以及该接口的具体实现,这是我的具体类的代码:

package org.andrea.myexample.HibernateOnSpring.dao;

import java.util.List;

import org.andrea.myexample.HibernateOnSpring.entity.Person;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.springframework.transaction.annotation.Transactional;

public class PersonDAOImpl implements PersonDAO {

    // Factory per la creazione delle sessioni di Hibernate:
    private static SessionFactory sessionFactory;

    // Metodo Setter per l'iniezione della dipendenza della SessionFactory:
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /** CREATE CRUD Operation:
     * Aggiunge un nuovo record rappresentato nella tabella rappresentato
     * da un oggetto Person
     */
    @Transactional(readOnly = false)
    public Integer addPerson(Person p) {

        System.out.println("Inside addPerson()");

        Session session = sessionFactory.openSession();

        Transaction tx = null;
        Integer personID = null;

        try {
            tx = session.beginTransaction();

            personID = (Integer) session.save(p);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null)
                tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }

        return personID;

    }

    // READ CRUD Operation (legge un singolo record avente uno specifico id):
    public Person getById(int id) {

        System.out.println("Inside getById()");

        Session session = sessionFactory.openSession();

        Transaction tx = null;          
        Person retrievedPerson = null;  

        try {
            tx = session.beginTransaction();
            retrievedPerson = (Person) session.get(Person.class, id);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {                 
            session.close();
        }

        return retrievedPerson;
    }

    // READ CRUD Operation (recupera la lista di tutti i record nella tabella):
    @SuppressWarnings("unchecked")
    public List<Person> getPersonsList() {

        System.out.println("Inside getPersonsList()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;
        List<Person> personList = null;

        try {
            tx = session.beginTransaction();
            Criteria criteria = session.createCriteria(Person.class);
            personList = criteria.list();
            System.out.println("personList: " + personList);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }
        return personList;
    }

    // DELETE CRUD Operation (elimina un singolo record avente uno specifico id):
    public void delete(int id) {

        System.out.println("Inside delete()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            tx = session.beginTransaction();
            Person personToDelete = getById(id);
            session.delete(personToDelete);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

    @Transactional
    public void update(Person personToUpdate) {

        System.out.println("Inside update()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            System.out.println("Insite update() method try");
            tx = session.beginTransaction();
            session.update(personToUpdate);

            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }   

    }

}

1) 第一个疑问与在这个类中,对于每个 CRUD 方法我打开一个新会话有关。

我之所以这样做,是因为在本教程中:http://www.tutorialspoint.com/hibernate/hibernate_sessions.htm 我已经阅读:

Session 对象是轻量级的,旨在在每次需要与数据库交互时实例化。持久对象通过 Session 对象进行保存和检索。 会话对象不应长时间保持打开状态,因为它们通常不是线程安全的,应根据需要创建和销毁它们。

但是后来有人说我集成 Spring 和 Hibernate 我不需要在每个 CRUD 方法中打开一个新会话,因为如果我将 @Transactional 注释添加到所有 CRUD 方法中,会话已被 Spring 关联到当前事务,并且该事务也将在事务结束时由 Spring 关闭。每次打开/关闭事务时,Spring 都会打开和关闭一个会话。

所以,如果是真的,我只需要打开一次会话,然后获取当前会话。

这是真的还是我的具体课程是正确的(它运作良好但我不知道它是否以愚蠢的方式运作!!!)

2)第二个疑问与阅读Spring文档有关:http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#orm-hibernate我发现它使用了可以调用DAO的AOP服务......

所以...是我的架构这么糟糕吗?我有一个接口,表示我的 DAO 和使用 Hibernate 实现 DAO 的具体类,我称它为在 DB 上执行 CRUD 操作的方法

【问题讨论】:

  • 如果你不相信上一个问题的答案,这个问题是由有很高声誉的人(我)给出的,在弹簧标签上获得了 667 分,已被投票 5 次,哪个指向相关的Spring文档,你为什么要问另一个类似的问题?为什么你会相信这个答案?
  • 顺便说一句:你应该看看 Spring-Data(-JPA) springsource.org/spring-data/jpa
  • @JBNizet 我只知道有一些不同的方法可以做同样的事情,没有什么私人的,我已经检查了你的答案:-)

标签: java spring hibernate spring-mvc


【解决方案1】:

关于#1。是的,当您在 DAO 的 CRUD 操作方法中使用 @Transactional 注释时,您不需要显式处理会话的打开和关闭。春天为你做到了。你需要做的就是在当前会话上调用 CRUD 方法,该方法是通过调用sessionFactory.getCurrentSession() 获得的。无需像在上面的代码中那样显式地打开、提交和回滚事务。当您使用 @Transactional 注释方法时,Spring 会为您执行此操作。

关于#2。 Spring 有自己的方式来实现您的 DAO 实现。它可能正在使用AOP。这并不意味着您的架构是错误的。使用接口和具体类实现的架构是正确的方法。我要做的是让所有的 CRUD 操作由一个基类实现,然后让子类实现 DAO 特定的方法。我的意思是这个(只给出伪代码):

interface BaseDAO {//declare all the CRUD methods}

interface PersonaDAO extends BaseDAO {//declare all Person related methods like getPersonsList}

class BaseDAOImpl implements BaseDAO {//CRUD method implementations }

class PersonaDAOImpl extends BaseDAOImpl implements PersonDAO {//implementation of Person related methods}

这个,我觉得会是一个更好的arch,让你可以复用CRUD操作代码。希望这会有所帮助。

【讨论】:

  • Tnx 这么多...是的,我有相同的架构:一个 PersonDAO 接口,我在其中声明了 CRUD 方法和实现此接口的 PersonDAOImpl 具体类及其方法 :-) 现在我将尝试使用 getCurrentSession() 方法。只有最后一个问题。我必须在我的具体课程中在哪里打开我的会话? Tnx 安德里亚
  • 您不需要打开任何会话。您需要将 SessionFactory 注入 DAO 并执行 sessionFactory.getCurrentSession() 来获取会话。让 Spring 为你做的一切都休息一下。
  • 不要工作...我在这里打开了另一个详细的帖子,如果你愿意,你能帮我吗? stackoverflow.com/questions/15309427/…
猜你喜欢
  • 1970-01-01
  • 2012-09-25
  • 2013-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-21
  • 2015-02-04
相关资源
最近更新 更多