【问题标题】:service layer are bound to DB tecnology in a spring application服务层在spring应用中绑定了DB技术
【发布时间】:2026-01-28 07:15:01
【问题描述】:

我的问题是:您的服务层是否与您使用的技术绑定?

例如,如果您使用休眠,则将一些仅作为休眠功能的 hql 查询或条件查询放入服务层,或者您只需调用 DAO(并且 dao 具有休眠实现,可能还有 jdbc 实现等。) ?

我在为我的软件构建有效的分层架构时遇到了一些麻烦。

编辑 这是一项简单的服务……我认为这是一项服务……不受我使用的技术的约束(休眠)

@Repository
public class PersonHibernateDAO implements PersonDAO {

    @Autowired
    SessionFactory sessionFactory;

    ... dao crud operations(implementation of PersonDAO interface) using sessionfactory ...

    //and some hibernate features methods
    public Person findByCriteria(Criterion criterion){
        // code
    }
}

@Service
public class PersonService {

    @Autowired
    private PersonDAO personDao;

    @Autowired
    private AccessDAO accessDao;

    @Transactional
    public boolean hasPermission(String username, String accessCode){
        Person p=personDao.findByUsername(username);
        Access a=accessDao.findByCode(accessCode);
        ... etc ...
    }
}

这是一个使用 Dao 实现的服务

@Service
public class PersonService {

    @Autowired
    private PersonDAO personDao;

    @Autowired
    private AccessDAO accessDao;

    @Transactional
    public boolean hasPermission(String username, String password){
        Person p=((PersonHibernateDao)personDao).findByCriteria(Restrictions.eq("username", username);
        ... etc ...
    }
}

这两种方法哪个是正确的?


EDIT2

所以,总结一下我的理解:

// BASE DAO INTERFACE
public interface DAOInterface<EntityClass, IDType extends Serializable> {
    EntityClass get(IDType id);
    EntityClass findById(IDType id);
    EntityClass save(EntityClass entity);
    EntityClass update(EntityClass entity);
    void delete(EntityClass entity);
}

// AN HIBERNATE IMPLEMENTATION
public abstract class HibernateDAO<EntityClass, IDType extends Serializable> implements DAOInterface<EntityClass, IDType> {

    @Autowired
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory){
        this.sessionFactory=sessionFactory;
    }

    public void getSessionFactory(){
        return this.sessionFactory;
    }

    // Implements all DAOInterface method using sessionFactory

}

// PERSON DAO INTERFACE
public interface PersonDAO extends DAOInterface<Person, Long>{

    Person findByName(String name, String surname);
    List<Person> getInAgeRange(int year1, int year2);
}

// PERSON HIBERNATE DAO IMPLEMENTATION
public PersonHDAO extends HibernateDAO<Person, Long> implements PersonDAO{

    // Implements the methods of PersonDAO interface using sessionFactory
}

@Service
public class PersonService {

    //spring inject the correct DAO by its xml config(in this case PersonHDAO
    @Autowired
    private PersonDAO personDAO; 

    // spring manage the transaction
    @Transactional
    public List<Person> getInAgeRange(int year1, int year2){
        return personDAO.getInAgeRange(year1, year2);
    }

}

// NOW... HOW USE IT
//let's assume i have a button, pressing it a table will be populated with all persons in age range
private void actionPerfom(ActionEvent e){
    List<Person> list=personService.getInAgeRange(age1Spinner.getValue(), age2Spinner.getValue());
    //Load a table with list
}

很抱歉这堵文字墙,我希望可能对其他人有用,我朝着正确的方向前进? 我的服务层需要接口吗? 都是正确分层的吗?我也需要控制层?

谢谢。

【问题讨论】:

  • 第一个!!!第二个太糟糕了!!!!
  • 我添加了更多信息,我做得对吗?
  • 看起来不错。我倾向于在整个代码库中使用相同的 ID 类型,所以我只会使用例如很长,因此在 dao 中只有一个通用参数,但您的版本更灵活。

标签: java hibernate spring service-layer


【解决方案1】:

我的建议:

对于较大的项目,请使用基于接口的专用 DAO 层。不要让您的服务层知道任何有关底层持久性技术的信息。只在 DAO 层使用 Hibernate / JPA / JDBC / JDO / 任何东西。

对于较小的项目,可能只有一个服务层是可以的(特别是考虑到 Hibernate Session 和 JPA EntityManager 都公开了大多数标准 DAO 行为。

基本经验法则:如果您要进行技术更改,请确保您只需要更改应用程序的一层

更新:这是一个示例 DAO 界面。您的服务层只会针对此接口进行编码,而实现将执行 session / entityManager / jdbc 调用,而无需服务层知道。

public interface CustomerDao extends CommonDao<Customer>{
    Customer getCustomerByEmail(String emailAddress);
    List<Customer> getCustomersWithinAgeRange(int lowerBound, int upperBound);
}

关键:在你的服务层,基于接口指定你的依赖,即

private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao){
    this.customerDao = customerDao;
}

而不是

// this is horrible, it ties the service layer to implementation
// details of the dao layer
private HibernateCustomerDaoImpl customerDao;
public void setCustomerDao(HibernateCustomerDaoImpl customerDao){
    this.customerDao = customerDao;
}

【讨论】:

  • 好的,但是我的服务层“知道”我使用的技术吗?我不能很好地解释我......例如,如果我使用休眠,我的 HibDaoImplementation 有一些“findByCriteria”,但 dao 接口没有(因为 JDBC 实现没有标准)所以,在我的服务中,我只能有我的 dao 接口还是我可以使用 dao 实现?我编辑了我的第一篇文章。
【解决方案2】:

DAO 是任何数据库特定查询的地方 - 在您的情况下是 JDBC 或 Hibernate。

服务层旨在向消费者提供 API,例如表示层或其他层。没有理由用数据库细节污染服务层。您的服务层可能具有很好的业务逻辑,但它不应该知道底层数据库实现 IMO

【讨论】:

  • 谢谢你,我想是这样,但例如在我看到的所有例子中,我看到的一个 dao 都只放入了 CRUD 操作。假设我必须按姓名、姓氏和出生日期查找一些记录,我必须向我的 dao 或我的服务层添加一个方法?
  • @blow:@seanizer 更好地回答了这个问题。您将为任何 CRUD 和非 CRUD 方法“编写接口代码”,然后通过 Spring 将 DAO 接口注入服务。
最近更新 更多