我正在使用 PostgreSQL 数据库,我想开始使用 JPA EntityManager
VACUUM FULL
。
版本1
public void doVacuum(){
entityManager.createNativeQuery("VACUUM FULL").executeUpdate()
}
抛出 TransactionRequiredException
版本2
@Transactional
public void doVacuum(){
entityManager.createNativeQuery("VACUUM FULL").executeUpdate()
}
抛出 PersistenceException“VACUUM 无法在事务块内运行”
版本3
public void doVacuum(){
entityManager.createNativeQuery("VACUUM FULL").getResultList()
}
执行真空,但之后我得到 PersistenceException“无结果”
启动这个sql命令的正确方法是什么?
正如 Alay Hay 提到的,使用底层连接是可行的:
public void doVacuum(){
org.hibernate.Session session = entityManager.unwrap(org.hibernate.Session);
org.hibernate.internal.SessionImpl sessionImpl = (SessionImpl) session; // required because Session doesn't provide connection()
java.sql.Connection connection = sessionImpl.connection();
connection.prepareStatement("VACUUM FULL").execute();
}
这是一个不需要转换为 Hibernate Session 内部实现的解决方案。请记住,VACUUM 无法在事务块中运行,这就是为什么您需要将
autoCommit
设置为 true
。
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
connection.setAutoCommit(true);
connection.prepareStatement("VACUUM FULL").execute();
connection.setAutoCommit(false);
}
});
我正在根据其他答案分享两个版本的工作示例。
static int vacuum1(final EntityManager em) throws SQLException {
final var session = em.unwrap(Session.class);
assert session instanceof JdbcSessionOwner;
final var access = ((JdbcSessionOwner) session).getJdbcConnectionAccess();
final var connection = access.obtainConnection();
try (var statement = connection.prepareStatement("VACUUM")) {
return statement.executeUpdate();
}
}
static void vacuum2(final EntityManager em) {
final var session = em.unwrap(Session.class);
session.doWork(c -> {
assert session instanceof JdbcSessionOwner;
try (var statement = c.prepareStatement("VACUUM")) {
try {
final var result = statement.executeUpdate();
assert result == 0;
} catch (final SQLException sqle) {
throw new RuntimeException(sqle);
}
}
});
}