Транзакция JDBC в Kotlin
По умолчанию SQLite фиксирует каждый запрос отдельно.
Флаг autoCommit = false на Connection
складывает шаги в одну транзакцию до явного
commit или rollback.
Два успешных INSERT попадут на диск только
после commit:
import java.sql.DriverManager
fun main() {
DriverManager.getConnection("jdbc:sqlite:txn_ok.db")
.use { connection ->
connection.autoCommit = false
connection.createStatement().use { statement ->
statement.execute(
"""
CREATE TABLE IF NOT EXISTS moves (
id INTEGER PRIMARY KEY,
step TEXT NOT NULL
)
"""
)
}
try {
val first = connection.prepareStatement(
"INSERT INTO moves (step) VALUES (?)"
)
first.setString(1, "load")
first.executeUpdate()
val second = connection.prepareStatement(
"INSERT INTO moves (step) VALUES (?)"
)
second.setString(1, "seal")
second.executeUpdate()
connection.commit()
} catch (ex: Exception) {
connection.rollback()
throw ex
}
}
}
При ошибке между шагами rollback отменяет
несохранённые изменения в рамках транзакции:
import java.sql.DriverManager
fun main() {
DriverManager.getConnection("jdbc:sqlite:txn_fail.db")
.use { connection ->
connection.autoCommit = false
connection.createStatement().use { statement ->
statement.execute(
"""
CREATE TABLE IF NOT EXISTS moves (
id INTEGER PRIMARY KEY,
step TEXT NOT NULL
)
"""
)
}
try {
val insert = connection.prepareStatement(
"INSERT INTO moves (step) VALUES (?)"
)
insert.setString(1, "start")
insert.executeUpdate()
error("stop")
} catch (_: Exception) {
connection.rollback()
}
val count = connection.createStatement()
.executeQuery("SELECT COUNT(*) AS c FROM moves")
if (count.next()) {
println(count.getInt("c"))
}
}
}
Создайте таблицу ledger_tx в bank.db
с полем note, выполните два добавления
в одной транзакции и зафиксируйте их.
Повторите два добавления, но вызовите откат перед
фиксацией и выведите 0 строк в таблице.