Моя текущая попытка (согласно этот ответ) выглядит следующим образом:
@Service
class VacuumDatabaseService(
private val entityManager: EntityManager
) {
fun vacuumAllTables() {
val session = entityManager.unwrap(org.hibernate.Session::class.java)
val sessionImpl = session as org.hibernate.internal.SessionImpl
val connection = sessionImpl.connection()
connection.prepareStatement("VACUUM FULL").execute()
}
}
Но выдает:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No transactional EntityManager available
Аннотирование функции с помощью @Transactional
приводит к:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.reflect.UndeclaredThrowableException
Caused by: org.postgresql.util.PSQLException: ERROR: VACUUM cannot run inside a transaction block
Следующее работает, но кажется опасно неправильным:
@Transactional
fun vacuumAllTables() {
val session = entityManager.unwrap(org.hibernate.Session::class.java)
val sessionImpl = session as org.hibernate.internal.SessionImpl
val connection = sessionImpl.connection()
connection.prepareStatement("END TRANSACTION; VACUUM FULL;").execute()
}
Каков правильный путь?
@JBNizet Потому что я не знал, что это возможно. :D Большое спасибо за замечание. Следующее работает нормально: class VacuumDatabaseService(private val dataSource: DataSource) { fun vacuumAllTables() { dataSource.connection.prepareStatement("VACUUM FULL;").execute() } }
Хотите опубликовать это решение в качестве ответа, чтобы я мог его принять?
Вам действительно нужно закрыть соединение: dataSource.connection.use { it.prepareStatement()... }
Вам просто нужно внедрить DataSource
, получить из него соединение, выполнить свою работу и закрыть соединение.
@Service
class VacuumDatabaseService(
private val dataSource: DataSource
) {
fun vacuumAllTables() {
dataSource.connection.use {
it.prepareStatement("VACUUM FULL").execute()
}
}
}
Обратите внимание на использование use
, которое закрывает соединение после выполнения блока.
Зачем проходить EntityManager и сеанс Hibernate только для того, чтобы получить соединение JDBC? Почему бы вам просто не внедрить Jdbc DataSource, получить из него соединение, выполнить свою работу и закрыть его?