Spring DAO与Spring ORM与Spring JDBC


103

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

据我了解,Spring JDBC提供了用于减少样板代码的模板,这些样板代码通过普通的旧方法(您编写自己的SQL查询)来访问数据库。

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

根据Spring网站的Spring-DAO:

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

我对ORM与JDBC比较了解,因为它们针对的是访问数据库的不同方式。但是Spring-DAO简直令人困惑!

谁能说明这三个之间到底有什么区别?在哪种情况下应首选哪个?

另外,还有另一个项目Spring-DATAhttp://projects.spring.io/spring-data/)现在,它是Spring支持的所有数据访问技术的父项目,还是Spring的新名称? -老兄?

Answers:


162

这是对每种提到的技术的介绍。

春道

从严格意义上讲,Spring-DAO并不是弹簧模块,而是约定,它们应指导您编写DAO并进行良好的编写。因此,它既不提供接口,也不提供实现或模板来访问您的数据。编写DAO时,应使用它们进行注释,@Repository以便将与基础技术(JDBC,Hibernate,JPA等)链接的异常一致地转换为适当的DataAccessException子类。

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

但是请注意,由于以下原因,此方法的使用受到限制:

  1. 您通常不应捕获持久性异常,因为提供程序可能已回滚事务(取决于确切的异常子类型),因此,不应使用替代路径继续执行。
  2. 提供程序中的异常层次结构通常比Spring提供的丰富,并且从一个提供程序到另一个提供程序之间没有明确的映射。依靠它是危险的。但是,用注释您的DAO是一个好主意@Repository,因为Bean将由扫描过程自动添加。此外,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事务管理平滑地集成。

对于每种技术,配置基本上都包括将DataSourcebean注入某种SessionFactoryEntityManagerFactory诸如此类的bean中。对于纯JDBC,不需要此类集成类(JdbcTemplate除外),因为JDBC仅依赖于数据源。

如果您打算使用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 power所在的位置:作为开发人员,您在编写代码时会专注于业务,如果做得好,更改底层技术就是实现或配置细节。

  1. 使用实体的POJO类定义数据模型,并获取/设置方法以表示实体属性以及与其他实体的关系。当然,您将需要基于该技术注释实体类和字段,但是从现在开始,POJO就足够了。现在只专注于业务需求。
  2. 为您的DAO定义接口。1个DAO恰好覆盖了1个实体,但是您肯定不需要为每个实体创建DAO,因为您应该能够通过导航关系来加载其他实体。遵循严格的命名约定定义finder方法。
  3. 基于此,其他人可以开始使用DAO的模拟进行服务层工作。
  4. 您将学习不同的持久性技术(sql,no-sql)以找到最适合您的需求,然后选择其中一种。基于此,您可以注释实体并实现DAO(或者,如果您选择使用spring-data,则让spring为您实现它们)。
  5. 如果业务需求发生变化,而您的数据访问技术不足以支持它(例如,您从JDBC和一些实体开始,但现在需要更丰富的数据模型,而JPA是更好的选择),则必须更改实现在您的DAO中,在您的实体上添加一些注释并更改弹簧配置(添加EntityManagerFactory定义)。您的其余业务代码不应看到更改带来的其他影响。

注意:交易管理

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

注意:Spring文档

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

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


我在这里的某些描述(例如Spring Data)中使用术语“伞”表示赞赏,因为它标识其中包含子组件/模块(而不是伞针对特定领域)。即使在问题中未提及,在这里在上下文中提及Spring Data也非常有用。
cellepo

是否没有spring-jdbc提供此处未提及的其他有用工具?例如,我发现SimpleJdbcInsert对于单次插入以及批量插入(非常合理的规模)都非常干净和有用。
Nom1fan

3

春天DAOd ATA 一个 CCESS Ø bject):是提供的抽象接口JDBC执行框架的目标,即春季DAO是 广义使用它的个性化支持类概念访问JDBC和Hibernate,MyBatis的,JPA,JDO。并且通过定义注释来提供广义的异常层次结构@Repository。该批注定义了Spring容器,用于将SQL异常转换SQLException与Spring的数据访问策略无关的 DataAccessException层次结构。

即,特定于平台的异常被捕获,然后作为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>

春天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:对于ORM工具支持,例如Hibernate,JPA,MyBatis ...通过DataSource与以下类和相应DaoSupport类一起注入,可以轻松集成Spring 。

  • SessionFactory 对于休眠
  • EntityManagerFactory 对于JPA,
  • SqlSessionFactory 对于MyBatis

1

spring-dao lib在版本2.0.8(2008年1月)中停止。spring-dao中的类已复制到spring-tx。因此,如果您需要在spring-dao中找到的类,请改为将依赖项添加到spring-tx。(来源。)


0

你创建了界面SomeObjectDao,然后创建这样的接口的不同实现JdbcSomeObjectDaoHibernateSomeObjectDao。然后,在您的SomeObjectService课堂上,您将在SomeObjectDao接口上进行操作,并在其中注入具体的实现之一。因此SomeObjectDao,无论您使用JDBC还是ORM等,的每个实现都会隐藏细节。

通常,JDBC和ORM的不同实现会引发不同类型的异常。Spring的DAO支持可以将这些不同的,特定于技术的异常映射到常见的Spring DAO异常。因此,您与实际的实现方式脱钩的更多。Spring的DAO支持还提供了一组抽象*DataSupport类,这些类在DAO开发中提供了更多帮助。因此,除了实现您的SomeObjectDao接口之外,您还可以扩展Spring的*DataSupport类之一。


所以你的意思是,spring-dao提取了特定于Hibernate / JDO / JDBC的异常,并提供了一组标准的异常?它有什么templates可以访问数据库的吗?还是与其他spring组件一起使用的抽象?例如,可以编写仅使用spring-dao来访问db的代码(不使用spring-jdbc,spring-orm,hibernate或任何其他框架)吗?
专利

0

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

1
请以代码块的格式设置代码,以使其可读。
某些性能
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.