Unlike Java, in the case of Kotlin, using JDBC directly does not become too redundant
Data acquisition method 3 patterns
EntityManager
@Component
class Clazz1(
private val entityManager: EntityManager
){
fun procSomething() {
val rows = entityManager.createNativeQuery("""
select id, field1 from table1
""").let { q ->
q.resultList
}
}
}
JpaRepository
@Entity
data class AnyData(
val id: Long,
val field1: String
)
interface AnyDataRepository : JpaRepository<AnyData, Long> {
}
@Component
class Clazz1(
private val anyDataRepository: AnyDataRepository
){
fun procSomething() {
val rows = anyDataRepository.findAll()
}
}
JDBC
inline fun <T> iterator(crossinline next: () -> Boolean, crossinline value: () -> T):
AbstractIterator<out T> = object : AbstractIterator<T>() {
override fun computeNext() {
if (next()) {
setNext(value())
} else {
done()
}
}
}
@Component
class Clazz1(
private val dataSource: DataSource
){
fun procSomething() {
dataSource.connection.use { con ->
val rows = con.prepareStatement("""
select id, field1 from table1
""").use { pst ->
pst.executeQuery().use { rs->
iterator(rs::next) {
Pair(rs.getLong(1), rs.getString(2))
}.asSequence().toList()
}
}
...
}
}
}
Transaction 3 pattern
Declarative transaction management
interface AnyDataRepository : JpaRepository<AnyData, Long> {
fun findOneById(id: Long): AnyData?
}
@Component
class Clazz1(
private val entityManager: EntityManager,
private val anyDataRepository: AnyDataRepository
){
// If you raise an exception from inside the method, it will be automatically rollback
// It is convenient to use timeout
@Transactional(timeout = 5)
fun procSomething() {
// row locking(select ... for update)
val data1 = entityManager.find(AnyData::class.java, 1, LockModeType.PESSIMISTIC_WRITE)
?: throw NotFoundException()
data1.name = "name1"
anyDataRepository.saveAndFlush(data1)
entityManager.createNativeQuery("""
update table1 set field1 = ? where id = ?
""").let { q ->
q.setParameter(1, "value1")
q.setParameter(2, 1)
q.executeUpdate()
}
entityManager.flush()
// Remarks:Processes that can not be rollback, such as mail transmission, Do it last
if(!sendMail(from, to, subject, body)){
throw InternalException()
}
}
}
Programmatic transaction management
import javax.persistence.EntityManager
import org.springframework.transaction.support.TransactionTemplate
import org.springframework.transaction.PlatformTransactionManager
@Component
class Clazz1(
private val entityManager: EntityManager,
private val anyDataRepository: AnyDataRepository,
private val transactionManager: PlatformTransactionManager
){
fun procSomething() {
TransactionTemplate(transactionManager).execute {
val data1 = AnyData()
data1.name ="name"
anyDataRepository.saveAndFlush(data1)
entityManager.createNativeQuery("""
update table1 set field1 = ? where id = ?
""").let { q ->
q.setParameter(1, "value1")
q.setParameter(2, 1)
q.executeUpdate()
}
entityManager.flush()
}
}
}
JDBC Transaction
@Component
class Clazz1(
private val dataSource: DataSource
){
fun procSomething() {
dataSource.connection.use { con ->
con.autoCommit = false
try {
_procSomething(con)
con.commit()
} catch (ex: Exception) {
con.rollback()
}
}
}
fun _procSomething(con: Connection) {
con.prepareStatement("""
update table1 set field1 = ? where id = ?
""").use { pst ->
pst.setString(1, "value1")
pst.setLong(2, 1)
q.executeUpdate()
}
}
}
Row locking(select for update) 2 pattern
val data1 = entityManager.find(AnyData::class.java, 1, LockModeType.PESSIMISTIC_WRITE)
?: throw NotFoundException()
val data1 = anyDataRepository.findOneById(1) ?: throw NotFoundException()
entityManager.lock(data1, LockModeType.PESSIMISTIC_WRITE)