ChatGPT解决这个技术问题 Extra ChatGPT

Spring DAO vs Spring ORM vs Spring JDBC

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

Spring-DAO (http://docs.spring.io/spring/docs/2.0.8/reference/dao.html)

Spring-ORM (http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/orm.html)

Spring-JDBC (http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html)

据我了解,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 的新名称?


c
cellepo

以下是对每个提到的技术的介绍。

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 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。它基本上定义了 2 个属性:一个 DataSource 和一个 JdbcTemplate,它们都可用于实现 DAO 方法。它还提供了一个从 SQL 异常到 Spring DataAccessExceptions 的异常转换器。

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

弹簧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 是一个伞形项目,它提供了一个通用 API 来定义如何以更通用的方式访问数据(DAO + 注释),涵盖 SQL 和 NOSQL 数据源。

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

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

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

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

下一步是什么

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

使用实体的 POJO 类定义数据模型,并使用 get/set 方法来表示实体属性以及与其他实体的关系。您当然需要根据技术对实体类和字段进行注释,但目前,POJO 已经足够开始了。现在只关注业务需求。为您的 DAO 定义接口。 1 个 DAO 恰好涵盖 1 个实体,但您当然不需要为每个实体创建一个 DAO,因为您应该能够通过导航关系来加载其他实体。遵循严格的命名约定定义查找器方法。基于此,其他人可以开始在服务层上工作,并为您的 DAO 提供模拟。您学习不同的持久性技术(sql、no-sql)以找到最适合您需求的技术,并从中选择一种。基于此,您注释实体并实现 DAO(如果您选择使用 spring-data,则让 spring 为您实现它们)。如果业务需求不断发展,而您的数据访问技术不足以支持它(例如,您从 JDBC 和一些实体开始,但现在需要更丰富的数据模型,而 JPA 是更好的选择),您将不得不更改实现在您的 DAO 中,在您的实体上添加一些注释并更改 spring 配置(添加 EntityManagerFactory 定义)。您的其余业务代码不应看到您的更改带来的其他影响。

注意:事务管理

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

注意:弹簧文档

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

单个html页面:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/

PDF:http://docs.spring.io/spring/docs/current/spring-framework-reference/pdf/spring-framework-reference.pdf

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

单个html页面:http://docs.spring.io/spring-data/data-commons/docs/1.9.2.RELEASE/reference/html/

PDF:http://docs.spring.io/spring-data/data-commons/docs/1.9.2.RELEASE/reference/pdf/spring-data-commons-reference.pdf


我很欣赏这个答案,在此处的某些描述(如 Spring Data)中使用术语“伞”,识别其中有子组件/模块(而不是更特定于域的伞)。在这里提到 Spring Data 在上下文中非常有用,即使问题中没有提到它。
spring-jdbc 是否提供了此处未提及的其他有用工具?例如,我发现 SimpleJdbcInsert 对于单项插入和批量(当然,达到合理的规模)都非常干净和有用。
P
Premraj

Spring DAO(Data Access Object):是一个对象,为JDBC实现提供抽象接口框架,即 Spring DAO 是 通用 概念,可以使用其单独的 Support 类访问 JDBC 和 Hibernate、MyBatis、JPA、JDO。它通过定义 @Repository 注释提供通用异常层次结构。此注释定义了从 SQLException 到 Spring 的数据访问策略不可知 DataAccessException 层次结构的 SQL exception translation 的 Spring 容器。

即在持久框架、代码之间轻松切换,而无需担心捕获特定于每种技术的异常。

Spring JDBC:对于普通的 JDBC,我们使用这个模块,它只依赖于 DataSource 和模板类,如 JdbcTemplateNamedParameterJdbcTemplate(wraps 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,它们是支持(即方便)的方式来扩展和开发我们自己的 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);
    }
}

在春季 XML 中:

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

Spring ORM:对于诸如 Hibernate、JPA、MyBatis 等 ORM 工具的支持...通过注入 DataSource 以及以下类和相应的 DaoSupport 类轻松集成 Spring。

用于休眠的 SessionFactory

JPA 的 EntityManagerFactory,

MyBatis 的 SqlSessionFactory


m
mike_m

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

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


所以你的意思是,spring-dao 抽象出特定于 Hibernate/JDO/JDBC 的异常并提供一组标准的异常?是否有任何 templates 可以访问数据库?还是只是与其他弹簧组件一起使用的抽象?例如,是否可以编写仅使用 spring-dao 访问 db 的代码(不使用 spring-jdbc、spring-orm、hibernate 或任何其他框架)?
P
Paulo Merson

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


B
Brandon Osorio

作为附加信息。我建议你使用 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();

请在代码块中格式化您的代码,使其可读。