关于 Java 数据库连接,您不知道的 5 件事

小夏 科技 更新 2024-01-31

增强您与 JDBC API 的关系。

你认为你知道如何在 J**A 中编程吗?事实是,大多数开发人员只触及了 J**a 平台的表面,并且只学到了足以完成工作的知识。 在本系列中,Ted Neward 深入探讨了 J**A 平台的核心功能,并揭示了一些鲜为人知的事实,以帮助您解决最棘手的编程挑战。 目前,许多开发人员使用 J**a 数据库连接 (JDBC) API 作为数据访问平台,例如 Hibernate 或 SpringMany。 但是,JDBC 不仅在数据库连接中扮演后端角色。 当涉及到JDBC时,你知道的越多,你的RDBMS交互就会越高效。

在这个 5 件事要做的系列中,我将向您介绍一些 JDBC 20 到 JDBC 40 中引入的新功能。 这些新功能在设计时考虑到了现代软件开发的挑战,支持应用程序可扩展性并提高开发人员的工作效率,这是现代 J**A 开发人员面临的两个最常见的挑战。 不同的RDBMS实现为SQL和/或增值功能提供不规则的支持(目的是使程序员的工作更轻松)。 例如,已知 SQL 支持标量运算count()返回满足特定 SQL 筛选规则的行数(更准确地说,是。where谓语)。最重要的是,修改 SQL 返回的值可能很棘手——试图从数据库中获取当前日期和时间会让 JDBC 开发人员甚至最有耐心的程序员发疯(甚至憔悴)。

因此,JDBC 规范通过标量函数为不同的 RDBMS 实现提供了一定程度的隔离覆盖。 JDBC 规范包括一个受支持的操作列表,JDBC 驱动程序应根据特定数据库实现的需要识别和覆盖这些操作。 因此,对于支持返回当前日期和/或时间的数据库,时间查询应该像清单 1 一样简单:

清单 1当前时间?

connection conn = ..// get it from someplacestatement stmt = conn.createstatement();resultset rs = stmt.executequery("");
JDBC 规范附录中提供了 JDBC API 识别的标量函数的完整列表(参见参考参考资料),但给定的驱动程序或数据库可能不支持完整列表。 您可以从connection返回databasemetadata对象来获取给定 JDBC 支持的函数,如清单 2 所示:

清单 2我能得到什么?

connection conn = ..// get it from someplacedatabasemetadata dbmd = conn.getmetadata();
标量函数列表来自各种来源databasemetadata该方法返回一个逗号分隔的string。例如,所有数值标量都由getnumericfunctions()调用列表,对结果执行一个string.split()— 看!— 即刻equals()-testable列表。

创建一个connection对象并使用它来创建一个statement,这在 JDBC 中最常用。 提供sql selectstatement返回一个resultset。然后,通过一个while循环(和iterator没有什么不同)得到resultset直到resultset为空,循环体从左到右一次提取一列。

这整个操作过程是如此普遍,以至于它接近神圣:它这样做只是因为它应该这样做。 唉!事实上,这是完全没有必要的。

许多开发人员没有意识到的是,在过去几年中,JBDC已经有了相当多的增强功能,尽管这些改进已经反映在新版本中。 第一个主要增强功能是在 JDBC 2 中0,在使用 JDK 1 时发生2 时期。 在撰写本文时,JDBC 已发展到 JDBC 40。

jdbc 2.0 中一个有趣的(尽管经常被忽视)增强功能是:resultset这意味着您可以根据需要前进或后退,或两者兼而有之。 但是,这样做需要一些远见,在创建时必须注意 jdbc 调用statement当您需要一个可以滚动的resultset

验证结果集类型。

如果您怀疑驱动程序实际上可能不支持可滚动resultsetS,不管怎样databasemetadata怎么写的,你要打电话gettype()验证resultset类型。 当然,如果你是一个偏执的人,你可能也不相信gettype()的返回值。 可以这么说,如果gettype()隐瞒 关于resultset在返回值中,它们确实会吃掉你。

如果底层 jdbc 驱动程序支持滚动,则一个是可滚动的resultset将从那statement返回。 但在请求它之前,最好弄清楚驱动程序是否支持可滚动性。 你可以这样做databasemetadata对象探测可滚动性,如上所述,可以从任何connection

一旦你有一个databasemetadata对象,一对getjdbcmajorversion()将确定驱动程序是否支持 JDBC 规范,至少支持 JDBC 20 规格。 当然,驱动程序可能会隐瞒它对给定规范的支持程度,因此为了安全起见,请使用您期望的内容resultset类型调用supportsresultsettype()方法。 (英寸)resultset传统上,它是一个常数;我们稍后将讨论它的每个值。 )

清单 3你能滚动吗?

int jdbcversion = dbmd.getjdbcmajorversion();boolean srs = dbmd.supportsresultsettype(resultset.type_scroll_insensitive);if (jdbcversion > 2 ||srs == true)
假设驱动程序回答“是”(如果不是,则需要新的驱动程序或数据库),可以通过将两个参数传递给connection.createstatement()调用以请求可滚动的resultset,如清单 4 所示:

清单 4我想滚动!

statement stmt = con.createstatement( resultset.type_scroll_insensitive, resultset.concur_read_only);resultset scrollingrs = stmt.executequery("select * from whatever");
在通话中createstatement(),你必须特别小心,因为它的第一个和第二个参数都是int之(在 j**a 5 之前,我们不能使用枚举类型!无论什么int值对(包括错误的常量)。createstatement()所有工作。

指定的第一个参数resultset预期的可滚动性应为以下 3 个值之一:

resultset.type_forward_only:这是默认设置,也是我们熟悉和喜爱的流游标。 resultset.type_scroll_insensitive:这resultset但是,如果数据库中的数据发生更改,则支持向后迭代和正向迭代resultset不会被反映出来。 这个是可滚动的resultset可能是最常用的类型。 resultset.type_scroll_sensitive:创建resultset它不仅支持双向迭代,而且还为您提供了数据变化时的实时视图。 第二个参数在下一个技巧中介绍,请稍等片刻。

当你来自statement得到一个resultset向后滚动后,只需调用previous(),即向后滚动一行,而不是向前滚动,比如next()就是这样。 您也可以调用first()返回resultset开始,或调用last()转到resultset或。。。。由你自己决定。

relative()absolute()通过移动指定数量的行(如果是正数,则向前移动,如果是负数,则向后移动)和移动后者来移动前者也很有用resultset,与光标无关。 当然,当前的行数是由getrow()获得。

如果您打算通过拨打电话setfetchdirection()通过指定方向可以帮助在特定方向上进行一些滚动resultset。(无论你朝哪个方向滚动。resultset提前知道滚动方向可以优化其数据检索。 )

JDBC 不仅支持双向resultset,它还支持就地更新resultset。这意味着,您只需要修改数据库中存储的值,而不需要创建新的 SQL 语句来修改当前存储在数据库中的值resultset,然后自动发送到数据库中该行的列。

请求可更新的resultset类似于请求可滚动的resultset过程。 事实上,在这里您将能够:createstatement()使用第二个参数。 无需指定第二个参数resultset.concur_read_only,只需要发送resultset.concur_updateable就是这样,如清单 5 所示:

清单 5我想要一个可更新的结果集

statement stmt = con.createstatement( resultset.type_scroll_insensitive, resultset.concur_updateable);resultset scrollingrs = stmt.executequery("select * from whatever");
假设您的驱动程序支持可更新的游标(这是 JDBC 20 规范的另一个功能,大多数现实数据库都支持),您可以更新resultset通过导航到该行并调用其给定值之一update...方法(如清单 6 所示),如下所示resultsetget...方法。 (英寸)resultset中等update...对于实际的列类型是重载的。 所以要改名price浮点列称为updatefloat("price")。但是,这样做只能更新resultset中的值。 为了将值插入到支持它的数据库中,可以调用它updaterow()。如果用户改变调整**的思路,调用cancelrowupdates()您可以停止所有正在进行的更新。

清单 6更好的方法。

statement stmt = con.createstatement( resultset.type_scroll_insensitive, resultset.concur_updateable);resultset scrollingrs = stmt.executequery("select * from lineitem where id=1");scrollingrs.first();scrollingrs.udpatefloat("price", 121.45f);// ..if (usersaidok) scrollingrs.updaterow();else scrollingrs.cancelrowupdates();
jdbc 2.0 不仅支持更新。 如果用户想要添加一个全新的行,则无需创建新行statement并执行一个insert,只需要调用movetoinsertrow(),为每列调用update...然后调用insertrow()完成工作。 如果未指定列值,则数据库默认为该值sql null(如果数据库架构不允许该列。null,这可能会触发sqlexception

如果,当然resultset如果你支持更新一条线,你将不可避免地支持它deleterow()删除一行。

我差点忘了强调所有这些可滚动性和可更新性适用于preparedstatement(通过。preparestatement()方法传递参数),因为它一直处于 SQL 注入攻击的危险之中,这不仅仅是一个规则statement好多了。

既然所有这些功能在 JDBC 中已经存在了大约 10 年,为什么大多数开发人员仍然痴迷于向前滚动resultset和脱节的访问?

罪魁祸首是可扩展性。 保持最小的数据库连接是支持大量用户通过 Internet 访问公司的关键。 因为滚动和/或更新resultset通常需要开放的网络连接,许多开发人员通常不(或不能)使用这些连接。

值得庆幸的是,JDBC 30 引入了另一种解决方案,以便您可以在使用之前执行相同的操作resultset参与方可以在不要求数据库连接保持打开状态的情况下执行操作。

概念rowset本质上是一个resultset,但它支持连接或断开模型,您需要做的就是创建一个rowset将其指向一个resultset,当它完成填充时,将其作为一个整体resultset,如清单 7 所示:

清单 7RowSet 替换 ResultSet

statement stmt = con.createstatement( resultset.type_scroll_insensitive, resultset.concur_updateable);resultset scrollingrs = stmt.executequery("select * from whatever");if (wantsconnected) jdbcrowset rs = new jdbcrowset(scrollingrs); // connectedelse cachedrowset crs = new cachedrowset(scrollingrs); disconnected
JDBC 还附带了其中的 5 个rowset接口实现(即扩展接口)。 jdbcrowset是一个连接的rowset实现;其余 4 个已断开连接:

cachedrowset只是一个断开连接的rowsetwebrowset是的cachedrowset知道如何将其结果转换为 XML 并再转换回来的子集。 joinrowset是其中之一webrowset并知道如何形成一个sql join无需连接到数据库。 filteredrowset是其中之一webrowset了解如何进一步筛选传回的数据,而无需连接到数据库。 rowsets完整的 j**abeans 意味着它们支持侦听类事件,因此可以在需要时捕获、检查和执行它们rowset任何修改。 事实上,如果rowset有自己的usernamepasswordurldatasourcename属性集(这意味着将使用它。drivermanager.getconnection()创建连接)或datasource属性集(可能由 JNDI 获取),甚至可以管理数据库上的所有操作。 然后你可以在command要执行(调用)的 SQL 在属性中指定execute()然后处理结果,无需再进行任何工作。

通常rowset实现由 JDBC 驱动程序提供,因此实际名称和包或包由您正在使用的 JDBC 驱动程序确定。 以 j**a 5 开头rowset该实现已经是标准发行版的一部分,因此您只需要创建一个...rowsetimpl()让它运行。 (如果您的驱动程序没有提供参考实现,Sun 会提供一个,请参见 参考资料 部分中的链接。 )

虽然rowset它很有用,但有时它不能满足您的需求,您可能需要返回并直接编写 SQL 语句。 在这种情况下,尤其是当您面临大量工作时,您会喜欢批量更新功能,该功能可在单个网络往返中执行数据库中的多个 SQL 语句。

要确定 JDBC 驱动程序是否支持批量更新,请进行快速调用databasemetadata.supportsbatchupdates()可以生成显式支持或不支持的布尔值。 当支持批量更新时(由一些非selectmarkup),所有任务都一个接一个地排队,然后在某个时间点同时更新,如清单 8 所示:

清单 8批量更新数据库!

conn.setautocommit(false);preparedstatement pstmt = conn.preparestatement("insert into lineitems values(?,");pstmt.setint(1, 1);pstmt.setstring(2, "52919-49278");pstmt.setfloat(3, 49.99);pstmt.setboolean(4, true);pstmt.addbatch();// rinse, lather, repeatint updatecount = pstmt.executebatch();conn.commit();conn.setautocommit(true);
默认情况下必须调用它setautocommit(),驱动程序会尝试传递提供给它的每个语句。 除此之外,其余的都简单易懂:使用statementpreparedstatement执行常见的 SQL 操作,但不要调用它们execute(),然后调用executebatch(),排队等待呼叫,而不是立即发送。

准备好各种语句后,在数据库中使用它们executebatch()触发所有语句,这些语句将返回一组整数值,每个值都包含相同的结果,就像它被使用一样executeupdate()一样。

如果批处理中的一条语句出错,如果驱动程序不支持批处理更新,或者批处理中的一条语句返回resultset司机会扔一个batchupdateexception。有时,在引发异常后,驱动程序可能会尝试继续语句。 JDBC 规范不授权行为,因此您应该事先试用驱动程序,以便确切地了解它的工作原理。 (当然,你会想要做单元测试,以确保你在错误成为问题之前发现它们,对吧?)

作为 J**a 开发的一个主题,JDBC API 是每个开发人员都应该熟悉的东西,就像你的右手和左手一样。 有趣的是,在过去几年中,许多开发人员并没有意识到 API 的增强功能,因此,他们错过了本文中介绍的节省时间的技巧。

当然,是否决定使用 JDBC 的新功能取决于您。 要考虑的一个关键因素是您正在使用的系统的可扩展性。 可伸缩性要求越高,数据库的使用就越有限,因此减少的网络流量就越多。rowset、标量调用和批量更新将对您有所帮助。 另外,尝试可滚动和可更新resultset(不是那样的。rowset这会消耗内存)并衡量可伸缩性。它可能没有你想象的那么糟糕。

相似文章

    关于市场,关于热点

    市场。周五,该指数逆转,指数收高。我们来看看上个月日的指数在突破日 后,直到周五接近点时,赚钱效应呈现整体回升。这期间,市场的赚钱效应持续减弱,从西陇科学 到银宝山鑫 再到三博硕,每一次监管后都意味着 进一步弱化,高位继续下滑,核键盛行,空间被压缩到板,虽然已经出现了医药和汽车的主流,但是没有开放空...

    关于慈善,关于文学,莫言是这样说的

    慈善和文学是相互联系的 中国文学要立足本土,表达人类共同价值。中国作家协会副主席 诺贝尔文学奖获得者莫言致辞。摄影 Ryu Shami。月日上午,莫言文艺馆 红高粱文学基地 开馆仪式在莫言故乡高密东北乡举行。中国作家协会副主席 诺贝尔文学奖获得者莫言出席开幕式。墨言文艺馆收藏了墨言的手稿 不同中外文...

    关于这篇小作文

    东方选品的小作文事,你应该知道,据我了解,说白了,就是在餐厅吃饭,我夸厨师的好吃,以后还会经常来。结果,厨房洗菜 切菜 配菜,跑到大厅,扫地,服务员不高兴,跑出去告诉厨师,这碗招牌菜是团队的功劳,大家刚开始吵架,然后总经理跑过来骂我,叫我以后不要来吃饭.俗话说,顾客是衣食之父,顾客就是上帝,可是这个...

    关于考研干货知识

    众所周知,考研是很多学生提高学历 实现人生价值的重要途径。然而,研究生之路并不总是一帆风顺的,它需要努力工作和掌握正确的方法。为了帮助考生在考研之路上更加顺利,本文将分享一些枯燥的知识,从备考策略到答题技巧,为考生提供全方位的指导。.备考策略。.制定计划。在备考过程中,考生需要根据自己的实际情况制定...

    如何使用杆秤

    您可能在菜市场或超市看到过秤,它由一根长杆 两块板和一个弹簧组成,可用于称量物品。这种秤叫杆秤,它是一种很古老的秤,有几千年的历史,它的原理很简单,就是利用杠杆的平衡。那么,杆秤是如何工作的呢?我们如何正确使用它?今天,我们一起来看看这个问题。杆秤的工作原理要了解棒形秤的工作原理,我们首先需要知道什...