Pat 的疑惑
最近关注于 Spring 提供的数据访问技术,对于 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 提供了通过 ROM 技术访问数据库的简化样板,比如 Hibernate,My(i)Batis 等等。
Spring 官网介绍的 Spring-DAO:
Spring 提供的数据访问对象(DAO)技术旨在以一个一致的方式轻松使用不同的数据访问技术诸如 JDBC,Hibernate 或者 JDO。
关于 ORM vs JDBC 我清楚一点,因为它们都用于以不同的方式访问数据库。但对于 Spring-DAO 我是晕头转向了。
有没有朋友把这三者之间的区别帮忙澄清一下?每个应该首选应用于什么场景?
此外,Spring 现在还出了另外一个项目 Spring-DATA,它是 Spring 提供的所有数据访问技术的一种父项目,还是只是 Spring-DAO 的一个新名字?
Gaetan 的解释
关于以上提到的每个技术的解释。
Spring-DAO
Spring-DAO 并非 Spring 的一个模块,它实际上是指示你写 DAO 操作、写好 DAO 操作的一些规范。因此,对于访问你的数据它既没有提供接口也没有提供实现更没有提供模板。在写一个 DAO 的时候,你应该使用
@Repository 对其进行注解,这样底层技术(JDBC,Hibernate,JPA,等等)的相关异常才能一致性地翻译为相应的
DataAccessException 子类。
举个例子,假设你正在使用 Hibernate,你的服务层捕获
HibernateException 以进行相关处理。如果你改为 JPA,你的 DAO 接口不应该也发生改变,服务层仍旧编译捕捉
HibernateException 的代码块,但是你永远不会再进入这些代码块,因为你的 DAO 现在抛出的是 JPA 的
PersistenceException。通过在你的 DAO 上使用
@Repository,底层技术相关的异常统统解释为 Spring 的
DataAccessException;你的服务层能够捕获到这些异常,而且如果你想要更换持久层技术,因为 Spring 翻译了本地异常所以仍然会抛出同样的 Spring
DataAccessException。
但注意由于以下原因这种用法是受限的:
- 你不应该在持久层捕捉异常,因为底层技术可能已经将事务进行了回滚(取决于具体的 exception 类型),因此你不应该再(在持久层)继续执行你的备用方案。
- 底层技术提供的异常级别往往比 Spring 提供的更加丰富,而且底层技术之间也没有任何限定来对此进行匹配。这样的依赖是有风险的。但是对你的 DAO 类使用 @Repository 进行注解仍然不失为一个好的做法,因为这些 bean 会自动被扫描程序添加。此外,Spring 可能还会给这一注解添加其他有用特性。
Spring-JDBC
Spring-JDBC 提供了 Jdbc 模板类,它移除了连接代码以帮你专注于 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 方法。JdbcDaoSupport 还提供了一个将 SQL 异常转换为 Spring DataAccessExceptions 的异常翻译器。
如果你计划使用纯 jdbc,那么你需要使用 Spring-JDBC 模块。
Spring-ORM
Spring-ORM 是一个囊括了很多持久层技术(JPA,JDO,Hibernate,iBatis)的总括模块。对于这些技术中的每一个,Spring 都提供了集成类,这样每一种技术都能够在遵循 Spring 的配置原则下进行使用,并平稳地和 Spring 事务管理进行集成。
对于每一种技术,配置主要在于将一个 DataSource bean 注入到某种
SessionFactory 或者
EntityManagerFactory 等 bean 中。纯 JDBC 不需要这样的一个集成类(JdbcTemplate 除外),因为 JDBC 仅依赖于一个 DataSource。
如果你计划使用一种 ORM 技术,比如 JPA 或者 Hibernate,那么你就不需要 Spring-JDBC 模块了,你需要的是这个 Spring-ORM 模块。
Spring-Data
Spring-Data 是一个提供了一个通用 API 来定义如何以一个更通用的方式访问数据(DAO + 注解)的总括模块,包括 SQL 和 NOSQL 数据源。
初步设想是提供一种技术,开发者可以以一种技术无关的方式为 DAO 和实体类写接口,仅仅基于配置(在 DAO 和实体类加注解 + spring 配置,或者 xml 配置),就可以决定实现技术是 JPA(SQL) 还是 redis,hadoop 等等。
如果你遵循了 spring 为方法查找定义的命名规范,大多数简单的场景下你甚至都不需要为查找方法提供查询字符串。其他少数情况下,你需要在查找方法的注解里提供查询字符串。
在应用上下文被加载后,spring 为 DAO 接口提供代理,它包含有数据访问技术相关的所有样板代码,并调用配置的查询。
Spring-Data 专注于非 SQL 技术,但仍为 JPA(唯一的 SQL 技术,其他诸如 Hibernate 等没有)提供了一个模块。
该选择哪个
了解了这些,现在你可以决定选用哪一个了。好消息是你不需要为底层技术做一个明确的最终选择。这正是 Spring 主旨所在:作为一名开发人员,在你写代码的时候更多专注于业务逻辑,如果你把业务处理好了,改变底层技术只是一些实现或者配置细节的工作。
- 使用 POJO 类为实体定义一个数据模型,并使用 get 和 set 方法来表示实体的属性以及和其他实体的关系。你当然需要根据底层技术的需要为实体类及其方法加注解,但是现在,作为入门 POJO 足够了。现在你只需要专注于业务需求。
- 为你的 DAO 定义接口。一个 DAO 刚好包含一个实体,但你也无需为每个实体都对应一个 DAO,因为通过关联关系你可以加载到额外的实体。遵循严格的命名约定定义查找器方法。
- 藉此,其他人就可以模仿你的 DAO 开始业务层的工作了。
- 你可以学习不同的持久层技术(sql,no-sql)来寻找最适合你需要的那个,并最终选择一个。藉此,为你的实体注解并实现 DAO(或者如果你选择使用 Spring-Data 你可以让 Spring 来实现 DAO)。
- 如果你的业务需求进化,而你的数据访问技术对此的支持并不充分(比方说,一开始你使用了 JDBC,只有寥寥几个实体,但是现在需要一个更加丰富的数据模型,而 JPA 是一个比较好的选择),那么你需要修改你的 DAO 实现,在你的实体上添加一些注解并修改 Spring 配置(添加一个 EntityManagerFactory 定义)。但这些也只是持久层的改动,对于业务逻辑层的代码不应该受到到因此改动的影响。
注意:事务管理
Spring 为事务管理提供了一个 API。如果你的数据访问计划使用 spring,那么你也应该用 spring 来做事务管理,因为它们整合在一起确实很好。对于每一个 spring 支持的数据访问技术,都有一个为本地事务匹配的事务管理器,或者如果你需要分布式事务你也可以选择 JTA。它们都实现了同样的 API,因此持久层技术的选择只是一个随意调整的配置的事情,它的更改不会影响到业务代码。
原文链接: http://stackoverflow.com/questions/24990400/spring-dao-vs-spring-orm-vs-spring-jdbc。