JDBC 性能优化技巧

JDBC 性能优化技巧

原文: https://howtodoinjava.com/java/jdbc/best-practices-to-improve-jdbc-performance/

Java 数据库连接(JDBC)是标准应用编程接口(API)的 JavaSoft 规范,允许 Java 程序访问数据库管理系统。 JDBC API 由一组用 Java 编程语言编写的接口和类组成。 使用这些标准接口和类,程序员可以编写连接数据库的应用,发送以结构化查询语言(SQL)编写的查询,并处理结果。 JDBC 面向关系数据库。

虽然不再标准直接在您的应用中使用 JDBC,因为我们有许多更健壮的 API 可以为我们完成这项工作,例如 HiberateiBatis 。 但是,如果由于特定的要求而仍然被您吸引,或者只是在学习它,那么下面的建议将帮助您编写更快速和有效的代码。

JDBC-Icon

Sections in this post:
Use Object Pooling
Consider MetaData Performance
Choose Commit Mode carefully
Save Some Bytes On Network Traffic

让我们直接进入讨论。

几乎始终使用对象池

对象池可以发生在两个方面:

1)连接池:由于在后端数据库中建立网络连接和初始化数据库连接会话会产生开销,因此创建数据库连接通常很昂贵。 反过来,连接会话初始化通常需要耗时的处理来执行用户认证,建立事务上下文以及建立后续数据库使用所需的会话的其他方面。

此外,数据库对所有连接会话的持续管理可能会对应用的可伸缩性施加主要限制因素。 基于并发连接会话的数量,诸如锁,内存,游标,事务日志,语句句柄和临时表之类的宝贵数据库资源都倾向于增加。

启用连接池允许池管理器在关闭连接后将其保留在“池”中。 下次需要连接时,如果请求的连接选项与池中的连接选项匹配,则将返回该连接,而不会产生与服务器建立另一个实际套接字连接的开销。

顺便说一句,您不需要为连接池管理器实现自己的逻辑。 您可以使用服务器上提供的某些功能。 例如:http://people.apache.org/~fhanik/jdbc-pool/jdbc-pool.html

2)语句池:从 JDBC 3.0 开始,JDBC 标准定义了一个语句缓存接口。 设置MaxPooledStatements连接选项将启用语句池。 启用语句池使驱动可以重新使用 Prepared Statement 对象。 关闭PreparedStatement后,它们将返回到池中而不是被释放,并且从池中检索下一个具有相同 SQL 语句的PreparedStatement,而不是针对服务器实例化和准备该语句。

语句缓存可以执行以下操作:

  1. 防止重复创建游标的开销
  2. 防止重复的语句解析和创建
  3. 重用客户端中的数据结构

请确保您的驱动支持此功能,并且默认情况下是否启用它。 如果您以编程方式进行操作,则示例代码可能是这样的。

Properties p = new Properties();
p.setProperty("user", "root");
p.setProperty("password", "password");
p.setProperty("MaxPooledStatements", "200");

connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/JDBCDemo", p);

在此处阅读有关语句池的更多信息:http://docs.oracle.com/cd/B28359_01/java.111/b31224/stmtcach.htm

同时考虑元数据性能

如果要在代码中处理元数据,那么这是需要注意的另一个重要方面。 这里的第一个技巧是使用尽可能多的参数(或过滤器)来获取指定的元数据。 例如,不要像这样调用getTables

DatabaseMetaData dbmd = connection.getMetaData();
ResultSet rs = dbmd.getTables(null,null,null,null);

在将请求发送到服务器时,至少指定模式将避免在每个表的所有表上返回信息:

DatabaseMetaData dbmd = connection.getMetaData();
ResultSet rs = dbmd.getTables(null,"testDB",null,null);

其次,请记住,大多数 JDBC 驱动在选择查询中返回所需数据时,会在提取时填充ResultSetMetaData对象。 使用此信息,而不是从DatabaseMetaData获取数据,这是附加请求,在大多数情况下是可以避免的。

selectStmt = connection.createStatement();
ResultSet rs = selectStmt.executeQuery("SELECT ID,FIRST_NAME,LAST_NAME,STAT_CD FROM EMPLOYEE WHERE ID <= 10");

ResultSetMetaData rsmd = rs.getMetaData();
rsmd.getColumnCount();
rsmd.getColumnName(0);
rsmd.getColumnType(0);
rsmd.getColumnTypeName(0);
rsmd.getColumnDisplaySize(0);
rsmd.getPrecision(0);
rsmd.getScale(0);

提示:可以考虑发出一个虚拟查询并使用返回的ResultSetMetaData来避免查询系统表,而不是使用getColumns获取有关表的数据!

仔细选择提交模式

在编写 JDBC 应用时,请确保考虑提交事务的频率。 每次提交都会导致驱动通过套接字发送数据包请求。 此外,数据库执行实际的提交,通常需要在服务器上进行磁盘 I/O。 考虑为您的应用删除自动提交模式,而改为使用手动提交以更好地控制提交逻辑。

使用的代码是:

Connection.setAutoCommit(false);

在网络流量上节省一些字节

为了减少网络流量,可以查看以下建议并对其进行调整以适合您的应用。

  1. 使用大容量客户端时,请使用addBatch()而不是使用PreparedStatement来插入数据。 这会在一个网络数据包中发送多个插入请求,并为您节省一些字节。
  2. 不要使用“SELECT * FROM TABLE。 而是指定实际需要的列名称。 我建议您将其作为一种习惯,因为我们很多时候都在这样做,却没有意识到它的负面影响。 试想一下,如果您在还要存储 BLOB 的表中执行此操作。 您从数据库中获取了如此重的对象,并且不使用它。 真是浪费
  3. 确保您的数据库设置了最大数据包大小,并且驱动与该数据包大小匹配。 为了获取更大的结果集,这减少了驱动和服务器之间发送/接收的总数据包数量。

这就是这篇文章的全部内容。 如果您有任何疑问,请发表评论。

祝您学习愉快!