Hibernate 和 Spring - 道,服务

Posted

技术标签:

【中文标题】Hibernate 和 Spring - 道,服务【英文标题】:Hibernate and Spring - Dao ,Services 【发布时间】:2013-05-09 00:15:04 【问题描述】:

我一直在阅读一些教程,我可以看到大多数 MVC 实现

基于:

1) 一个dao接口,例如“IUserDao”

2) 该接口的 dao impl - “mySimpleUserDaoImpl”

3) 持久化服务接口:“IUserService”

4) 和一个 impl - "UserServiceImpl"

这是最佳做法吗?我的意思是我问这个问题的原因是因为有 30 个服务与 getXById()、deleteX(x)、createX(x) 方法或多或少相同,这似乎是多余的。

请考虑到我使用的是 spring 3 和 hibernate 4,我决定在开始用代码敲击键盘之前先问这个问题

谢谢。

【问题讨论】:

您可以删除接口的I 前缀。用户不应该知道它正在获取一个界面。打电话给他们UserDAOUserService 同意,将 I 放在接口上。我个人称我的 Dao classes Repositories 只是为了使其与 Spring Annotations 保持一致,但这并不重要。 技术教程通常不涉及业务逻辑,因此它们不是很好的参考。 ***.com/q/3688664/217324有一个类似的问题可能对你有帮助 关于服务层的另一件事是你的@Transaction 应该从哪里开始。因此,如果您想跨多个存储库回滚事务,则可以在服务层执行此操作。这就是为什么服务应该与存储库是一对多的。 【参考方案1】:

如果您刚刚开始开发,请查看Spring JPA。服务应该是一对多存储库 (DAO)。但我也不会再手动创建所有样板代码。 Spring JPA 消除了基本的 CRUD 和搜索功能以及分页。

Here is a video 遍历 Spring、JPA、Hibernate 的所有配置,并以 Spring Data JPA 结束,向您展示所有已消除的样板代码。

要使用 Spring Data JPA,你的存储库接口最终是:

package com.mysampleapp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.wcfgroup.model.Employee;

@Repository("employeeRepository")
public interface EmployeeRepository extends JpaRepository<Employee, Long> 
    Employee findBySsn(String ssn);

然后XML配置使用Spring Data JPA:

<jpa:repositories base-package="com.mysampleapp.repository"/>

现在为您处理所有样板代码。您不再需要创建具有查找方法和基本 CRUD 功能的基本存储库类。 JpaRepository 接口提供了许多不错的功能,您无需为实现做任何事情。

【讨论】:

关于服务层的另一件事是你的@Transaction 应该开始。因此,如果您想跨多个存储库回滚事务,则可以在服务层执行此操作。这就是为什么服务应该与存储库是一对多的。【参考方案2】:

每个模型都必须有 dao、daoImpl、service、serviceImpl。

用户道 UserDaoImpl 用户服务 UserServiceImpl

您可以使用通用类 EntityDaoImpl 和接口 EntityDao,如下所示:

实体道:

public interface EntityDao<E> 

void persist(E e) throws Exception;

void remove(Object id) throws Exception;

E findById(Object id) throws Exception;

EntityDaoImpl:

public class EntityDaoImpl<E>  implements EntityDao<E> 

@PersistenceContext(unitName="UnitPersistenceName")
protected EntityManager entityManager;

protected E instance;
private Class<E> entityClass;

@Transactional
public void persist(E e) throws HibernateException     
    getEntityManager().persist(e);

    @Transactional
public void remove(Object id) throws Exception     
    getEntityManager().remove((E)getEntityManager().find(getEntityClass(), id));


public E findById(Object id) throws Exception      
    return (E)getEntityManager().find(getEntityClass(), id);    

    public EntityManager getEntityManager() 
    return entityManager;

public void setEntityManager(EntityManager entityManager) throws Exception
    this.entityManager = entityManager;


    public Class<E> getEntityClass() throws Exception      
   if (entityClass == null) 
            Type type = getClass().getGenericSuperclass();
          if (type instanceof  ParameterizedType) 
          
              ParameterizedType paramType = (ParameterizedType) type;
              if (paramType.getActualTypeArguments().length == 2) 
                    if (paramType.getActualTypeArguments()[1] instanceof  TypeVariable) 
                       throw new IllegalArgumentException(
                          "Can't find class using reflection");
                   
                    else 
                       entityClass = (Class<E>) paramType.getActualTypeArguments()[1];
                  
                else 
                  entityClass = (Class<E>) paramType.getActualTypeArguments()[0];
                
            else 
              throw new Exception("Can't find class using reflection");
          
        
       return entityClass;
   

你可以这样使用:

public interface UserDao extends EntityDao<User> 


public class UserDaoImpl extends EntityDaoImpl<User> implements UserDao


【讨论】:

所有这些代码本质上都是 Spring Data Jpa 为您提供的:springsource.org/spring-data/jpa 这段代码实际上有一些错误,你不想在 DAO/Repository 层开始你的事务。【参考方案3】:

没有,没有必要有 30 个服务层或 30 个 dao 层。您应该指定层,而不是考虑实体,而是考虑业务功能。可以有 5 或 6 个与某些功能相关的实体,这些实体应该在一层。但是如果需要,您仍然必须在这些冗余层中拥有 getXById()、deleteX(x)、createX(x)。

【讨论】:

【参考方案4】:

为每个模型创建单独的服务是实现此目的的一种方法,我已经看到了这样做的实际应用程序,但我不推荐这样做。这对于简单的 CRUD 案例来说是多余的,对于更复杂的案例(您实际上希望事务跨越多个 DAO 调用)没有帮助。它给你留下了很多无用的代码。可以使用 Spring Data 指定 DAO,服务将是样板文件,每个方法都包装对 DAO 的调用。 Spring 应该有助于减少样板文件,而不是强制它。

如果您有一个完全 CRUD 应用程序,那么您可以合法地不使用服务,将 @Transactional 放在 DAO 上,并从控制器调用 DAO。如果服务没有发挥作用,请摆脱它。

如果您在应用程序中确实有实际的业务逻辑,那么当用户调用可能涉及调用不同 DAO 的某些内容时,这些调用通常应该在同一个事务中进行,这样如果某件事失败,一切都会回滚。 (此外,创建事务相对昂贵,如果您有一个控制器为不同的实体调用不同的服务,那么这将很慢。)这就是服务派上用场的地方,服务指定用户想要的低级用例执行并允许指定事务行为。

对于 CRUD 案例,我更喜欢使用 Grails 或 Play 或 Rails 之类的工具,而不是使用 Spring MVC 编写 Java。例如,Grails 将为您生成视图和控制器,通过 GORM 提供基本的数据访问(因此无需编写 DAO),并且可以让您轻松地为您发现需要它们的情况指定服务。

【讨论】:

以上是关于Hibernate 和 Spring - 道,服务的主要内容,如果未能解决你的问题,请参考以下文章

Spring 和 Hibernate Restful web 服务配置

spring三大核心学习---控制反转

Hibernate 5.x和Spring Data 2.x:如何在服务保存方法中更新原始对象

在DAO,服务层架构中使用spring MVC和Hibernate的正确方法是啥

全网最全Spring系列面试题129道(附答案解析)

如何使用 Spring 和 Hibernate 为 Web 应用程序和批处理作业设置事务