使用JDBC存在一些限制,数据库依赖性是其中一个限制。
是否有任何模式或方法可以在JDBC中实现数据库独立性(不使用任何其他ORM框架或工具)。
我试图通过动态多态来实现这一点(根据特定的SQL语法为不同的DBMS创建特定的类并覆盖常见的CRUD操作)。
例如,有没有办法编写通用SQL语句,以便它们几乎可以在每个SQL相关的DBMS中执行?
我认为我有资格回答,作为jOOQ的作者,已经在another answer中提出过。正如我所展示的那样,完全有可能实现你想要做的事情,但如果你想要自己动手,那么你前面还有很长的路要走。
JDBC是一种出色的网络协议抽象,因此它是一个很好的起点。当你继续解决API中更复杂的问题时,有很多需要注意的事情,比如你正在尝试构建的问题。例如:
NULL
值。有时候它有效,有时则不然。java.sql.Date
和java.time.LocalDate
吗?祝好运!TIMESTAMP WITH TIME ZONE
数据类型的解释吗?INTERVAL
类型?真?OUT
参数结合起来BOOLEAN
类型autoCommit
设置为true时,您是否知道某些PostgreSQL语句不起作用?DatabaseMetaData
来反向设计您的架构吗?算了吧!ResultSetMetaData
来发现合格的列名吗?好...正如您所见,即使JDBC对大多数人来说也能很好地完成它的工作(并且上面的每一个都适用于单个数据库,但总是有一个hacky解决方法。但是你想编写一个适用于所有数据库的API,所以你必须修理/解决以上所有问题。相信我。这会让你忙一阵子!
但到目前为止,我们只讨论了绑定到JDBC的难度。我们还没有讨论标准化SQL的难度。所以我们暂时讨论一下:
LIMIT n OFFSET m
很好,是吗?或者是LIMIT m, n
?还是TOP n START AT m
?还是OFFSET m ROWS FETCH NEXT n ROWS ONLY
?如果您想支持旧数据库怎么办?你会推出自己的ROW_NUMBER()
过滤吗? Here, I've documented it for you。SELECT
的FROM
。在其他数据库中,您需要像DUAL
表这样的东西。 There you go, all documented。DUAL
表,直到他们的解析器中断并且你仍然需要它(你好MySQL)SELECT
的FROM
,但他们确实需要FROM
用于WHERE
/ HAVING
/ GROUP BY
(SELECT 1 UNION SELECT 2) UNION ALL SELECT 3
。它适用于所有数据库吗? (我的意思是带括号的嵌套)EXCEPT ALL
? EXCEPT
甚至支持吗?FULL OUTER JOIN
?AS
是否允许在派生表上使用?ORDER BY
子句是否包含引用SELECT
子句中的别名的表达式?或只是引用FROM
子句中的列的表达式?ORDER BY
子句可以包含表达式吗?ORDER BY
子句吗?SUBSTRING()
或SUBSTR()
或INSTR()
或什么?REPEAT()
function on SQLiteVALUES()
构造函数,就像在SELECT * FROM (VALUES (1), (2)) t(a)
中一样?很少有数据库具有本机支持table(column)
)? Here's a funky idea。(a, b) > (x, y)
与此相同:a > x OR a = x AND b > y
。前者在任何地方都不受支持UPDATE .. RETURNING
:
declare
t0 dbms_sql.number_table;
t1 dbms_sql.date_table;
c0 sys_refcursor;
c1 sys_refcursor;
begin
update "TEST"."T_2155"
set "TEST"."T_2155"."D1" = date '2003-03-03'
returning
"TEST"."T_2155"."ID",
"TEST"."T_2155"."D1"
bulk collect into t0, t1;
? := sql%rowcount; // Don't forget to fetch the row count
open c0 for select * from table(t0);
open c1 for select * from table(t1);
? := c0; // These need to be bound as OracleTypes.CURSOR OUT params
? := c1; // These need to be bound as OracleTypes.CURSOR OUT params
end;
如你所见,它可以完全完成。我做到了,它被称为jOOQ。这可能是我职业生涯中最大的挑战,而且很有趣。 jOOQ 3.10 will feature a parser,可以translate from a SQL string (in any dialect) to another SQL string (in a specific dialect),这是供应商不可知论的下一级别。
但到达这里还有很长的路要走。在我做jOOQ(2009年开始)之前,我已经深入研究了Oracle SQL和基于JDBC的内部框架(就像你计划编写的那样)。我写过jOOQ,因为我看到很多内部框架正在编写,但没有一个能够很好地完成工作。开发商总是处理SELECT
.. FROM
.. WHERE
- 这是容易的部分。有些人设法在游戏中获得JOIN
,也许GROUP BY
就是这样。然后他们放弃了这项任务,因为他们有更重要的事情要做,而不是维护无聊和错误的基础设施软件。
现在,我不知道你自己的动机是什么,但我的建议是:
您可以尝试构建自己的jOOQ(或Hibernate)。这是一个有趣的挑战。但如果您有最后期限,我建议您查看以上选项。
首先,数据库独立性很难。真的,真的很难;要在不使用ORM或其他工具的情况下实现它,您将需要交换解决方案设计的其他方面。简化和可维护性将受到影响,实施解决方案的努力也将受到影响。
所以,我真的非常确定这是一个高优先级的要求 - 假设“如果我们想从Oracle切换到SQL Server会怎么样”的问题 - 在我看来 - 没有足够的理由来承担额外的费用。 。
如果您必须提供此功能,ORM是迄今为止最简单的方法。 ORM框架在设计时考虑了数据库独立性(其复杂性至少部分归因于该要求)。他们通过将数据库实现抽象到更高级别来实现这一目标;而不是在SQL语句中思考,我们鼓励您考虑域对象。
说了这么多......
我已经提供了一个解决方案(不是Java,但原则就是这个),它允许数据库独立。我们将SQL语句存储为资源,并通过资源文件加载它们。默认值为ANSI SQL,它应该适用于任何现代SQL兼容的数据库。
我们为每个支持的数据库风格(在我们的例子中是MySQL和Oracle)提供了资源文件,并使用覆盖来加载特定于数据库的SQL语句(如果它们存在)。
这在大多数语言中都像国际化一样 - 首先查找特定于语言环境的字符串,如果找不到,则回退到默认字符串。
Java的资源包将使这很容易。在您的应用程序中不对您的SQL进行硬编码还有其他好处 - 在不更改应用程序代码的情况下修复数据库问题要容易得多,您可以将修复程序部署为“资源”更新而不是发布新的二进制文件等。
正如我在my book中解释的那样,有两种方法可以解决数据库的可移植性:
但是,由于您明确声明:
是否有任何模式或方法可以在JDBC中实现数据库独立性(不使用任何其他ORM框架或工具)。
您需要使用JDBC API解决此问题,对吧?
实现这一目标的唯一方法是在不采用实际意味着实现自己的数据访问框架的ORM或jOOQ方法的情况下,为每个受支持的数据库使用自定义DAO。
因此,您可以定义服务层使用的DAO接口,例如ProductDAO
,并为每个受支持的数据库实现每个接口:
OracleProductDAOImpl
MySQLProductDAOImpl
PostgreSQLProductDAOImpl
SQLServerProductDAOImpl
或者,您可以使用单个ProductDAOImpl
,但是您需要使用存储过程并确保每个存储过程都在数据库中实现:
所以,虽然它是可能的,但基本上我们在2000年初的时候我们没有Hibernate或者jOOQ。根据我的经验,与使用成熟的数据访问框架相比,它的工作量更大。
在我看来,你真正想通过创建一个允许你一般访问数据库的库来构建它,就像许多ORM已经做的那样。
你试过jOOQ吗?它与其他ORM完全不同,并且可以满足您的需求。人们可以将其称为“工具”,但我还可以将您想要构建的内容称为“工具”。
jOOQ努力成为一种java本地语言,用于进行便携式数据库调用,所以听起来就像你正在寻找的那样。
虽然(很晚)参加聚会并且没有带来任何新的东西,但我想赞一下并扩大Neville's和Vlad's的答案(作为一个合理的选择)。
像jOOQ和Hibernate这样的框架可能是更好的方法,特别是如果你想要获得的东西是完全通用的(即处理大多数可以想象的数据库操作)而不是少数涉及SQL的特定任务。但是,因为看起来它们不适合你,所以以这种或那种方式外化SQL实际上可能会让你走得太远(从SQL方言的角度来看,不一定来自Lukas' answer之前很好地概述的JDBC绑定问题) 。
我之前曾在Oracle和DB2上运行过基于Java的自定义ETL引擎(成功)。您可以想象,我们需要在速度方面获得最佳查询,我们的DBA正在使用本书中的每一个技巧优化它们,然后是一些!因此,我们不仅要容纳2种SQL方言,而且我们必须执行的查询也是高度自定义的(提示等)......我们解决的解决方案是使用模板引擎在运行时生成SQL(Velocity) ,当时)和自定义模板,为目标数据库量身定制(可能类似于Hibernate或jOOQ构建最终SQL的方式)。诚然,我们有自己的“背景”,具有明确的需求......