Spring Data –一个可以全部统治的API?

Spring Data是一个高级SpringSource项目,其目的是统一和简化对关系数据库系统和NoSQL数据存储等各种持久性存储的访问。

对于每种类型的持久性存储,您的存储库(也称为DAO或数据访问对象)通常在单个域对象,查找器方法,排序和分页中提供CRUD(创建-读取-更新-删除)操作。 Spring Data为这些方面(CrudRepository,PagingAndSortingRepository)以及针对持久性存储的特定实现提供了通用接口。

您可能已经使用过Spring模板对象之一(例如JdbcTemplate )来编写自定义存储库实现。 尽管模板对象功能强大,但我们可以做得更好。 使用Spring Data的存储库,您只需要编写一个具有根据给定约定定义的finder方法的接口 (该方法可能会因所使用的持久性存储的类型而异)。 Spring Data将在运行时提供该接口的适当实现。 举个例子:

public interface UserRepository extends  MongoRepository<User, String> { 
        @Query ( "{ fullName: ?0 }" )
        List<User> findByTheUsersFullName(String fullName);

        List<User> findByFullNameLike(String fullName, Sort sort);
}
...

Autowired  UserRepository repo ;

 

在本文中,我们将比较JPA,MongoDB和Neo4j的三个子项目。 JPA是JEE堆栈的一部分,并定义了用于访问关系数据库和执行O / R映射的统一API。 MongoDB是一个可扩展的,高性能,开源,面向文档的数据库。 Neo4j是一个图形数据库,这是一个完全事务性的数据库,用于存储结构化为图形的数据。

所有这些Spring Data项目都支持以下方面:

  • 模板化
  • 对象/数据存储映射
  • 仓库支持

其他Spring Data项目(例如Spring Data RedisSpring Data Riak)实际上仅提供模板,因为相应的数据存储保留了无法映射或查询的非结构化数据。

让我们详细了解模板,对象映射和存储库支持。

范本

Spring Data模板(和所有其他Spring模板)的主要目的是资源分配和异常转换。

在我们的例子中,资源是数据存储区,通常可以通过TCP / IP连接进行远程访问。 以下示例显示了如何配置MongoDB模板:

<!-- Connection to MongoDB server -->
<mongo:db-factory  host = "localhost"  port = "27017" dbname = "test" /> 

<!-- MongoDB Template -->
<bean id = "mongoTemplate"
class = "org.springframework.data.mongodb.core.MongoTemplate" >
  <constructor-arg name = "mongoDbFactory" ref = "mongoDbFactory" /> 
</bean> 

首先,我们定义某种连接工厂,然后由MongoTemplate引用。 对于MongoDB,Spring Data项目依赖于底层MongoDB Java驱动程序

通常,这样的低级数据存储区API将具有其自己的异常处理策略。 Spring处理异常的方法是使用开发人员可以捕获但不必捕获的未经检查的异常。 为了弥合这一差距,模板实现捕获了低级异常并抛出了相应的未经检查的Spring异常,该异常是Spring的DataAccessException的子类。

模板提供了存储特定的操作,例如保存,更新和删除单个记录,或用于执行查询或映射/减少作业。 但是所有这些方法仅适用于相应的基础数据存储。

Spring Data JPA不提供模板,因为JPA实现本身已经是JDBC API之上的抽象层。 JPA的EntityManager是模板的对应物。 异常转换由存储库实现处理。

对象/数据存储映射

JPA引入了O / R映射的标准(即,将对象图映射到关系数据库表)。 Hibernate可能是实现JPA规范的最常见的O / R映射器。

使用Spring Data,此支持扩展到具有类对象数据结构的NoSQL数据存储。 但是这些数据结构可能彼此完全不同,因此很难为对象/数据存储区映射建立通用的API。 每种类型的数据存储区都有其自己的注释集,以提供映射所需的元信息。 让我们看看如何将一个简单的域对象User映射到我们的数据存储区:

JPA

MongoDB

Neo4j

@Entity
@Table(name="TUSR" )
public class User {

  @Id
  private String id;

  @Column(name= "fn" )
  private String name;

  private Date lastLogin;

...
}
@Document (
collection= "usr" )
public class User {

  @Id
  private String id;

  @Field ( "fn" )
  private String name;

  private Date lastLogin;

 ...
}
@NodeEntitypublic class User {

  @GraphId
  Long id;


  private String name;

  private Date lastLogin;

...
}

如果您熟悉JPA实体,则可以识别标准的JPA批注。 Spring Data重用了它们; 没有引入其他注释。 映射本身由您使用的JPA实现完成。 MongoDB和Neo4j需要类似的注释集。 您在类级别有一个将类映射到集合(在MongoDB中,集合类似于关系数据库中的表)或节点类型(节点和边是图数据库(如Neo4j)的主要数据类型) 。

每个JPA实体必须具有唯一的标识符。 MongoDB文档和Neo4j节点也是如此。

MongoDB使用@Id注释(与JPA不同,它在org.springframework.data.annotation包中)Neo4j @GraphId。 保留域对象后,将填充这些属性的值。 对于其他持久属性,如果MongoDB文档中的属性名称与Java属性不匹配,则使用@Field批注。

还支持对其他对象的引用。 我们用户的角色可以这样保持:

JPA

MongoDB

Neo4j

@OneToManyprivate List<Role> roles;
private List<Role> roles;
@RelatedTo (
type = "has" ,
direction = 
Direction. OUTGOING )
private List<Role> roles;

在JPA中,您使用@O​​neToMany关系,将n端存储在另一个表中,通常使用联接查询。 MongoDB不支持集合之间的联接,默认情况下,引用的对象就位存储在同一文档中。 您也可以引用其他文档,从而导致客户端连接。 在Neo4j中,关系是调用边,这是基本数据类型之一。

概括起来:MongoDB和Neo4j使用的对象映射与众所周知的JPA O / R映射相似,但是由于数据结构不同,它并不完全相同。 但是,所有映射背后的概念都是相同的:将Java对象映射到持久性存储的数据结构。

储存库支持

如果您曾经在业务应用程序中保存过数据,则可能编写了某种DAO。 通常,您为单个记录实现CRUD操作,并为每个持久类实现一堆finder方法。 Finder方法使用在执行之前放入查询中的参数。

随着JPA的出现,至少可以通过EntityManager接口使用CRUD操作。 尽管编写自定义查找器仍然很无聊:创建一个命名查询,设置每个参数,执行该查询。 例如:

@Entity
@NamedQuery ( name= "myQuery" , query = "SELECT u FROM User u where u.name = :name" )
public class User { 
...
} 

@ Repository 
public class ClassicUserRepository { 

   @PersistenceContext EntityManager em ; 

   public List < User > findByName( String Name ) { 
      TypedQuery < User > q = getEntityManger () . createNamedQuery( "myQuery" , User.class ); 

      q. setParameter ( "name" , fullName );

      return q. getResultList() ;
   } 
   ...

通过使用TypedQuery的流畅接口可以略微减少此问题。

@Repository
public class ClassicUserRepository { 

   @PersistenceContext EntityManager em ; 

   public List < User > findByName ( String name ) {
      return getEntityManger () . createNamedQuery ( "myQuery" , User.class )
         .setParameter( "name" , fullName )
         .getResultList(); 
   } 
   ...

...但是您仍然在实现一种方法,该方法调用设置器并为每个查询执行查询。 使用Spring Data JPA ,相同的查询归结为以下代码:

package repositories; 

public interface UserRepository extends JpaRepository < User, String >  {

   List < User > findByName ( String name ); 
} 

 

使用Spring Data JPA时 ,不必在相应JPA实体的类文件中将JPQL查询声明为@NamedQuerys。 相反,查询是存储库方法(!)的注释:

@Transactional( timeout = 2 , propagation = Propagation. REQUIRED)
@Query ( "SELECT u FROM User u WHERE u.name = 'User 3'" )
List < User > findByGivenQuery (); 

以上所有内容对于Spring Data MongoDBSpring Data Neo4j也适用。 以下示例使用Cipher查询语言查询Neo4j数据库:

public interface UserRepository extends GraphRepository < User > {

  User findByLogin ( String login ); 

  @ Query ( " START root=node:User (login = 'root') MATCH root-[:knows]->friends RETURN friends" )
  List < User > findFriendsOfRoot (); 
} 

当然,查找器方法的命名约定因持久性存储而异。 例如,MongoDB支持地理空间查询 ,因此您可以编写如下查询:

public interface LocationRepository extends MongoRepository<Location, String> {

        List<Location> findByPositionWithin(Circle c);

        List<Location> findByPositionWithin(Box b);

        List<Location> findByPositionNear(Point p, Distance d);
}

通过为所有持久性存储的finder方法提供特殊参数,还对分页和排序提供了通用支持。

存储库支持的主要优点是:

  • 开发人员编写的样板代码少得多
  • 可以在finder方法及其文档旁边定义查询
  • 另外,JPQL查询在Spring上下文组装好后立即编译,而不是在您第一次使用查询时进行编译,这使检测语法错误更加容易

摘要

本文概述了许多复杂的技术,并试图发现相似之处和不同之处。 有关Spring Data项目的更多详细信息,我建议您看一下项目的主页:

要回答标题中的问题:不,没有针对所有持久性存储的通用API。 差异太根本了。 但是Spring Data项目确实提供了一种通用的编程模型来访问您的数据:

存储库支持是物理数据层的抽象,也使编写许多查找程序方法变得非常容易。 通过对象映射,您的域对象可以转换为持久性存储的数据类型。 模板提供了对存储特定功能的低级别访问。

关于作者

Tobias Trelle是Codecentric AG的高级IT顾问,在IT业务方面拥有超过15年的经验。 他的主要兴趣是软件体系结构,EAI和云计算。 他是定期的博客作者,还提供培训并在会议上发表演讲。
Twitter / 博客 / 链接到 / G +

翻译自: https://www.infoq.com/articles/spring-data-intro/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,包括非关系数据库、Map-Reduce 框架、云数据服务等等;另外也包含对关系数据库的访问支持。 Spring Data 包含多个子项目: Commons - 提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化 Hadoop - 基于 Spring 的 Hadoop 作业配置和一个 POJO 编程模型的 MapReduce 作业 Key-Value - 集成了 Redis 和 Riak ,提供多个常用场景下的简单封装 Document - 集成文档数据库:CouchDB 和 MongoDB 并提供基本的配置映射和资料库支持 Graph - 集成 Neo4j 提供强大的基于 POJO 的编程模型 Graph Roo AddOn - Roo support for Neo4j JDBC Extensions - 支持 Oracle RAD、高级队列和高级数据类型 JPA - 简化创建 JPA 数据访问层和跨存储的持久层功能 Mapping - 基于 Grails 的提供对象映射框架,支持不同的数据库 从之前发布其他chm文件下载用户的反映看,有不少朋友反映下载后打开无法显示,这一般不是chm文件的问题,这里统一说明一下解决办法: 如果文件打开看不到右边的内容,是因为你的操作系统为了安全对下载的chm文件进行了锁定,只需要在打开前右键单击该chm文件选择“属性”,然后在“常规”选项卡的下方单击“解除锁定”按钮就可以了。如果还是不能看,请再查看一下你的chm文件所存储的目录或文件名是否有特殊字符如“#”号字符等,去掉特殊字符即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值