主流数据库的 SQL 语法差异以解决方案(下)

消除差异性的方案

由于不同数据库系统的语法有差异,所以如果想要开发的系统能够运行于多数据库系统下就必须通过一定的方法来消除这些差异性。消除差异性的主要方法有:为每种数据库编写不同的SQL语句;使用语法交集;使用抽象SQL;使用ORM,EF等工具;使用SQL翻译器。下面对这几种方案进行分析。

1.为每种数据库编写不同的SQL语句

采用这种方案时,对于有语法差异的SQL语句则为为每种数据库编写不同的SQL,然后在运行时根据当前数据库类型来执行不同的SQL语句,采用这种方案的时候能够比较好的解决多数据库的问题,但是要求开发人员对每种数据库的语法差异性非常精通,而且这增加了开发的工作量。

2.使用语法交集

为了避免多数据库的问题,在开发的时候避免使用各个数据库系统语法的差异部分,只使用所有数据库系统都支持的SQL语句。采用这种方案的时候能够比较好的解决多数据库的问题,但是由于不能使用一些高级的语法,因此有的功能无法实现或者必须在宿主语言中通过代码来实现,这不仅限制了系统功能的实现而且降低了运行效率,最重要的问题是:我既然花大价钱买了Oracle数据,为什么不用Oracle提供的一些耗用的特性呢?

3.使用SQL实体对象

该方案下,开发人员访问数据库方法并不是直接执行SQL语句,而是以SQL实体对象的方式描述出对应SQL语句的语意;然后调用SQL实体执行器对SQL实体描述对象处理,生成对应的数据类型的SQL语句,并执行。在SQL执行器中,为每种数据库实现一个适配翻译器,该适配翻译器接收传入的SQL实体对象,并能根据SQL实体对象描述的语意,生成符合对应数据库语法的SQL语句。SQL实体执行器在运行期间才与具体适配翻译器关联,不必事先知道由何种适配翻译器处理SQL实体对象;当需要增加对新数据库的支持时,不必修改任何原有软件,只需要实现一个新的适配翻译器即可。

采用这种方案,开发人员不能直接编写SQL语句,只能编写抽象的语法结构,比如下面的代码来实现取得表T_Person中前10行数据的功能:

系统框架会将Query翻译成对应数据库系统支持的SQL语句,比如:

MYSQL:

SQLServer:

Oracle:

DB2:

采用这种方式能最大程度的利用目标数据库的高级特性,而且开发人员甚至不需要对SQL语法有任何了解,其缺点是编写的代码量增加了,同时如果要实现子查询、连接等复杂功能就编写非常冗长且难懂的代码,使用普通SQL语句三五行就能完成的功能如果采用这种方式可能就需要几十行代码。

4.使用ORM工具

Java中的Hibernate、EJB以及.Net中的Linq、NHibernate等都是非常优秀的ORM工具,这些ORM工具提供了以面向对象的方式使用数据库,开发人员只要操作实体对象就可以,从而避免了直接编写SQL语句,比如下面的代码用来向人员表中加入一条记录:

ORM工具会将其翻译成如下的SQL语句:

下面的代码用来取得人员表中排名前十的人员:

系统框架会将Query翻译成对应数据库系统支持的SQL语句,比如:

MYSQL:

SQLServer:

Oracle:

DB2:

ORM工具将对实体对象的操作翻译成SQL语句,这本质上也是一种“使用SQL实体对象”的解决方案。

除了支持以操作实体对象的方式使用ORM工具,很多ORM工具都提供了以一种类似于SQL语句的语法工具,比如EJB中的EJB-SQL以及Hibernate中的HSQL,我们可以统称为ORMSQL,在实现复杂功能的时候使用ORMSQL可以避免编写过长的对象操作代码,ORM工具会将ORMSQL语句翻译成目标数据库平台支持的语法。ORMSQL简化了开发,但是目前的ORMSQL支持的语法主要集中在数据查询上,对DELETE、INSERT、UPDATE以及DDL语句的支持非常有限,而且对常用函数的支持也明显不足。

5.使用SQL翻译器

SQL翻译器是这样一种翻译器,它接受开发人员编写的SQL,然后会将SQL翻译成目标数据库系统支持的SQL语句。比如开发人员编写下面的SQL语句来取得人员表中排名前十的

人员:

SQL翻译器会将其翻译成目标数据库系统支持的SQL语句:

MYSQL:

SQLServer:

Oracle:

DB2:

SQL翻译器支持完整的SELECT、INSERT、UPDATE、DELETE以及DDL语句语法,而且支持任意复杂度的SQL语句,而且开发人员只要熟悉一种SQL语法就可以了,无需对SQL语句在不同数据库系统中的实现差异性有了解。

目前SQL翻译器产品有三个,分别是SwisSQL、LDBC和CowNewSQL,SwisSQL是一个非开源的商业公司的公开产品,LDBC和CowNewSQL是开源项目。

5.1 SwisSQL

SwisSQL支持的数据库非常多,包括DB2、ORACLE、MYSQL、INFORMIX、SQLServer、SYBASE、POSTGRESQL等,但是有如下一些重大的缺陷。

1)部分SQL语句解析速度太慢,一些简单SQL的解析竟然用了将近一秒钟,这在大并发的系统中显然是无法忍受的;

2)一些重要的SQL语句有翻译错误;

3)代码可扩展性非常差,对各个数据库的翻译支持是定义在SwisSQLStatement接口的toOracleString、toSQLServerString、toDB2String等方法中的要扩展的话必须到SwisSQLStatement中添加一个新的toxxxString方法,并在所有的实现类(共15个)中添加相应的实现代码;

5.2 LDBC

LDBC是位于SourceForge上的开源项目,地址是http://sourceforge.net/projects/ldbc。要使用LDBC需要下载ldbc.jar,如果需要分析源代码则需要下载ldbc-src.zip或者连接其CVS服务器。

LDBC是以一个JDBC驱动的形式运行的,它会接管系统的SQL请求,将SQL翻译成目标平台SQL,然后再转发给底层数据库的JDBC驱动运行。由于LDBC是以JDBC驱动的形式运行的,所以只要使用标准的JDBC方式使用即可。

在通过这样的方式得到的Connection中执行SQL语句,LDBC就能自动翻译了。

LDBC的缺点如下:

1)对复杂的SQL语句不支持,比如报表开发中常用的子查询、union等不支持;

2)支持的函数数量非常少,对DateDiff、DateAdd、Trim、ABS等函数不支持;

3)可扩展性差,特别是在函数这方面更差,因为在解析SQL语句的时候把函数名当成和Select、Insert一样的关键字,而不是一个标识名,如果要增加新函数的支持必须在语法文件中增加新的关键字。

5.3 CowNewSQL

1)支持较复杂的语法。对于子查询、union等都有良好的支持,支持查询数据库元数据、数据表管理、索引管理、外键管理等高级特性。

2)支持MYSQL、SQLServer、Oracle、DB2等主流数据库系统。

3)支持的函数比较丰富,包括ABS、ACOS、ATAN、CEILING、COS、EXP、LOG、RAND、SQRT等数学函数,CURDATE、DATEADD、DATEDIFF、DAYOFMONTH、HOUR、MONTHS_BETWEEN、DAYS_BETWEEN等日期函数,CHARINDEX、LEFT、LENGTH、LCASE、REPLACE、RIGHT、SUBSTRING等字符串函数,ISNULL、NULLIF等逻辑函数,TO_INT、TO_NUMBER等转型函数,SUM、MAX、MIN、AVG等聚合函数。

4)支持函数的各种常见别名,提高了容错性。比如NOW与GETDATE、CHAR与CHR、LENGTH与LEN、LCASE与LOWER、SUBSTRING与SUBSTR、TOCHAR与TO_CHAR。

5)解析过程分层明确。首先将源SQL语句翻译为一棵抽象语法树(AST),然后将此AST交给各个数据库平台的翻译器去翻译成平台相关SQL。

6)易于增加新的数据库支持。根据SQL语句生成的AST是一棵普通的树,因此任何熟悉树操作的开发人员都可以开发对应数据库平台的翻译器,并不需要开发人员有编译原理方面的基础;

7)易于增加新的函数支持。翻译器把函数名当成普通的标识符看待,这样增加新的函数支持无需修改语法文件,只要在方法翻译器(MethodTranslator)中添加数行代码即可,这也无需开发人员有编译原理的基础;

其缺点如下:对Informix、Sybase、Firbird、Posgtreql等数据库系统还没有提供支持;

目前仅能在Java平台下使用,不过在其发布的开发计划列表中,已经将对.Net、Python等语言的支持加入了开发计划中。

综上,在这三种SQL翻译器产品中,CowNewSQL拥有非常大的优势。耿股将在下一次分享。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180821G1T6OD00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券