掌桥专利:专业的专利平台
掌桥专利
首页

基于数据库的数据访问系统

文献发布时间:2023-06-19 19:28:50


基于数据库的数据访问系统

技术领域

本发明涉及数据访问技术领域,尤其涉及一种基于数据库的数据访问系统。

背景技术

随着大数据作为战略资源的地位日益凸显,人们越来越重视数据的采集和存储,越来越强烈地意识到挖掘数据和转化数据的重要性,各企业也逐步构建了数据分析类系统,来支撑灵活的数据查询和分析工作。而如何支持不同类型数据库,如何快速开发并满足客户不同的查询需求是在开发系统时比较关注的问题。

现有的开源框架封装了数据查询方法,便于开发人员查询数据和封装SQL(Structured Query Language,结构化查询语言)语句,比如Hibernate、JPA(JavaPersistence API,Java持久层API)、Mybatis,对于复杂的业务数据获取,往往直接编写符合数据库语法的SQL进行查询。

在采用开源框架中面向对象的查询方式时,通常适用于简单的数据查询,而且开发人员需要根据查询的业务类型,构建出对应的业务对象;采用封装SQL或直接编写SQL时,不同类型的数据库,或者有些数据库不同版本,都存在SQL语法不同的问题。往往需要根据数据库类型,封装多套SQL来满足不同的语法要求,而且需要注意SQL注入、SQL拼接顺序、SQL动态参数与占位符的匹配等问题,给开发带来了很多的困难,影响开发效率,难以控制SQL质量,使得查询性能存在风险。

发明内容

鉴于上述的分析,本发明实施例旨在提供一种基于数据库的数据访问系统,用以解决现有SQL构造复杂而且无法用一套查询逻辑适配多种数据载体的问题。

本发明实施例提供了一种基于数据库的数据访问系统,包括:查询构造器、查询转译器、数据源、执行配置器和查询执行器;其中,

查询构造器,用于通过链式调用方式构造查询对象语法树,基于查询对象语法树获取查询对象;

查询转译器,用于管理上下文,调用注册的写入器在转译准备操作中调整查询对象的语法树结构,在转译写入操作中将调整后的查询对象转译成SQL;

数据源,用于获取与目标数据库的连接;

执行配置器,用于获取与数据源对应的查询执行器,并创建查询转译器,以及将与目标数据库类型对应的写入器注册至查询转译器中;

查询执行器,用于将查询构造器生成的查询对象传入查询转译器中,执行查询转译器返回的SQL,获取查询结果。

进一步地,查询对象语法树上的节点是与SQL语法元素对应的引用对象,引用对象实现了相同的父引用接口,均包括一个获取元素类型的方法,用于定义引用对象对应的SQL语法元素类型;引用对象可以关联其它引用对象,也可以派生出子引用对象。

进一步地,查询构造器包括多个与SQL组成部分对应的接口,在每个接口实现类中通过start和end开头的方法表示构造SQL组成部分的开始和结束;

构造查询对象语法树,包括:通过链式调用方式,调用多组start和end开头的方法,在每组start和end开头的方法中挂接1个或多个引用对象;一棵查询对象语法树描述一条完整的SQL语句。

进一步地,写入器具有相同的父写入器接口,用于执行以下操作:获取写入器处理类型、准备转译和写入转译;其中,

获取写入器处理类型,用于定义写入器可处理的元素类型,且与一个引用对象中定义的SQL语法元素类型对应;

准备转译,用于根据目标数据库类型,使用等价语法转换查询对象中的引用对象,调整引用对象之间的节点挂接关系,得到处理后的查询对象;

写入转译,用于根据处理后的查询对象中引用对象对应的元素类型,在上下文的字符串建造者中生成对应的SQL片段,和/或在参数列表缓冲区中写入值。

进一步地,查询对象语法树根节点的引用对象对应的写入器作为查询转译器调用的入口写入器;在入口写入器的转译准备和转译写入操作中分别定义对查询对象语法树的遍历顺序。

进一步地,将与目标数据库类型对应的写入器注册至查询转译器中,注册顺序是:先注册标准的ANSI SQL的写入器,然后再注册与目标数据库类型对应的处理差异化语法的写入器,最后注册处理特殊业务场景的写入器,根据写入器中定义的相同的可处理的元素类型,后注册的会覆盖之前注册的写入器。

进一步地,管理上下文包括以下操作:

创建上下文,用于根据当前上下文生成子上下文,子上下文包括:当前上下文中的变量,子上下文独立的变量、字符串建造者和参数列表缓冲区;

合并上下文,用于将子上下文中的字符串建造者和参数列表缓冲区合并到父上下文中,最终合并生成完整的SQL语句和参数列表;

回收上下文,用于将空闲上下文释放至内存中的上下文资源池中。

进一步地,变量存在于上下文中,分为三种级别:全局变量、查询对象级变量和局部变量;

全局变量,指在转译过程中所有上下文中共享的变量;

查询对象级变量,指在转译过程中查询对象的主子查询的上下文中分别独立但可共享的变量;

局部变量,指逐级向子上下文传递的变量,无法通过合并上下文方法写回父上下文中。

进一步地,查询结果封装为数据集对象,包括查询结果集和查询结果的元数据,其中查询结果集采用二维数组格式存储。

进一步地,查询执行器是一个抽象接口,根据查询对象中的对象类型进行扩展,包括:JDBC执行器和JPA执行器。

与现有技术相比,本发明至少可实现如下有益效果之一:

1、使用链式方法调用来构造查询对象语法树,无需考虑SQL拼接顺序,并支持多层次子查询嵌套,支持复杂SQL的构造,降低了构造SQL的难度;

2、只需构造一个查询对象,提供一套查询逻辑就可支持不同类型和不同版本的数据库,提高了代码的复用度,数据库的兼容性,降低了维护成本;

3、通过查询转译器集中处理不同数据库特殊转换,避免使用者编写不规范的原生SQL,避免SQL语法错误,提高了代码质量,降低了出现性能问题的风险;

4、提供了可扩展机制,支持自定义的函数、引用对象、写入器、执行器和数据集,满足个性化的使用;

5、查询结果集采用二维数组进行数据存储,大大减少了存储空间。

本发明中,上述各技术方案之间还可以相互组合,以实现更多的优选组合方案。本发明的其他特征和优点将在随后的说明书中阐述,并且,部分优点可从说明书中变得显而易见,或者通过实施本发明而了解。本发明的目的和其他优点可通过说明书以及附图中所特别指出的内容中来实现和获得。

附图说明

附图仅用于示出具体实施例的目的,而并不认为是对本发明的限制,在整个附图中,相同的参考符号表示相同的部件。

图1为本发明实施例中基于数据库的数据访问系统组成图。

具体实施方式

下面结合附图来具体描述本发明的优选实施例,其中,附图构成本申请一部分,并与本发明的实施例一起用于阐释本发明的原理,并非用于限定本发明的范围。

本发明的一个具体实施例,公开了一种基于数据库的数据访问系统,如图1所示,包括:查询构造器、查询转译器、数据源、执行配置器和查询执行器;

查询构造器,用于通过链式调用方式构造查询对象语法树,基于语法树获取查询对象;

查询转译器,用于管理上下文,调用注册的写入器在转译准备操作中调整查询对象的语法树结构,在转译写入操作中将调整后的查询对象转译成SQL;

数据源,用于获取与目标数据库的连接;

执行配置器,用于获取与数据源对应的查询执行器,并创建查询转译器,以及将与目标数据库类型对应的写入器注册至查询转译器中。

查询执行器,用于将查询构造器生成的查询对象传入查询转译器中,执行查询转译器返回的SQL,获取查询结果。

实施时,使用查询构造器定义统一的查询对象,将数据源传入执行配置器,由执行配置器自动注册写入器至转译器中,返回适配的查询执行器,再将查询对象传入查询执行器中,由查询执行器自动调用查询转译器,通过注册的写入器将查询对象转换为不同数据库专有的SQL,执行SQL后得到查询结果。

优选地,本实施例中基于数据库的数据访问系统可以打成Jar包,作为企业开发框架中的工具类,便于各开发项目组使用和扩展。

以下详细介绍基于数据库的数据访问系统中各模块的运行原理及技术方案。

具体来说,考虑到一个SQL语句的组成部分包括:选择列名select,查询表名from,过滤条件where,分组字段group by,排序条件orderby,分组条件having,表合并unionall/union,因此,查询构造器中组合了很多接口,包括Select、From、Where、Group、Order、Having和Merge,分别对应SQL的各个组成部分,每个接口实现类中通过start和end开头的方法表示构造SQL组成部分的开始和结束。

具体来说,查询构造器包括以下方法:

startSelect,用于设置选择列名;endSelect,用于表示当前选择列名设置完成;

startFrom,用于设置查询的表;endForm,用于表示当前查询的表设置完成;

startWhere,用于设置过滤条件;endWhere,用于表示当前过滤条件设置完成;

startGroup,用于设置分组字段;endGroup,用于表示当前分组字段设置完成;

startOrder,用于设置排序字段和排序顺序;endOrder,用于表示当前排序字段和排序顺序设置完成;

startHaving,用于设置分组条件;endHaving,用于表示当前分组条件设置完成;

startMerge,用于设置表合并;endMerge,用于表示当前合并设置完成;

page,用于设置查询的分页条件;

limit,用于设置查询结果的最大条数;

需要注意的是,page与limit方法互斥,其它方法调用时不分先后顺序,根据SQL语法组合调用上述方法,在构造完成后调用build方法创建和生成查询对象;

需要说明的是,可以用一条语句或多条语句来构造一棵语法树,一棵语法树描述一条完整的SQL语句。在一条语句中组合调用多个方法构造多个SQL组成部分时,各start和end开头的方法成对调用,如果通过多条语句,每条语句只构造SQL的一个组成部分时,可以只调用start开头的方法,代码换行相当于调用了end开头的方法。当逻辑十分复杂时,这种可自由构造SQL的方式使得开发人员可以将注意力集中在业务上,而不需要操心SQL的各种组成部分拼接时的先后关系、括号是否匹配、是否存在SQL注入攻击、语法是否符合目标数据库等问题。

示例性地,对SQL语句“SELECT C.CUSTOMERNAMEAS客户名称FROM CUSTOMER CWHERE C.ID>1”,利用HQueryFacade.createQueryBuilder()方法创建一个查询构造器,用一条语句将上述SQL语句构造成一棵语法树,示例代码如下:

HQuery query=

HQueryFacade.createQueryBuilder().startFrom().tab(“CUSTOMER”,“C”).endFrom().startSelect().col(0,“CUSTOMERNAME”,“客户名称”).endSelect().startWhere().gtr(getCol(0,“ID”),getVal(1)).endWhere().build();

用多条语句将上述SQL语句构造成一棵语法树,示例代码如下:

HQueryBuilder querybuilder=HQueryFacade.createQueryBuilder().startFrom().tab(“CUSTOMER”,

“C”).endFrom();

querybuilder.startSelect().col(0,“CUSTOMERNAME”,“客户名称”);

querybuilder.startWhere().gtr(getCol(0,“ID”),getVal(1));

HQuery query=querybuilder.build();

查询构造器构造SQL的组成部分时,每个组成部分的数据被封装为引用对象,作为语法树上的一个节点,被放在各组成部分对应的引用对象集合中,语法树的根节点也有对应的引用对象HQuery,包含各个子节点的引用对象集合。

优选地,引用对象集合采用ArrayList类型。

引用对象是用SQL语法元素描述SQL组成部分,包括表引用对象、选择列引用对象、分组引用对象、排序引用对象、布尔条件引用对象、字段引用对象、常量引用对象和函数调用引用对象等,这些引用对象实现了相同的父引用接口HValRef,均包括一个获取元素类型的方法,用于定义引用对象对应的SQL语法元素类型。引用对象可以关联其它引用对象,也可以派生出子引用对象。

在上述示例代码中,通过tab(“CUSTOMER”,“C”)方法,构造了一个表引用对象,其中“CUSTOMER”是表引用对象中的表名,“C”是表引用对象中的表别名,该表引用对象会放入表引用对象集合中;通过col(0,“CUSTOMERNAME”,“客户名称”)方法,构造了一个选择列引用对象,其中“0”是列所属的表索引,即第1张表,“CUSTOMERNAME”是列名,“客户名称”是列别名,该选择列引用对象会放入选择列引用对象集合selList中;通过gtr(getCol(0,“ID”),getVal(1))构造了一个布尔条件引用对象,其中gtr是布尔条件的运算符,表示“>”,getCol(0,“ID”)是布尔条件的左边,表示被比对字段是第1张表的“ID”字段,getVal(1)是布尔条件的右边,表示比对值是“1”,该布尔条件引用对象会放入布尔条件引用对象集合boolList中。

优选地,考虑到使用between运算符时会有2个比对值,布尔条件引用对象支持2个右值。

需要说明的是,父引用接口派生出了很多子引用接口,每个引用对象直接实现的是对应的子引用接口,在继承父引用接口中方法的同时可以增加新的方法。以布尔条件引用对象为例,构造引用对象并放入对应的引用对象集合的示例代码如下,其中HBoolExpImpl是布尔条件引用接口HBoolRef的实现类,HBoolRef是父引用接口HValRef派生的一个子引用接口:

//构造布尔条件引用对象

HBoolRefbool=

new HBoolExpImpl(getCol(0,“ID”),GTR,getVal(1),null);

//将布尔条件引用对象放入布尔条件引用对象集合中

ListboolList=Arrays.asList(bool);

引用对象对应SQL语法元素,包括:列SEL、字段COL、表FRM、分组GRP和常量CST等,需要说明的是,元素类型支持自定义,比如可以定义“CST_USER”为扩展的常量引用,与通用的CST区分处理方式的不同。

对于引用对象可以关联其它引用对象,以SQL中select后定义的选择列为例来说明。选择列可以设置为:当前表的字段、常量字段、关联的表字段、子查询的查询字段、函数值等非常多的情况。从这些情况中可以看出,选择列名可以关联字段引用对象、变量引用对象、函数调用引用对象等,因此,在构造SQL中选择列名的组成部分时,Select接口实现类中定义了多个方法将字段引用、函数调用引用、变量引用等符合SQL语法的相关引用对象加入到选择列引用对象的集合中,常量引用对象、子查询引用对象都是变量引用接口HValRef的子接口对象,可以通过变量引用对象获取常量引用对象、子查询引用对象,函数调用引用中的输入参数又会关联列引用、常量引用或子查询引用对象。

语法树上可以挂接任意实现了父引用接口的引用对象,每个引用对象可以再挂接其它引用对象,也可以挂接子语法树,从而实现语法树的无限拓展,可以有效降低SQL的构造难度。

示例性地,待查询字段是另一个表中的一个字段,示例代码如下:

querybuilder.startSelect().val(HQueryFacade.createQueryBuilder().startSelect().col(0,“TOTALS”,“TOTALS”).endSelect().startFrom().tab(“PRODUCT”,“P”).endFrom().build(),“销售量”);

对于SQL中的复杂查询,通常都是多表关联,包括leftjoin、rightjoin、innerjoin和fulljoin,只有一个表引用对象难以覆盖复杂场景,本实施例中将引用对象派生出子引用对象来实现。优选地,将表引用对象HFrmRef,又派生出主表名HFrmNRef,用于表示直接根据表名进行关联;子查询引用对象HFrmQRef,用于表示将一个子查询结果作为表进行关联;表关联引用对象HFrmJRef,用于定义关联的左表的表引用对象、关联方式和关联条件。而表关联时既可以直接关联表名,又可以关联查询子表,因此基于上述三个派生的子接口,又派生出关联表名引用对象HFrmJNRef,用于表示关联的右表是直接的表名;关联子表引用对象HFrmJQRef,用于表示关联的右表是子查询。

示例性地,A表与B表通过A表的AID与B表的BID左外连接,在构造语法树时的示例代码如下:

querybuilder.startFrom().tab(“A”,“A

表”).join(0,“AID”,JoinType.LEFT_JOIN,“B”,“B表”,“BID”).endFrom();

代码中通过tab(“A”,“A表”)方法,构造了一个主表名引用对象HFrmNRef,通过join(0,“AID”,JoinType.LEFT_JOIN,“B”,“B表”,“BID”)方法,构造了一个关联表名引用对象HFrmJNRef,其中包含表引用对象HFrmRef、关联方式JoinType和布尔条件引用对象HBoolRef,分别用于定义关联的左表的引用对象、关联关系和关联条件。

值得注意的是,现有技术中,当SQL语句中需要动态传入查询条件时,为了避免SQL注入攻击,而用JDBC占位符“?”来表示SQL中的参数,但是当查询逻辑比较复杂时,开发人员在构造SQL时很难将占位符和对应的参数值一一匹配,出现问题时也很难排查。虽然Hibernate中可以将变量和参数值存放在Map中,但是当变量比较多,或者同一个变量要在SQL中使用多次时,就要使用“变量名+序号”的方式来防止变量名重复,出现问题时也很难排查。而本实施例中,查询构造器在各组成部分中通过挂接引用对象来构造语法树,对于动态参数可以作为语法树上的一个节点,用实现了HValRef接口的常量引用对象来定义,在构造时无需考虑占位符问题。

基于构造完成的查询对象语法树获取查询对象,是将语法树上具有相同元素类型的引用对象放在对应的引用对象集合中,将引用对象集合放入语法树根节点的根引用对象中,返回根引用对象。

引用对象集合中的引用对象在执行查询时由查询转译器来解析,查询转译器采用策略模式进行设计,查询转译器中注册了支持不同数据库SQL语法的多个写入器,具有相同的父写入器接口HWriter;每一个写入器用于转译对应的数据库SQL中的一个语法元素;每一个引用对象至少对应一个写入器。

值得注意的是,在查询构造器构造查询对象时,不需要考虑不同数据库类型、相同数据库不同版本之间的差异,通过相同的引用对象来构造查询对象,提高了使用的便利性和开发效率。在执行时,根据数据库类型和版本再由不同的写入器完成不同的转译功能,具体来说,写入器执行的操作包括:获取写入器处理类型、准备转译和写入转译;

①获取写入器处理类型,用于定义写入器可处理的元素类型,且与一个引用对象中定义的SQL语法元素类型对应;

需要说明的时,写入器中定义的元素类型,与一个引用对象中获取元素类型方法返回的元素类型对应,一个引用对象的元素类型可以对应多个写入器,即可以根据不同的应用场景,使用不同的写入器进行转译。

②准备转译,用于根据目标数据库类型,使用等价语法转换查询对象中的引用对象,调整引用对象之间的节点挂接关系,得到处理后的查询对象;

示例性地,MySQL5.7和MySQL8,版本不同,支持的函数也不同。如果要统计每一个产品的销量排名,对于MySQL8来说,采用RANK函数可以用于实现这个需求,但是如果使用MySQL版本是5.7,则没有提供RANK函数,只能采用定义变量和主子查询来获取排名。这种情况,可以自定义一个函数MY_RANK,该函数根据输入的排序方向和至少一个用于排序的列,得到排名,在构造语法树时,通过函数调用引用对象来调用函数MY_RANK,示例代码如下:

HQueryFacade.createQueryBuilder().startSelect()

.col(“P”,“PRODUCT_NAME”,“产品名称”)

.sel(HQueryFacade.getFunRef(“MY_RANK”,HQueryFacade.getCol(0,“TOTALS”),0),“RK”)

.endSelect().startForm.tab(“PRODUCT”,“P”).endFrom().build();

与函数调用引用对象对应的是函数调用写入器HWriterFun,其继承HWriter接口,扩展了一个获取函数名称的方法,则基于HWriterFun接口,针对不同类型和版本的数据库实现不同的写入器,比如MySQL5MyRankFunWriter、MySQL8MyRankFunWriter,在MySQL8MyRankFunWriter写入器的准备转译方法中不需要特殊处理,在写入转译方法中,转换成Rank函数的SQL片段即可,但是在MySQL5MyRankFunWriter写入器的准备转译方法中,由于排名函数是需要通过主子查询、增加排名字段来完成,则在写入器中将一个函数引用对象转换成多个引用对象重新挂接在主查询对象中,得到调整后的查询对象语法树。

③写入转译,用于根据处理后的查询对象中引用对象对应的元素类型,在当前上下文的字符串建造者中生成对应的SQL片段,和/或在参数列表缓冲区中写入值。

值得注意的是,如果写入器用来支持JPA的查询,则生成的是符合HQL(HibernateQuery Language,Hibernate查询语言)片段。

需要说明的是,上下文中包括一个字符串建造者StringBuilder,和一个参数列表缓存区List,根据写入器的处理功能和数据库类型进行处理。

示例性地,不同类型的数据库中表名、表别名、列别名的引号标识不同,比如,MySQL数据库中的引号要用单引号,Oracle数据库中要用双引号,那么在MySQL对应的写入器的写入转译方法中,在字符串建造者中生成对应的SQL片段时需要加上单引号,在Oracle对应的写入器的写入转译方法中,在字符串建造者中生成对应的SQL片段时需要加上双引号。

在进行查询时,当现有的写入器无法直接满足业务需求,可以通过继承父写入器接口来扩展新的写入器。

示例性地,常量引用对象对应的写入器有HCstWriterImpl,这个写入器负责在上下文的字符串建造者StringBuilder中写入占位符“?”,并且同时在上下文的参数列表缓冲区List中加入这个占位符对应的参数值,转译后,生成的SQL中自动带有占位符,而参数列表缓冲区中的参数值自动与占位符一一匹配。如果不想生成带有占位符的SQL,想让参数值直接拼接在SQL中,可以扩展一个写入器MyCstWriterImpl,在其实现中,将参数值直接写入当前上下文的字符串建造者StringBuilder中,不往上下文中的参数列表缓冲区中添加元素,使用这个转译器转译出来的SQL即是不带占位符“?”的了。最后只需要在转译器中注册新的写入器,替换HCstRef对应的写入器HCstWriterImpl即可。

查询对象构造好后,查询对象语法树根节点的引用对象对应的写入器作为查询转译器调用的入口写入器;查询转译器在转译准备和转译写入中分别对查询对象语法树进行遍历时,遍历顺序在入口写入器中定义。

具体来说,转译准备期主要用于调整语法树结构,只需要遍历语法树上的引用对象集合,以及集合内的每个引用对象即可,遍历顺序没有严格的要求,但是转译写入期需要按照SQL语法规范将多个写入器转译生成的SQL片段合并成完整的SQL语句和参数列表,在入口写入器中通过定义语法树引用对象的转译顺序,从而控制引用对象对应的写入器的调用顺序,创建上下文生成SQL片段,通过上下文合并顺序控制SQL片段和参数列表的合并顺序。

优选地,对于MySQL数据库,先转译From对应的表引用对象集合,在上下文中生成SQL片段,再转译Select对应的选择列引用对象集合,在上下文中生成SQL片段,合并SQL片段时,先合并写入了Select的上下文,再合并写入了From的上下文。

需要说明的是,根据语法树的层级,查询转译器对上下文的管理涉及多级上下文的操作,包括如下操作:

创建上下文,用于根据当前上下文生成子上下文,子上下文包括:当前上下文中的变量,子上下文独立的变量、字符串建造者和参数列表缓冲区;

合并上下文,用于将子上下文中的字符串建造者和参数列表缓冲区合并到父上下文中,最终合并生成完整的SQL语句和参数列表;

回收上下文,用于将空闲上下文释放至内存中的上下文资源池中。

示例性地,第一级的上下文派生出二级上下文,二级上下文派生出三级上下文,上下文合并时,三级上下文中的SQL片段和参数列表会合并到上级的上下文上。如果在合并三级上下文之前二级上下文中也存在写入SQL片段和参数,那么合并进来的三级上下文的内容一定会在二级上下文已写入的片段和参数之后。

在创建上下文时,上下文中的变量分为三种级别:全局变量、查询对象级变量和局部变量;其中,

全局变量,指在转译过程中所有上下文中共享的变量;

查询对象级变量,指在转译过程中查询对象的主子查询的上下文中分别独立但可共享的变量;

示例性地,在转译准备期,子查询的上下文中,将调整后的语法树写入查询对象级变量Map中,主查询可以从查询对象级变量Map中获取子查询调整后的语法树结构。

局部变量,指逐级向子上下文传递的变量,无法通过合并上下文方法写回父上下文中。

考虑到因为数据库类型和版本的不同,一个引用对象会对应多个写入器,因此在执行查询时就需要根据数据库的类型,选择对应的写入器,这个工作由执行配置器来完成。

在获取到数据源后,执行配置器用于获取与数据源对应的查询执行器,并创建查询转译器,以及根据数据源获取目标数据库类型,将与目标数据库类型对应的写入器注册至查询转译器中。注册时是先注册标准的ANSI SQL的写入器,然后再注册与数据库类型对应的处理差异化语法的写入器,最后注册处理特殊业务场景的写入器,根据写入器中定义的相同的可处理的元素类型,后注册的会覆盖之前注册的写入器。

优选地,提供ANSI SQL全套语法元素对应的写入器,以及处理常用数据库差异化语法的写入器,即能保证SQL转换的质量,又能方便开发人员使用,提高开发效率。

查询执行器是一个抽象接口,根据查询对象中的对象类型进行扩展,包括:JDBC执行器和JPA执行器。

具体来说,在构造查询对象树时,如果数据存储于数据库中,且项目框架未采用Hibernate或JPA,通过物理表名和表字段来访问数据,则使用JDBC执行器,调用JDBC驱动;如果数据存储于数据库中,且项目框架采用了Hibernate或JPA,将数据库表封装成了实体对象,通过对象名称和对象属性来访问数据,则使用JPA执行器,调用JPA的驱动类包。

查询执行器返回的查询结果封装为数据集对象,数据集对象采用二维数组存储数据结果,包括查询结果集和查询结果的元数据。

具体来说,数据集对象DataSet接口继承了List接口,增加了两个方法,分别用来获取查询结果集、获取查询结果的元数据;其中查询结果集采用二维数组格式List存储。这种结构方便对数据结果进行管理,比如对数据结果的列进行重命名时,只需要修改查询结果的元数据即可,大大提升了修改效率,而使用二维数组存储查询结果集可以大大减少存储所需的空间。

与现有技术相比,本实施例提供了一种基于数据库的数据访问系统,解决开发中针对不同数据载体需要多套处理逻辑,数据库一旦发生改变,需要重构代码,复杂SQL拼接复杂,很难排查等问题,通过链式调用方式构造查询对象语法树,支持无限拓展;无需在开发时创建业务对象,无需考虑SQL拼接顺序,占位符与参数匹配问题,支持复杂SQL的构造,降低了构造SQL的难度;只需构造一个查询对象语法树就可支持不同类型和不同版本的数据库,提高了代码的复用度,数据库的兼容性;通过查询转译器集中处理不同数据库特殊转换,避免使用者编写不规范的原生SQL,提高了代码质量,降低了性能风险;查询结果集采用二维数组进行数据存储,大大减少了存储空间;提供了可扩展机制,支持自定义的函数、引用对象、写入器、执行器和数据集,满足个性化的使用。

本领域技术人员可以理解,实现上述实施例方法的全部或部分流程,可以通过计算机程序来控制相关的硬件来完成,所述的程序可存储于计算机可读存储介质中。其中,所述计算机可读存储介质为磁盘、光盘、只读存储记忆体或随机存储记忆体等。

以上所述,仅为本发明较佳的具体实施方式,但本发明的保护范围并不局限于此,任何熟悉本技术领域的技术人员在本发明揭露的技术范围内,可轻易想到的变化或替换,都应涵盖在本发明的保护范围之内。

技术分类

06120115924115