JDBC protocol plugin for Gatling load testing framework. Execute SQL queries, inserts, updates, batch operations, raw SQL, and stored procedures against any JDBC-compatible database with connection pooling (HikariCP) and result checks.
- Compatibility
- Installation
- Database Driver Dependencies
- Quick Start
- Protocol Configuration
- Actions
- Checks
- Session Variables
- Examples
- Contributing
- License
| Plugin Version | Gatling | Scala | Java |
|---|---|---|---|
| 1.x.y | 3.13.x | 2.13 | 11+ |
| 0.20.x | 3.13.x | 2.13 | 17+ |
Branch strategy:
maintargets Gatling 3.13.x.
libraryDependencies += "org.galaxio" %% "gatling-jdbc-plugin" % "<version>" % Testgatling("org.galaxio:gatling-jdbc-plugin_2.13:<version>")<dependency>
<groupId>org.galaxio</groupId>
<artifactId>gatling-jdbc-plugin_2.13</artifactId>
<version>${version}</version>
<scope>test</scope>
</dependency>This plugin does not bundle vendor JDBC drivers. You must add the driver for your database separately.
// sbt
libraryDependencies += "org.postgresql" % "postgresql" % "42.7.11" % Test// Gradle Kotlin DSL
gatling("org.postgresql:postgresql:42.7.11")<!-- Maven -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.11</version>
<scope>test</scope>
</dependency>libraryDependencies += "com.mysql" % "mysql-connector-j" % "9.3.0" % TestlibraryDependencies += "com.microsoft.sqlserver" % "mssql-jdbc" % "12.10.0.jre11" % TestlibraryDependencies += "com.oracle.database.jdbc" % "ojdbc11" % "23.7.0.25.01" % TestNote: The quick-start examples below use PostgreSQL. Add the corresponding driver dependency before running them.
docker run -d --name gatling-pg \
-e POSTGRES_USER=test -e POSTGRES_PASSWORD=test -e POSTGRES_DB=test \
-p 5432:5432 postgres:16import org.galaxio.gatling.jdbc.Predef._
import io.gatling.core.Predef._
class JdbcSimulation extends Simulation {
val dbConf = DB
.url("jdbc:postgresql://localhost:5432/test")
.username("test")
.password("test")
.maximumPoolSize(10)
val scn = scenario("JDBC Query")
.exec(
jdbc("select users")
.query("SELECT * FROM users WHERE id = 1")
.check(simpleCheck(_.nonEmpty))
)
setUp(scn.inject(atOnceUsers(1))).protocols(dbConf)
}import static org.galaxio.gatling.javaapi.JdbcDsl.*;
import static io.gatling.javaapi.core.CoreDsl.*;
public class JdbcSimulation extends Simulation {
var dbConf = DB()
.url("jdbc:postgresql://localhost:5432/test")
.username("test")
.password("test")
.maximumPoolSize(10)
.protocolBuilder();
var scn = scenario("JDBC Query")
.exec(
jdbc("select users")
.query("SELECT * FROM users WHERE id = 1")
.check(simpleCheck(simpleCheckType.NonEmpty))
);
{ setUp(scn.injectOpen(atOnceUsers(1)).protocols(dbConf)); }
}import org.galaxio.gatling.javaapi.JdbcDsl.*
import io.gatling.javaapi.core.CoreDsl.*
class JdbcSimulation : Simulation() {
val dbConf = DB()
.url("jdbc:postgresql://localhost:5432/test")
.username("test")
.password("test")
.maximumPoolSize(10)
.protocolBuilder()
val scn = scenario("JDBC Query")
.exec(
jdbc("select users")
.query("SELECT * FROM users WHERE id = 1")
.check(simpleCheck(simpleCheckType.NonEmpty))
)
init { setUp(scn.injectOpen(atOnceUsers(1)).protocols(dbConf)) }
}import org.galaxio.gatling.jdbc.Predef._
import scala.concurrent.duration._
val dataBase = DB
.url("jdbc:postgresql://localhost:5432/test")
.username("user")
.password("pass")
.maximumPoolSize(32)
.blockingPoolSize(32)
.queryTimeout(30.seconds)var dataBase = DB()
.url("jdbc:postgresql://localhost:5432/test")
.username("user")
.password("pass")
.maximumPoolSize(32)
.blockingPoolSize(32)
.queryTimeout(Duration.ofSeconds(30))
.protocolBuilder();val dataBase = DB()
.url("jdbc:postgresql://localhost:5432/test")
.username("user")
.password("pass")
.maximumPoolSize(32)
.blockingPoolSize(32)
.queryTimeout(Duration.ofSeconds(30))
.protocolBuilder()| Setting | Default | Description |
|---|---|---|
maximumPoolSize |
10 | Max connections in HikariCP pool |
minimumIdleConnections |
10 | Min idle connections |
blockingPoolSize |
= maximumPoolSize |
Fixed thread pool for blocking JDBC calls |
connectionTimeout |
1 minute | Connection acquisition timeout |
queryTimeout |
None | Statement query timeout (per query) |
JDBC calls are blocking, so the plugin runs them on a dedicated executor. blockingPoolSize defaults to maximumPoolSize to prevent unbounded native thread growth.
val hikariConfig = new HikariConfig()
hikariConfig.setJdbcUrl("jdbc:postgresql://localhost:5432/test")
hikariConfig.setMaximumPoolSize(16)
val dataBase = DB.hikariConfig(hikariConfig)jdbc("select users")
.query("SELECT * FROM users WHERE status = 'active'")
.check(simpleCheck(_.nonEmpty))Uses prepared statements. {param} placeholders are replaced with ? at execution time.
jdbc("find user")
.queryP("SELECT * FROM users WHERE id = {id} AND status = {status}")
.params("id" -> "#{userId}", "status" -> "active")jdbc("insert user")
.insertInto("users", Columns("id", "name", "email"))
.values("id" -> 1, "name" -> "#{userName}", "email" -> "#{email}")Java / Kotlin:
jdbc("insert user")
.insertInto("users", "id", "name", "email")
.values(Map.of("id", 1, "name", "#{userName}", "email", "#{email}"))Execute any SQL statement (DDL, DML, etc.) without result mapping:
jdbc("create table")
.rawSql("CREATE TABLE IF NOT EXISTS users (id INT PRIMARY KEY, name VARCHAR(100))")Java / Kotlin:
jdbc("create table")
.rawSql("CREATE TABLE IF NOT EXISTS users (id INT PRIMARY KEY, name VARCHAR(100))")Execute multiple insert/update operations in a single batch:
Scala:
jdbc("batch insert").batch(
insertInto("users", Columns("id", "name")).values("id" -> 1, "name" -> "Alice"),
insertInto("users", Columns("id", "name")).values("id" -> 2, "name" -> "Bob"),
)jdbc("batch update").batch(
update("users").set("name" -> "Updated").where("id = 1"),
update("users").set("name" -> "Updated2").where("id = 2"),
)Java / Kotlin:
jdbc("batch insert").batch(
insertInto("users", "id", "name").values(Map.of("id", 1, "name", "Alice")),
insertInto("users", "id", "name").values(Map.of("id", 2, "name", "Bob"))
)Call stored procedures with IN and optional OUT parameters:
Scala:
jdbc("call procedure")
.call("my_procedure")
.params("inParam" -> "#{value}")With OUT parameters (values are stored in the Gatling session):
jdbc("call with out")
.call("my_procedure")
.params("inParam" -> "#{value}")
.outParams("outResult" -> java.sql.Types.INTEGER)Java / Kotlin:
jdbc("call procedure")
.call("my_procedure")
.params(Map.of("inParam", "#{value}"))
.outParams(Map.of("outResult", java.sql.Types.INTEGER))After execution, OUT parameter values are available in the session via #{outResult}.
| Check | Description |
|---|---|
allResults / allResults() |
Full result set as List[Map[String, Any]] |
simpleCheck(predicate) |
Custom boolean predicate over the result set |
simpleCheck(simpleCheckType.NonEmpty) |
Built-in Java/Kotlin check: result is non-empty |
simpleCheck(simpleCheckType.Empty) |
Built-in Java/Kotlin check: result is empty |
jdbc("select users")
.query("SELECT * FROM users")
.check(
simpleCheck(_.nonEmpty),
allResults.saveAs("rows"),
)jdbc("select users")
.query("SELECT * FROM users")
.check(
simpleCheck(simpleCheckType.NonEmpty),
allResults().saveAs("rows")
);The plugin supports Gatling Expression Language (EL) in SQL queries. Use #{variableName} to reference session values.
exec(session => session.set("tableName", "USERS"))
.exec(jdbc("dynamic query").query("SELECT * FROM #{tableName} WHERE id = #{id}")){param}in SQL — prepared statement placeholder (replaced with?)"#{var}"in.params()— Gatling EL, resolves from session at runtime
jdbc("parameterized query")
.queryP("SELECT * FROM users WHERE id = {id}")
.params("id" -> "#{userId}")jdbc("insert user")
.insertInto("users", "id", "name", "active")
.values(Map.of(
"id", 1,
"name", "#{userName}",
"active", true
));# Build
sbt compile
# Run unit tests
sbt test
# Run all tests (unit + integration; integration tests start PostgreSQL via Testcontainers)
sbt test
# Run Gatling example simulation (H2)
sbt "Gatling / testOnly org.galaxio.performance.jdbc.test.DebugTest"
# Check formatting
sbt scalafmtCheckAll
# Format code
sbt scalafmtAllApache License 2.0. See LICENSE for details.