Czar
12/12/2019, 1:20 PM@Component class MyComponent(...) {
fun someFun() {
/* do something non-transactional before the transaction */
inTransaction(txType = TxType.REQUIRED, readOnly = false) {
/* do something inside a transaction */
}
/* do something non-transactional after the transaction */
}
}
What would be the best way to implement the inTransaction
fun?Thiago Nerys
12/12/2019, 1:23 PM@Component
class TransactionHelper {
@Transactional(propagation = Propagation.REQUIRES_NEW)
fun <T> runOnSeparateTx(handler: () -> T): T {
return handler()
}
@Async("limitedExecutor")
@Transactional(propagation = Propagation.REQUIRES_NEW)
fun <T> runOnSeparateTxAsync(handler: () -> T?): CompletableFuture<T?> {
return CompletableFuture.completedFuture(handler())
}
}
dmnk_89
12/12/2019, 1:24 PMTransactionTemplate
dmnk_89
12/12/2019, 1:24 PMCzar
12/12/2019, 1:25 PM@Component
class TransactionSupport : InitializingBean {
@Autowired
private lateinit var m: PlatformTransactionManager
override fun afterPropertiesSet() {
manager = this.m
}
companion object {
private lateinit var manager: PlatformTransactionManager
fun <R> inTransaction(txType: TxType = TxType.REQUIRED, readOnly: Boolean = false, block: () -> R): R? {
val template = TransactionTemplate(manager, buildTransactionDefinition(txType, readOnly))
return template.execute {
block.invoke()
}
}
private fun buildTransactionDefinition(txType: TxType, readOnly: Boolean): TransactionDefinition {
val def = RuleBasedTransactionAttribute()
def.isReadOnly = readOnly
def.setPropagationBehaviorName(PREFIX_PROPAGATION + txType.toString())
return def
}
}
}
Czar
12/12/2019, 1:27 PMinTransaction
as top-level function instead of a companion object
one, but both seem dirty.
What I'm asking is if there is a better way to have nice API like in my usage example where I can just write inTransaction { /* stuff */ }
and not inject a helper manuallyThiago Nerys
12/12/2019, 1:31 PM@Transactional
method on a superclass and extend that wherever you want to use that inTransaction { }
, or creating an Extension fun <T> Any.inTransaction()
calling that "static" implementation.Czar
12/12/2019, 1:35 PMAny.inTransaction
does not make sense to me, why would I need a receiver there? It also doesn't improve on the main problem - static stuff.
I guess it's either static or inheritance or injection?Thiago Nerys
12/12/2019, 1:37 PMAny.inTransaction
makes the inTransaction
method available for any class - even String.
I don't see any other option.dmnk_89
12/12/2019, 2:14 PMConfiguration
instead of Component
- you can setup it later to use as Auto-Configuration
@Configuration
@ConditionalOnBean(PlatformTransactionManager::class)
class TransactionSupport(private val m: PlatformTransactionManager) {
@PostConstruct
fun setup() {
manager = this.m
}
dmnk_89
12/12/2019, 2:18 PMTransactionManager
if you want to release it as library 🙂Jukka Siivonen
12/12/2019, 2:27 PM@Component
class TransactionSupport(
@Autowired transactionTemplate: TransactionTemplate
) {
...
}
(this doesn't answer your original question though)Jukka Siivonen
12/12/2019, 2:29 PMCzar
12/12/2019, 8:38 PMTransactionTemplate
using supplied parameters, like isolation for example.
I actually have configuration based setup too for other stuff, the @Component here was to try this approach out.
Here's my configuration based Command.execute():
private lateinit var STATIC_COMMAND_SERVICE: CommandService
interface Command<T> : Serializable {
fun execute(): T {
return STATIC_COMMAND_SERVICE.execute(this)
}
}
@Configuration
internal class CommandServiceKotlinInitializer(
commandService: CommandService
) {
init {
STATIC_COMMAND_SERVICE = commandService
}
}
with this I can do MyCommand(/* stuff */).execute()
Czar
12/12/2019, 8:39 PMinTransaction
in a similar way to command service, via configuration and private top-level var and public top level function