今日份学习之Spring Boot 数据访问实现原理

Spring Boot 的数据库管理功能非常强大,它到底可以支持哪些数据库,访问这些数据库的功能又是如何实现的,这些功能有没有欠缺或者需要扩展的地方,如果需要扩展应该如何改进?如果你对这些问题感兴趣,那么可以开始这一章的学习。

1连接数据源的源代码分析

要使用数据库,首先必须与数据库服务器建立连接。对于关系型数据库,SpringBoot连接数据源―般都采用JDBC ( Java Data Base Connectivity)的方式来实现。其他类型的数据库却使用各自独立的方式来建立连接。代码清单11-1是JDBC的一些连接参数的定义,使用关系型数据库时,Spring Boot 的自动配置将尝试从应用的配置文件中读取这些配置项。

代码清单11-1数据源配置参数定义源代码

今日份学习之Spring Boot 数据访问实现原理

 

1.1数据源类型和驱动

JDBC连接数据源必须指定数据源类型和数据库驱动程序,在程序中用driver-ClassName来指定数据库驱动程序的名称,例如使用MySQL的驱动程序是com.mysql.jdbc.Driver,而数据源的类型默认使用org.apache.tomcat.jdbc.pool.DataSource,如代码清单11-2所示。

代码清单11-2JDBC的DataSourceBuilder源代码片段

今日份学习之Spring Boot 数据访问实现原理

 

数据源的类型可以通过配置更改,这一功能给我们使用其他数据源提供了很大的便利。例如在第4章中使用Druid数据源时,就是使用如下的配置来指定数据源类型,即代码中的type设定为com.alibaba.druid.pool.DruidDataSource。

今日份学习之Spring Boot 数据访问实现原理

 

1.2支持的数据库种类

Spring Boot 默认几乎可以支持现有的所有数据库,代码清单11-3是DatabaseDriver定义一个枚举类的源代码,从这个数据库驱动的定义列表中可以看出,它默认支持的数据库种类。但这并不是说,这个列表中没有列出的数据库就不支持了,只是可以采用其他方式来建立连接而已。例如,Redis、MongoDB、Neo4j等数据库都使用了各自独特的方式来建立连接。

代码清单11-3 枚举类DatabaseDriver源代码片段

今日份学习之Spring Boot 数据访问实现原理

 

1.3与数据库服务器建立连接

最终,不管使用哪―种数据库,与数据库服务器建立连接大体上都会用到三个参数,即数据库链接地址、用户名和密码。下面我们来看一看,Spring Boot在使用一个新型的数据库Neo4j时是怎么建立连接的。Neo4j是一个NoSQL数据库,它不能使用JDBC的方式来建立连接,所以由spring-data-neo4j提供连接数据库服务器的方法。使用Neo4j数据库,一般使用如代码清单11-4所示的方法来连接数据库服务器,即通过继承Neo4jConfiguration,重载neo4jServer方法来实现。

代码清单11-4连接Neo4j 的配置类定义

今日份学习之Spring Boot 数据访问实现原理

 

上面的代码最终将调用超类Neo4jConfiguration中的constructSession方法,使用提供的链接地址、用户名和密码,与数据库服务器建立连接,如代码清单11-5所示。

代码清单11-5Neo4j连接服务器部分源代码

今日份学习之Spring Boot 数据访问实现原理

 

2数据存取功能实现原理

与数据库服务器建立连接之后,就可以对数据库执行一些存取操作,对数据库实现管理的功能。数据存取的操作大体上都包含两个方面的内容,即实体建模和持久化。不管是关系型数据库,还是NoSQL数据库,都遵循这一设计规范。

2.1实体建模源代码分析

实体建模的原理简单地说,即将Java的普通对象和关系映射为数据库表及其相关的关系。而这种映射在Spring Boot中,主要是通过注解的方式来实现。几种数据库中主要的注解定义如表11-1所示。

表11-1 实体建模主要注解定义

今日份学习之Spring Boot 数据访问实现原理

 

这种映射机制是双向的,当向数据库存入数据时,是将Java对象映射为数据库对象,而从数据库取出数据时,却将数据库中的数据还原为Java对象。

例如对于Neo4j来说,在实体建模中的主要注解@NodeEntity 的定义如代码清单11-6所示。在一个类定义中使用这个注解,表示这个类定义就是一个节点实体的建模。

代码清单11-6@NodeEntity源代码

今日份学习之Spring Boot 数据访问实现原理

 

Neo4j是一个图形数据库,所以程序中的实体对象要存入数据库时,将被映射为数据库图形。代码清单11-7是这种映射的部分实现代码。它的实现原理是,将实体对象转化为数据库可以识别的查询语句,实现对象到数据的转换。

代码清单11-7实体对象映射为数据库图形的部分源代码

今日份学习之Spring Boot 数据访问实现原理

 

当从Neo4j数据库中读取数据时,Neo4j将数据库中的图形还原为实体对象。代码清单11-8是实现这种功能的部分源代码,即将从数据库中查询得到的数据集合转化为实体对象,实现从数据到对象的转换。

代码清单11-8数据库中图形还原为实体对象的部分源代码

今日份学习之Spring Boot 数据访问实现原理

 

2.2持久化实现原理

关系型数据库都使用了JPA的一套执行标准,它结合使用Hibernate实现了实体的持久化。后续的数据库管理设计都遵循了JPA这一个标准规范,提供相同的访问数据库的API。图11-1是JPA、MongoDB 、Neo4j三种不同的资源库接口定义的相同的继承关系。

今日份学习之Spring Boot 数据访问实现原理

 

这就不难理解,为什么在Spring Boot 中使用数据库,对于不同种类的数据库,几乎都可以使用相同的方法来访问。但是,上面不同数据库的资源库接口定义虽然有相同的继承关系,它们的实现方法却是不同的,JPA由 SimpleJpaRepository实现了JpaRepository,如代码清单11-9所示。

代码清单11-9JPA数据库持久化源代码片段

今日份学习之Spring Boot 数据访问实现原理

 

而对于Neo4j来说,它使用GraphRepositoryImpl实现了GraphRepository,如代码清单11-10所示。

代码清单11-10Neo4j数据库持久化源代码片段

今日份学习之Spring Boot 数据访问实现原理

 

3 扩展数据存取的功能

使用数据库是应用系统最基本的功能需求,同时也是最频繁和最复杂的功能需求。Spring Boot始终以使用简单为基准,提供了一套以JPA的标准规范来设计的数据存取方法,虽然功能相当强大,但往往不能适合一些复杂的功能需求,这就需要对数据存取的功能做一些扩展。了解Spring Boot使用数据库的实现原理之后,要扩展数据存取的功能就比较容易了。

3.1 扩展JPA功能

根据数据库持久化的原理,可以扩展数据存取的功能,例如在第4章中,实现了扩展JPA的功能,如代码清单11-11所示。数据库持久化的接口实现类ExpandJpa-RepositoryImpl,它继承了SimpleJpaRepository 的实现,扩展了JPA访问数据库的功能。

今日份学习之Spring Boot 数据访问实现原理

 

3.2扩展Neo4j功能

遵循JPA标准规范来设计,这对于新型的Neo4j数据库来说是一个挑战。在JPA中,可以使用如下定义来执行一个分页的查询:

Query ( "select t from User t where t.name like :name" )

Page<User> findByName(@Param ( " name") String name,Pageable pageRequest);

但是这种方法对于Neo4j来说,却会导致严重的错误,如下定义是无法被正常执行的:

Query ( "MATCH (m :Movie) WHERE m.name =~ ( ' (?i). * ' + {name }+'.* ') RETURN m")Page<Movie> findByName (@Param ( "name" ) String name,Pageable pageable) ;

所以为了实现这种分页查询,需要编写一个全局扩展类来实现,如代码清单11-12所示,它调用了Neo4j的底层实现方法 org.neo4j.ogm.session.Session来执行分页查询。

今日份学习之Spring Boot 数据访问实现原理

 

这样在进行分页查询时,就可以调用这个服务类,代码清单11-13是使用电影名称,分页查询电影列表的一个实现例子。

今日份学习之Spring Boot 数据访问实现原理

 

4小结

在Spring Boot中访问数据库为什么如此简单?从对一些核心源代码的分析中可知,它始终遵循一套在业界中广为流行的JPA标准规范来设计,无论是哪种数据库,它都能使用相同且简单的方法来访问。只是,这对于一些复杂的功能需求来说,未免有些欠缺。所以,在认识它的实现原理之后,需要借助一些底层调用来加强和扩展访问数据库的功能。

通过分析一些核心源代码,我们认识到Spring Boot提供的一些可以简单使用的组件中蕴藏的强大功能,也是通过内部的复杂实现来完成的。下一章将剖析微服务的内部实现原理,看看那些可以拿来即用的微服务,其内部的实现原理又是怎样的。

上一篇:知识图谱-用python操纵neo4j数据库-以高速收费站记录为例


下一篇:在python中操作neo4j数据库的方法