Chapter 16Lesson 03~175 minutes

JDBC Database Load Testing and Connection-Pool Considerations: Configuration, Design Patterns, and Trade-Offs

A JDBC plan is meaningful only when its connection and SQL model answer a specific database question. The same thread count can represent very different database demand depending on whether every thread owns a connection, shares a pool, executes read-only indexed lookups, or performs writes/transactions.

Direct vs APIPool sizingRead/writePrepared SQLEmbedded vs server

Learning objectives

  • Choose direct DB or application/API load from the layer under test.
  • Choose per-thread or shared JMeter pool semantics deliberately.
  • Separate read-only experiments from write/transaction tests.
  • Use prepared parameters rather than SQL interpolation.
  • Choose embedded, local server, or containerized DB setups for portability and observability.
  • Connect configured/achieved load, pool state, target telemetry, and validity.

1. Mandatory path stays local, free, and read-only

Runnable designs remain H2 2.5.250 on loopback 127.0.0.1:9092, SELECT-only, ≤2 threads. Production databases, managed cloud DBs, paid telemetry/load platforms, shared performance databases, remote RMI, and write stress are optional concepts only and require separate authorization/design.

2. Direct DB load versus application/API load

Direct JDBC Application/API
Measures driver/pool/query/database path directly. Measures web/service/ORM/cache/application pool plus database.
Excellent for SQL/query/connection diagnostics. Required for end-to-end user/application capacity.
Can precisely control client DB connection demand. Connection demand is mediated by application pool/runtime.
Bypasses business validation/security/caching layers. Preserves real application semantics.

Run both when both questions matter—but never merge conclusions. A DB can handle direct reads while the API still bottlenecks in serialization/connection-pool wait, or vice versa.

3. Per-thread versus shared JMeter pool

JMeter pool design Meaning Validity concern
Max connections = 0 Each thread gets its own one-connection pool. Physical connection count scales with active threads.
Shared max = thread count One shared pool can supply each thread without intentional client-side wait. Closer to a common pooled-client pattern but still not the app pool.
Shared max < active threads Threads can wait for JMeter pool connections. Measures client-pool contention plus DB work.
Shared max > needed May open more DB connections than workload requires. Can create artificial target connection pressure.

Max Wait defines how long a thread can wait before the pool throws an error. A pool timeout is a generator/client configuration symptom—not automatically a DB execution failure.

4. Lazy pool versus preinitialized pool

With Preinit Pool=false (default), the first JDBC requests may include connection-establishment time for pool creation. This is useful if session establishment belongs to the experiment; otherwise warm/preinitialize deliberately and separate cold-start from steady-state metrics.

5. Read-only versus write scenarios

Read-only SELECT tests are the mandatory baseline because cleanup and data corruption risk are low. Write scenarios introduce transactions, locks, logs/WAL, indexes, rollback/commit behavior, row ownership, idempotency, cleanup, and potentially irreversible data changes.

A write test should use a dedicated disposable schema/database, synthetic rows tagged to a run, an account granted only the minimum write rights, explicit transaction/rollback design, and verified cleanup. Do not “upgrade” the Chapter 16 lab by granting SA/admin to JMeter.

6. Prepared parameters versus string interpolation

Prepared Select Statement uses ? placeholders plus Parameter values/types. It reduces quoting/type errors and prevents a CSV value such as 1 OR 1=1 from becoming executable SQL text.

Broken construction:

SELECT ID, DESCRIPTION FROM PUBLIC.CATALOG_ITEM WHERE CATEGORY = '${CATEGORY}'

Preferred:

SQL: SELECT ID, DESCRIPTION FROM PUBLIC.CATALOG_ITEM WHERE CATEGORY = ?
Parameter value: ${CATEGORY}
Parameter type: VARCHAR

7. Embedded H2 versus local TCP server

Embedded mode is simplest and removes network transport, but the database runs inside the JMeter JVM/process path and a file DB cannot be opened by another process simultaneously. That complicates independent telemetry and conflates generator/database CPU.

Local H2 TCP server keeps the DB in a separate process while remaining free/local. It is the mandatory chapter choice because session/query telemetry and process utilization are easier to observe.

8. Local server versus containerized server

A container can improve reproducibility/isolation for PostgreSQL/MySQL or H2 server demos, but adds image/runtime/network/filesystem startup state. It is optional. The mandatory path uses a plain Java H2 server so Docker is not required.

If a container is used, pin the DB/driver version, mount only disposable data, bind only loopback, cap resources, and preserve container startup/CPU/memory telemetry separately from JMeter.

9. Driver-specific compatibility

JMeter JDBC support is generic; the vendor driver defines URL syntax, class name, SQL types, timeout support, transaction behavior, and authentication. JMeter lists common classes such as PostgreSQL, H2, MariaDB, SQL Server, Oracle, and others, but you must verify the current vendor driver documentation/version.

The plan and driver version belong together in evidence. A driver upgrade can change connection behavior/performance without JMX changes.

10. Auto-commit and transaction state

The SELECT-only baseline keeps Auto Commit=true. JDBC Request also exposes special query types for Autocommit(false/true), Commit, and Rollback. Those change connection transaction state and belong in explicitly designed transaction tests—not random add-ons around read queries.

11. Query timeout and Max Wait are different clocks

Max Wait limits how long JMeter waits to borrow a connection from its client pool. Query timeout asks the JDBC driver/database to limit query execution time after a connection is acquired. A connection-pool timeout should not be diagnosed as a slow SQL timeout.

12. Result-variable strategy

Variable Names can store returned columns as NAME_1, NAME_#, etc. Result Variable Name stores a Java object list of row maps. The beginner path uses simple scalar variables because they are easy to assert and lower scripting complexity.

13. Configuration-layer boundaries

Layer Examples Do not confuse with
JMeter core JDBC config/request, pool max/wait, variables, timers, assertions Application datasource pool.
Java/JVM driver classpath, heap/GC, TLS trust for DB driver DB query plans/indexes.
OS/network loopback sockets, ephemeral ports, file/cache behavior JMeter pool wait.
Database/SUT sessions, SQL execution, locks, indexes, CPU/I/O Generator CPU/listener cost.
Driver/plugin H2 JDBC JAR; no JMeter plugin required JMeter core version.
CI/container runner/container CPU, mounted JAR/data, startup Database production capacity.

14. Worked scenario

Requirement: “The API is slow and DBA suspects one indexed lookup. We need to know whether that query itself degrades with 20 DB connections.”

  • First run direct JDBC against a disposable/read replica/test DB with the exact prepared SELECT and controlled connection count.
  • Collect JTL latency/elapsed + DB execution/session telemetry + generator state.
  • Separately run API load and inspect the application's actual connection pool.
  • If direct SQL stays fast but API DB-pool wait rises, the application pool/lifecycle may be the bottleneck rather than SQL execution.

15. Decision table

Question Preferred design Evidence
Is SQL itself slow? Direct prepared JDBC + DB telemetry JTL total/acquisition + DB execution/query plan.
Is app pool undersized? Application/API load Application pool wait/usage + DB sessions.
Need safe beginner lab? Read-only local H2 TCP No writes; independent sessions/telemetry.
Need portability in CI? Pinned local Java H2 or optional pinned container Driver/DB versions and runner resources explicit.
User input controls WHERE value Prepared statement Typed binding; no executable interpolation.

16. Evidence contract

Preserve JMeter/Java/driver/DB versions, JDBC URL with credential redaction, pool settings, exact prepared query/parameters, thread/timer model, raw JTL + matching jmeter.log, generator CPU/memory, H2 process CPU/memory, session counts, query statistics, and a validity statement that direct JDBC bypasses application pooling.

Knowledge check

When should you use API load instead of direct JDBC?

What changes when shared max connections is less than active threads?

Why prefer local TCP H2 over embedded H2 here?

Why is Query Timeout different from Max Wait?

Why must driver version be part of evidence?

Next lesson

Diagnose pool/driver/database failures causally

Lesson 4 engineers pool starvation and SQL-construction mistakes, then separates generator/client symptoms from target database behavior.

Official references and version notes

Version and compatibility note

Version-sensitive behavior was rechecked against current primary documentation on 2026-09-05. The course baseline is Apache JMeter 5.6.3 with a Java 17 JDK; JMeter 5.6.3 requires Java 8+. The mandatory database is H2 2.5.250 (released 2026-08-29), whose current engine requirements specify Java 11+ and which is tested with Java 11 and 17. The JDBC driver class is org.h2.Driver. Copy the H2 driver JAR into JMETER_HOME/lib and restart JMeter before authoring/running the JDBC plan. The H2 JAR is a JDBC driver dependency, not a JMeter plugin. JMeter's JDBC Connection Configuration uses Apache DBCP internally. Its documented recommended Max Number of Connections = 0 means each JMeter thread gets its own one-connection pool; a positive value creates a shared pool. JDBC Request latency is set to connection-acquisition time, so pool wait can be separated from total sample elapsed time. H2 server mode is bound to loopback only in this chapter; no -tcpAllowOthers is used.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.