Spring DAO vs Spring ORM vs Spring JDBC

我正在浏览Spring支持的数据访问技术,我注意到它提到了多个选项,我不确定它们之间的区别:

据我所知,Spring JDBC提供了模板,用于减少用于通过简单的旧方式访问数据库的样板代码 - 您编写自己的SQL查询 .

Spring-ORM提供了通过ORM技术访问数据库的简化模板,如Hibernate,My(i)Batis等 .

Spring-DAO按照Spring的网站:

Spring中的数据访问对象(DAO)支持旨在使您能够以一致的方式轻松使用JDBC,Hibernate或JDO等数据访问技术

我对ORM与JDBC有一点关系,因为它们针对的是访问数据库的不同方式 . 但Spring-DAO简直令人困惑!

有谁能请澄清这三者之间究竟有什么不同?哪种情况应该首选?

此外,还有另一个项目 Spring-DATA 也可用(http://projects.spring.io/spring-data/)现在,它是否是Spring支持的所有数据访问技术的父项目,还是Spring-DAO的新名称?

回答(5)

3 years ago

以下是每种技术的介绍 .

Spring-DAO

Spring-DAO并不是一个严格意义上的 spring 模块,而是应该指示你编写DAO并写好它们的约定 . 因此,它既不提供接口,也不提供实现或模板来访问您的数据 . 在编写DAO时,您应该使用 @Repository 对它们进行注释,以便链接到底层技术(JDBC,Hibernate,JPA等)的异常一致地转换为正确的 DataAccessException 子类 .

例如,假设您现在正在使用Hibernate,并且您的服务层捕获 HibernateException 以便对其做出反应 . 如果您更改为JPA,则DAO接口不应更改,并且服务层仍将使用捕获 HibernateException 的块进行编译,但您永远不会输入这些块,因为您的DAO现在正在抛出JPA PersistenceException . 通过在DAO上使用 @Repository ,链接到底层技术的异常将转换为Spring DataAccessException ;您的服务层捕获这些异常,如果您决定更改持久性技术,Spring仍会抛出相同的Spring DataAccessExceptions ,因为Spring已经翻译了本机异常 .

但请注意,由于以下原因,这限制了使用:

  • 您通常不应该捕获持久性异常,因为提供程序可能已回滚事务(取决于确切的异常子类型),因此您不应该使用备用路径继续执行 .

  • 异常的层次结构通常比Spring提供的更丰富,并且没有从一个提供者到另一个提供者的明确映射 . 依靠这是危险的 . 但是,使用 @Repository 注释DAO是个好主意,因为扫描过程会自动添加bean . 此外,Spring可以为注释添加其他有用的功能 .

Spring-JDBC

Spring-JDBC提供了JdbcTemplate类,它可以删除管道代码并帮助您专注于SQL查询和参数 . 您只需要使用 DataSource 进行配置,然后就可以编写如下代码:

int nbRows = jdbcTemplate.queryForObject("select count(1) from person", Integer.class);

Person p = jdbcTemplate.queryForObject("select first, last from person where id=?", 
             rs -> new Person(rs.getString(1), rs.getString(2)), 
             134561351656L);

Spring-JDBC还提供了一个JdbcDaoSupport,您可以扩展它以开发DAO . 它基本上定义了两个属性:一个DataSource和一个JdbcTemplate,它们都可以用来实现DAO方法 . 它还提供了从SQL异常到spring DataAccessExceptions的异常转换器 .

如果您打算使用普通的jdbc,那么这是您需要使用的模块 .

Spring-ORM

Spring-ORM是一个涵盖许多持久性技术的伞形模块,即JPA,JDO,Hibernate和iBatis . 对于这些技术中的每一种,Spring都提供了集成类,以便按照Spring的配置原则使用每种技术,并与Spring事务管理顺利集成 .

对于每种技术,配置基本上包括将 DataSource bean注入某种 SessionFactoryEntityManagerFactory 等bean . 对于纯JDBC,不需要这样的集成类(除了JdbcTemplate),因为JDBC只依赖于DataSource .

如果你打算使用像JPA或Hibernate这样的ORM,你不需要spring-jdbc,只需要这个模块 .

Spring-Data

Spring-Data是一个伞形项目,提供一个通用API,以更通用的方式定义如何访问数据(DAO注释),涵盖SQL和NOSQL数据源 .

最初的想法是提供一种技术,以便开发人员以技术无关的方式为DAO(finder方法)和实体类编写接口,并且仅基于配置(DAO和实体 spring 配置上的注释,不管是xml) - 或基于java),决定实现技术,无论是JPA(SQL)还是redis,hadoop等(NOSQL) .

如果您遵循spring为finder方法名称定义的命名约定,则甚至不需要为最简单的情况提供与finder方法相对应的查询字符串 . 对于其他情况,您必须在finder方法的注释中提供查询字符串 .

加载应用程序上下文时,spring为DAO接口提供代理,其中包含与数据访问技术相关的所有样板代码,并调用已配置的查询 .

Spring-Data专注于非SQL技术,但仍为JPA(唯一的SQL技术)提供了一个模块 .

What's next

知道这一切,你现在要决定选择什么 . 这里的好消息是,您不需要为该技术做出明确的最终选择 . 这实际上就是Spring的所在:作为开发人员,您在编写代码时专注于业务,如果您做得好,更改底层技术就是实现或配置细节 .

  • 使用POJO类为实体定义数据模型,并使用get / set方法表示实体属性以及与其他实体的关系 . 您肯定需要根据技术对实体类和字段进行注释,但就目前而言,POJO足以开始 . 现在就专注于业务需求 .

  • 定义DAO的接口 . 1 DAO只包含1个实体,但您肯定不需要为每个实体添加DAO,因为您应该能够通过导航关系来加载其他实体 . 按照严格的命名约定定义finder方法 .

  • 基于此,其他人可以开始使用服务层,并为您的DAO进行模拟 .

  • 您将学习不同的持久性技术(sql,no-sql)以找到最适合您需求的技术,并选择其中之一 . 在此基础上,您可以注释实体并实现DAO(或者如果您选择使用spring-data,请让Spring为您实现) .

  • 如果业务需求发展并且您的数据访问技术不足以支持它(比如,您从JDBC和一些实体开始,但现在需要更丰富的数据模型而JPA是更好的选择),您将不得不更改实现您的DAO,在您的实体上添加一些注释并更改spring配置(添加EntityManagerFactory定义) . 其余的业务代码不应该看到您的更改带来的其他影响 .

Note : Transaction Management

Spring提供了一个用于事务管理的API . 如果您计划使用spring进行数据访问,那么您还应该使用spring进行事务管理,因为它们很好地集成在一起 . 对于spring支持的每种数据访问技术,都有一个匹配的事务管理器用于本地事务,或者如果需要分布式事务,则可以选择JTA . 所有这些都实现了相同的API,因此(再一次)技术选择只是一个可以在不对业务代码产生进一步影响的情况下进行更改的配置 .

Note : Spring documentation

您提到的Spring文档的链接相当陈旧 . 以下是最新版本的文档(4.1.6,涵盖所有主题):

Spring-data不是Spring框架的一部分 . 有一个共同的模块,您应该首先阅读以习惯这些原则 . 文档可以在这里找到:

3 years ago

Spring DAOD ata A ccess O bject):是一个为JDBC实现框架提供抽象接口的对象,即Spring DAO是 generalized 概念,用于访问JDBC和Hibernate,MyBatis,JPA,JDO使用它的各个Support类 . 它通过定义 @Repository 注释提供 generalized 异常层次结构 . 这个注释定义为Spring容器SQL exception translationSQLException到Spring的数据访问策略 - 不可知DataAccessException层次结构 .

例如,特定于平台的异常是捕获,然后作为Spring未经检查的数据访问异常之一重新抛出 .


Spring JDBC :对于普通JDBC,我们使用此模块,它仅依赖于 DataSource 和模板类,如 JdbcTemplateNamedParameterJdbcTemplate (包裹 JdbcTemplate )和 SimpleJdbcTemplate ,以减少交叉切割问题 .

public class EmployeeDao {  
private JdbcTemplate jdbcTemplate;  

public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {  
    this.jdbcTemplate = jdbcTemplate;  
}  

public int saveEmployee(Employee e){  
    return jdbcTemplate.update(query);  
}  
public int updateEmployee(Employee e){  
    return jdbcTemplate.update(query);  
}  
public int deleteEmployee(Employee e){  
       return jdbcTemplate.update(query);  
}  

}

在Spring XML中:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>

Spring JDBC还提供 JdbcDaoSupportNamedParameterJdbcDaoSupportSimpleJdbcDaoSupport ,这是支持(即 convenient )扩展和开发我们自己的DAO抽象接口的方法,如下所示:

public interface EmployeeDao {

    public void saveEmployee(Employee emp);
}

public class EmployeeDaoImpl extends JdbcDaoSupport implements EmployeeDao{

    @Override
    public void saveEmployee(Employee emp) {

        Object[] inputs = new Object[] {emp.getName(), emp.getSalary(), emp.getDept()};
        getJdbcTemplate().update(query, inputs);
    }
}

并在 Spring 季XML:

<bean id="employeeDAO" class="EmployeeDaoImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>

Spring ORM: 对于ORM工具支持,如Hibernate,JPA,MyBatis ......通过注入 DataSource 以及以下类和各自的 DaoSupport 类,可以轻松集成Spring .

  • SessionFactory for Hibernate
    JPA的

  • EntityManagerFactory

  • SqlSessionFactory for MyBatis

3 years ago

您创建类似 SomeObjectDao 的接口,然后创建此接口的不同实现,如 JdbcSomeObjectDaoHibernateSomeObjectDao . 然后在 SomeObjectService 类中,您将在 SomeObjectDao 接口上操作,并在其中注入一个具体实现 . 所以 SomeObjectDao 的每个实现都会隐藏细节,无论你使用JDBC还是ORM等 .

通常是JDBC,ORM的不同实现会抛出不同类型的异常 . Spring的DAO支持可以将这些不同的,特定于技术的异常映射到常见的Spring DAO异常 . 所以你与实际的实现分离得更多 . 此外,Spring的DAO支持提供了一组抽象的 *DataSupport 类,这些类在DAO开发中更有帮助 . 因此,除了实现 SomeObjectDao 接口之外,您还可以扩展Spring的 *DataSupport 类之一 .

3 years ago

作为附加信息 . 我建议你使用Spring Data JPA . 使用诸如:@Repository,@ Service之类的语法 . 我给你举个例子:

@Repository("customerEntitlementsRepository")
public interface CustomerEntitlementsRepository extends CrudRepository<BbsExerul, BbsExerulPK> {

  @Query(value = "SELECT " + "CONTRACT_NUMBER, EXECUTIVE_NUMBER, " + "GROUP_VALUE, " + "CODE, "
      + "SUBCODE, " + "CURRENCY " + "FROM BBS_EXERUL " + "WHERE CONTRACT_NUMBER =:clientId AND "
      + "EXECUTIVE_NUMBER =:representativeId", nativeQuery = true)
  Collection<CustomerEntitlementsProjection> getFieldsExerul(@Param("clientId") String clientId,
      @Param("representativeId") String representativeId);

}

CustomerEntitlementsProjection是Spring投影,与您的实体或DTO pojo链接;

@Projection(name = "customerEntitlementsProjection", types = { BbsExerul.class })
public interface CustomerEntitlementsProjection {

  String getContractNumber();

  String getExecutiveNumber();

3 years ago

spring-dao lib在版本2 . 0 . 8(2008年1月)中停止 . spring-dao中的类被复制到spring-tx . 因此,如果您需要在spring-dao中找到的类,请将依赖项添加到spring-tx . (Source . )