DEV Community

Cover image for Announcing Kapper 1.2: Cleaner Transactions with Less Boilerplate
Dries Samyn
Dries Samyn

Posted on

Announcing Kapper 1.2: Cleaner Transactions with Less Boilerplate

I'm excited to announce the release of Kapper 1.2, which introduces a small but meaningful enhancement.

In line with Kapper's philosophy of being lightweight and non-intrusive, we've added withTransaction as an extension method to both Connection and DataSource. This addition doesn't abstract away or replace the underlying functionality—it's purely syntactic sugar designed to save you from writing repetitive boilerplate code.

Before: Transactions in Kapper 1.0

Here's an example of how you might execute a couple of queries within a transaction using Kapper 1.0:

dataSource.connection.use {
    try {
        it.autoCommit = false
        it.execute(
            """
             INSERT INTO villains(id, name) 
             VALUES (:id, :name)
              """.trimIndent(),
            "id" to villain.id,
            "name" to villain.name,
        )
        it.execute(
            """
             INSERT INTO battles(super_hero_id, villain_id, battle_date, updated_ts)
             VALUES (:super_hero_id, :villain_id, :date, NOW())
              """.trimIndent(),
            "super_hero_id" to superHero.id,
            "villain_id" to villain.id,
            "date" to date,
        )
        it.commit()
    } catch (ex: SQLException) {
        try {
           it.rollback()
        } catch (rollbackException: Exception) {
           ex.addSuppressed(rollbackException)
        }
        throw ex
    }
}
Enter fullscreen mode Exit fullscreen mode

While this code is clear, it involves a fair amount of boilerplate for managing exceptions and transactions.

After: Transactions in Kapper 1.2

With Kapper 1.2, the same logic can now be written more concisely:

dataSource.withTransaction {
    it.execute(
        """
         INSERT INTO villains(id, name) 
         VALUES (:id, :name)
          """.trimIndent(),
        "id" to villain.id,
        "name" to villain.name,
    )
    it.execute(
        """
         INSERT INTO battles(super_hero_id, villain_id, battle_date, updated_ts)
         VALUES (:super_hero_id, :villain_id, :date, NOW())
          """.trimIndent(),
        "super_hero_id" to superHero.id,
        "villain_id" to villain.id,
        "date" to date,
    )
}
Enter fullscreen mode Exit fullscreen mode

How withTransaction Simplifies Your Code

The withTransaction function automatically:

  • Creates a connection.
  • Starts and commits the transaction.
  • Rolls back the transaction if an exception occurs.
  • Ensures the connection is properly closed.

This results in cleaner, more readable code while retaining the flexibility to use the native JDBC API whenever needed.

Kapper 1.2 is now available on Maven Central. For more details, check out the GitHub repository or explore the examples.

I’d love to hear your feedback—let me know what you think!

Sentry mobile image

Mobile Vitals: A first step to Faster Apps

Slow startup times, UI hangs, and frozen frames frustrate users—but they’re also fixable. Mobile Vitals help you measure and understand these performance issues so you can optimize your app’s speed and responsiveness. Learn how to use them to reduce friction and improve user experience.

Read the guide →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay