Spring DAO vs Spring ORM vs Spring JDBC

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

据我所知,SpringJDBC 提供了一些模板,用于减少通过普通的老方法访问数据库的样板代码——您可以编写自己的 SQL 查询。

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

Spring-DAO 根据 Spring 的网站:

Spring 中的数据访问对象(DataAccessObject,DAO)支持旨在实现 易于使用 JDBC、 Hibernate 或 JDO 等数据访问技术 以一种一致的方式

我对 ORM 和 JDBC 有一点了解,因为它们针对访问数据库的不同方式。但是 Spring-DAO 实在是太令人困惑了!

有人能说明一下这三者之间到底有什么不同吗? 在哪些情况下应该首选哪个?

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

88809 次浏览

You create interface like SomeObjectDao and then create different implementations of this interface like JdbcSomeObjectDao, HibernateSomeObjectDao. Then in your SomeObjectService class you will operate on the SomeObjectDao interface, and inject there one of the concrete implementations. So each implementation of SomeObjectDao will hide the details, whether you use JDBC, or ORM etc.

Usually JDBC, and different implementations of ORM throws different kind of exceptions. Spring's DAO support can map those different, technology specific exceptions to common Spring DAO exceptions. So you are decoupled more from the actual implementation. Also Spring's DAO support offers set of abstract *DataSupport classes which even more help in DAO development. So beside implementing your SomeObjectDao interface, you can extend one of Spring's *DataSupport class.

Here is an introduction to each mentioned technology.

Spring-DAO

Spring-DAO is not a spring module in a strict sense, but rather conventions that should dictate you to write DAO, and to write them well. As such, it does neither provide interfaces nor implementations nor templates to access your data. When writing a DAO, you should annotate them with @Repository so that exceptions linked to the underlying technology (JDBC, Hibernate, JPA, etc.) are consistently translated into the proper DataAccessException subclass.

As an example, suppose you're now using Hibernate, and your service layer catches HibernateException in order to react to it. If you change to JPA, your DAOs interfaces should not change, and the service layer will still compile with blocks that catches HibernateException, but you will never enter these blocks as your DAOs are now throwing JPA PersistenceException. By using @Repository on your DAO, the exceptions linked to the underlying technology are translated to Spring DataAccessException; your service layer catches these exceptions and if you decide to change the persistence technology, the same Spring DataAccessExceptions will still be thrown as spring have translated native exceptions.

Note however that this has limited usage for the following reasons:

  1. Your should usually not catch persistence exceptions, as the provider may have rolled back the transaction (depending on the exact exception subtype), and thus you should not continue the execution with an alternative path.
  2. The hierarchy of exceptions is usually richer in your provider than what Spring provides, and there's no definitive mapping from one provider to the other. Relying on this is hazardous. This is however a good idea to annotate your DAOs with @Repository, as the beans will be automatically added by the scan procedure. Further, Spring may add other useful features to the annotation.

Spring-JDBC

Spring-JDBC provides the JdbcTemplate class, that removes plumbing code and helps you concentrate on the SQL query and parameters. You just need to configure it with a DataSource, and you can then write code like this:

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 also provides a JdbcDaoSupport, that you can extend to develop your DAO. It basically defines 2 properties: a DataSource and a JdbcTemplate that both can be used to implement the DAO methods. It also provides an exceptions translator from SQL exceptions to spring DataAccessExceptions.

If you plan to use plain jdbc, this is the module you will need to use.

Spring-ORM

Spring-ORM is an umbrella module that covers many persistence technologies, namely JPA, JDO, Hibernate and iBatis. For each of these technologies, Spring provides integration classes so that each technology can be used following Spring principles of configuration, and smoothly integrates with Spring transaction management.

For each technology, the configuration basically consists in injecting a DataSource bean into some kind of SessionFactory or EntityManagerFactory etc. bean. For pure JDBC, there's no need for such integration classes (apart from JdbcTemplate), as JDBC only relies on a DataSource.

If you plan to use an ORM like JPA or Hibernate, you will not need spring-jdbc, but only this module.

Spring-Data

Spring-Data is an umbrella project that provides a common API to define how to access data (DAO + annotations) in a more generic way, covering both SQL and NOSQL data sources.

The initial idea is to provide a technology so that the developer writes the interface for a DAO (finder methods) and the entity classes in a technology-agnostic way and, based on configuration only (annotations on DAOs & entities + spring configuration, be it xml- or java-based), decides the implementation technology, be it JPA (SQL) or redis, hadoop, etc. (NOSQL).

If you follow the naming conventions defined by spring for the finder method names, you don't even need to provide the query strings corresponding to finder methods for the most simple cases. For other situations, you have to provide the query string inside annotations on the finder methods.

When the application context is loaded, spring provides proxies for the DAO interfaces, that contain all the boilerplate code related to the data access technology, and invokes the configured queries.

Spring-Data concentrates on non-SQL technologies, but still provides a module for JPA (the only SQL technology).

What's next

Knowing all this, you have now to decide what to pick. The good news here is that you don't need to make a definitive final choice for the technology. This is actually where Spring power resides : as a developer, you concentrate on the business when you write code, and if you do it well, changing the underlying technology is an implementation or configuration detail.

  1. Define a data model with POJO classes for the entities, and get/set methods to represent the entity attributes and the relationships to other entities. You will certainly need to annotate the entity classes and fields based on the technology, but for now, POJOs are enough to start with. Just concentrate on the business requirements for now.
  2. Define interfaces for your DAOs. 1 DAO covers exactly 1 entity, but you will certainly not need a DAO for each of them, as you should be able to load additional entities by navigating the relationships. Define the finder methods following strict naming conventions.
  3. Based on this, someone else can start working on the services layer, with mocks for your DAOs.
  4. You learn the different persistence technologies (sql, no-sql) to find the best fit for your needs, and choose one of them. Based on this, you annotate the entities and implement the DAOs (or let spring implement them for you if you choose to use spring-data).
  5. If the business requirements evolve and your data access technology is not sufficient to support it (say, you started with JDBC and a few entities, but now need a richer data model and JPA is a better choice), you will have to change the implementation of your DAOs, add a few annotations on your entities and change the spring configuration (add an EntityManagerFactory definition). The rest of your business code should not see other impacts from your change.

Note : Transaction Management

Spring provides an API for transaction management. If you plan to use spring for the data access, you should also use spring for transaction management, as they integrate together really well. For each data access technology supported by spring, there is a matching transaction manager for local transactions, or you can choose JTA if you need distributed transactions. All of them implement the same API, so that (once again) the technology choice is just a matter a configuration that can be changed without further impact on the business code.

Note : Spring documentation

The links to Spring documentation that you mentioned are rather old. Here is the documentation of the latest release (4.1.6, covering all topics) :

Spring-data is not part of the Spring framework. There is a common module that you should first read to get used to the principles. Documentation can be found here:

Spring DAO(Data Access Object): is an object that provides an abstract interface to JDBC implementation frameworks i.e. Spring DAO is generalized concept to access JDBC and Hibernate, MyBatis, JPA, JDO using it's individual Support classes. And it provides generalized exception hierarchy by defining @Repository annotation. This annotation defines to Spring container for SQL exception translation from SQLException to Spring's data access strategy-agnostic SQLException0 hierarchy.

i.e. Easily switch between persistent frameworks, code without worrying about catching exceptions that are specific to each technology.


Spring JDBC: For plain JDBC we use this module, which is only depends on DataSource and Template classes like JdbcTemplate, NamedParameterJdbcTemplate(wraps JdbcTemplate) and SimpleJdbcTemplate for reducing cross cutting concerns.

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);
}
  

}

and in Spring XML:

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

Spring JDBC also provides JdbcDaoSupport, NamedParameterJdbcDaoSupport, SimpleJdbcDaoSupport, which are support(i.e. convenient) way to extend and develop our own DAO abstract interface as follows:

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);
}
}

and in spring XML:

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

Spring ORM: For ORM tools support such as Hibernate, JPA, MyBatis...easily integrates Spring by injecting DataSource along with following classes and respective DaoSupport classes.

  • SessionFactory for Hibernate
  • EntityManagerFactory for JPA,
  • SqlSessionFactory for MyBatis

As an additional info. I suggest you use Spring Data JPA. Using anotations such as: @Repository, @Service. I show you an example:

@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);


}

Where CustomerEntitlementsProjection is Spring projection, linked with you entity or DTO pojo;

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


String getContractNumber();


String getExecutiveNumber();

The spring-dao lib stopped in version 2.0.8 (January 2008). The classes in spring-dao were copied to spring-tx. So, if you need a class that you find in spring-dao, add the dependency to spring-tx instead. (Source.)