Java 附带了一组核心库,包括定义常用数据类型和相关行为的库,例如 String 或 Date;与主机操作系统交互的实用程序,例如 System 或 File;以及用于管理安全性、处理网络通信以及创建或解析 XML 的有用子系统。 鉴于这组核心库的丰富性,通常很容易找到必要的位和片段,以减少程序员为解决问题而必须编写的代码量。
即便如此,仍有许多有趣Java 库是由发现核心库中存在差距的人员创建的。 例如,Apache Commons“是一个专注于可重用 Java 组件各个方面的 Apache 项目”,并提供大约 43 个开源库的集合(截至撰写本文时),涵盖 Java 核心之外的一系列功能(例如 geometry 或 statistics)或增强或替换 Java 核心中的功能的功能(例如 math 或 numbers)。
另一种常见的 Java 库是系统组件的接口,例如,到数据库系统的接口。 本文着眼于使用这样的接口来连接到 PostgreSQL 数据库并获取一些有趣的信息。 但首先,我将回顾一下库的重要组成部分。
什么是库?
当然,库必须包含一些有用的代码。 但要发挥作用,需要以 Java 程序员可以访问组件以解决手头问题的方式组织代码。
我将大胆地声称,库最重要的部分是其应用程序编程接口 (API) 文档。 许多人对这种文档很熟悉,它通常由 Javadoc 生成,Javadoc 读取代码中的结构化注释并生成 HTML 输出,该输出在页面的左上角面板中显示 API 的包;左下角显示其类;右侧显示库、包或类级别的详细文档(具体取决于主面板中的选择)。 例如,Apache Commons Math 的 API 文档的顶层看起来像

单击主面板中的包会显示在该包中定义的 Java 类和接口。 例如,org.apache.commons.math4.analysis.solvers 显示诸如 BisectionSolver 之类的类,用于使用二分法算法查找单变量实函数的零点。 单击 BisectionSolver 链接会列出类 BisectionSolver 的所有方法。
这种类型的文档可用作参考信息;它并不旨在作为学习如何使用库的教程。 例如,如果您知道什么是单变量实函数并查看包 org.apache.commons.math4.analysis.function,您可以想象使用该包来组合函数定义,然后使用 org.apache.commons.math4.analysis.solvers 包来查找刚创建函数的零点。 但实际上,您可能需要更多面向学习的文档来桥接到参考文档。 甚至可能需要一个例子!
此文档结构还有助于阐明包的含义 - 相关 Java 类和接口定义的集合 - 并显示特定库中捆绑了哪些包。
此类库的代码最常见于 .jar 文件中,它基本上是由 Java jar 命令创建的 .zip 文件,其中包含一些其他有用的信息。 .jar 文件通常创建为编译定义的各种包中所有 .java 文件的构建过程的端点。
访问外部库提供的功能有两个主要步骤
- 确保 Java 编译步骤 - javac - 和执行步骤 - java - 可以通过类路径(命令行上的 -cp 参数或 CLASSPATH 环境变量)访问该库。
- 使用适当的 import 语句来访问程序源代码中的包和类。
剩下的就像使用 Java 核心类(例如 String)进行编码一样 - 使用库提供的类和接口定义编写代码。 简单,是吧? 好吧,可能没那么简单; 首先,您需要了解库组件的预期使用模式,然后才能编写代码。
示例:连接到 PostgreSQL 数据库
用于访问数据库系统中数据的典型使用模式是
- 获取对正在使用的数据库软件的特定代码的访问权限。
- 连接到数据库服务器。
- 构建查询字符串。
- 执行查询字符串。
- 对返回的结果执行一些操作。
- 断开与数据库服务器的连接。
所有这些面向程序员的部分由独立于数据库的接口包 java.sql 提供,它定义了核心客户端 Java 数据库连接 (JDBC) API。 java.sql 包是核心 Java 库的一部分,因此无需向编译步骤提供 .jar 文件。 但是,每个数据库提供程序都会创建自己的 java.sql 接口实现 - 例如,Connection 接口 - 并且必须在运行步骤中提供这些实现。
让我们看看它是如何使用 PostgreSQL 实现的。
获取对特定于数据库的代码的访问权限
以下代码使用 Java 类加载器(Class.forName() 调用)将 PostgreSQL 驱动程序代码引入到执行虚拟机中
import java.sql.*;
public class Test1 {
public static void main(String args[]) {
// Load the driver (jar file must be on class path) [1]
try {
Class.forName("org.postgresql.Driver");
System.out.println("driver loaded");
} catch (Exception e1) {
System.err.println("couldn't find driver");
System.err.println(e1);
System.exit(1);
}
// If we get here all is OK
System.out.println("done.");
}
}
因为类加载器可能会失败,因此在失败时可能会引发异常,所以请将对 Class.forName() 的调用括在 try-catch 块中。
如果使用 javac 编译上面的代码并使用 Java 运行它
me@mymachine:~/Test$ javac Test1.java
me@mymachine:~/Test$ java Test1
couldn't find driver
java.lang.ClassNotFoundException: org.postgresql.Driver
me@mymachine:~/Test$
类加载器需要包含 PostgreSQL JDBC 驱动程序实现的 .jar 文件位于类路径中
me@mymachine:~/Test$ java -cp ~/src/postgresql-42.2.5.jar:. Test1
driver loaded
done.
me@mymachine:~/Test$
连接到数据库服务器
以下代码加载 JDBC 驱动程序并创建与 PostgreSQL 数据库的连接
import java.sql.*;
public class Test2 {
public static void main(String args[]) {
// Load the driver (jar file must be on class path) [1]
try {
Class.forName("org.postgresql.Driver");
System.out.println("driver loaded");
} catch (Exception e1) {
System.err.println("couldn't find driver");
System.err.println(e1);
System.exit(1);
}
// Set up connection properties [2]
java.util.Properties props = new java.util.Properties();
props.setProperty("user","me");
props.setProperty("password","mypassword");
String database = "jdbc:postgresql://myhost.org:5432/test";
// Open the connection to the database [3]
try (Connection conn = DriverManager.getConnection(database, props)) {
System.out.println("connection created");
} catch (Exception e2) {
System.err.println("sql operations failed");
System.err.println(e2);
System.exit(2);
}
System.out.println("connection closed");
// If we get here all is OK
System.out.println("done.");
}
}
编译并运行它
me@mymachine:~/Test$ javac Test2.java
me@mymachine:~/Test$ java -cp ~/src/postgresql-42.2.5.jar:. Test2
driver loaded
connection created
connection closed
done.
me@mymachine:~/Test$
关于以上的一些说明
- 注释 [2] 后面的代码使用系统属性来设置连接参数 - 在本例中,为 PostgreSQL 用户名和密码。 这样可以从 Java 命令行获取这些参数,并将所有参数作为参数包传入。 还有其他用于单独传入参数的 Driver.getConnection() 选项。
- JDBC 需要一个 URL 来定义数据库,该 URL 在上面声明为 String database,并与连接参数一起传递到 Driver.getConnection() 方法中。
- 该代码使用 try-with-resources,该资源在 try-catch 块中的代码完成后自动关闭连接。 Stack Overflow 上对此方法进行了漫长的讨论。
- try-with-resources 提供对 Connection 实例的访问权限,并可以在此处执行 SQL 语句; 任何错误都将由同一个 catch 语句捕获。
使用数据库连接做一些有趣的事情
在我的日常工作中,我经常需要知道为给定的数据库服务器实例定义了哪些用户,并且我使用此 方便的 SQL 代码段 来获取所有用户的列表
import java.sql.*;
public class Test3 {
public static void main(String args[]) {
// Load the driver (jar file must be on class path) [1]
try {
Class.forName("org.postgresql.Driver");
System.out.println("driver loaded");
} catch (Exception e1) {
System.err.println("couldn't find driver");
System.err.println(e1);
System.exit(1);
}
// Set up connection properties [2]
java.util.Properties props = new java.util.Properties();
props.setProperty("user","me");
props.setProperty("password","mypassword");
String database = "jdbc:postgresql://myhost.org:5432/test";
// Open the connection to the database [3]
try (Connection conn = DriverManager.getConnection(database, props)) {
System.out.println("connection created");
// Create the SQL command string [4]
String qs = "SELECT " +
" u.usename AS \"User name\", " +
" u.usesysid AS \"User ID\", " +
" CASE " +
" WHEN u.usesuper AND u.usecreatedb THEN " +
" CAST('superuser, create database' AS pg_catalog.text) " +
" WHEN u.usesuper THEN " +
" CAST('superuser' AS pg_catalog.text) " +
" WHEN u.usecreatedb THEN " +
" CAST('create database' AS pg_catalog.text) " +
" ELSE " +
" CAST('' AS pg_catalog.text) " +
" END AS \"Attributes\" " +
"FROM pg_catalog.pg_user u " +
"ORDER BY 1";
// Use the connection to create a statement, execute it,
// analyze the results and close the result set [5]
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery(qs);
System.out.println("User name;User ID;Attributes");
while (rs.next()) {
System.out.println(rs.getString("User name") + ";" +
rs.getLong("User ID") + ";" +
rs.getString("Attributes"));
}
rs.close();
stat.close();
} catch (Exception e2) {
System.err.println("connecting failed");
System.err.println(e2);
System.exit(1);
}
System.out.println("connection closed");
// If we get here all is OK
System.out.println("done.");
}
}
在以上代码中,一旦有了 Connection 实例,它就会定义一个查询字符串(上面的注释 [4]),创建一个 Statement 实例并使用它来执行查询字符串,然后将其结果放入 ResultSet 实例中,它可以迭代该实例来分析返回的结果,最后通过关闭 ResultSet 和 Statement 实例(上面的注释 [5])来结束。
编译并执行程序会产生以下输出
me@mymachine:~/Test$ javac Test3.java
me@mymachine:~/Test$ java -cp ~/src/postgresql-42.2.5.jar:. Test3
driver loaded
connection created
User name;User ID;Attributes
fwa;16395;superuser
vax;197772;
mbe;290995;
aca;169248;
connection closed
done.
me@mymachine:~/Test$
这是在简单 Java 应用程序中使用 PostgreSQL JDBC 库的一个(非常简单的)示例。 值得强调的是,由于 java.sql 库的设计方式,它不需要像在代码中使用 import org.postgresql.jdbc.*; 这样的 Java import 语句。 因此,无需在编译时指定类路径。 相反,它使用 Java 类加载器在运行时引入 PostgreSQL 代码。
评论已关闭。