[英]Spring Boot + Hibernate Web Application: How to globally intercept native and managed entity queries?
Is it possible to place a hook at the low level of the database connection or data source and execute a query just before any other query is executed?是否可以在数据库连接或数据源的低级别放置一个钩子,并在执行任何其他查询之前执行查询?
Hello.你好。
I'd like to be able to intercept all database queries in hibernate and inject execute one simple query before the original query gets sent to the database: SET @SomeSessionVariable = 123346;
我希望能够拦截 hibernate 中的所有数据库查询,并在原始查询发送到数据库之前注入执行一个简单的查询:
SET @SomeSessionVariable = 123346;
. .
Since hibernate uses a lifecycle for its managed entities, I find it a challenge to achieve what I need.由于 hibernate 对其托管实体使用生命周期,因此我发现实现我需要的东西是一个挑战。
In my spring boot application, I'd like to audit data changes using triggers.在我的 spring 启动应用程序中,我想使用触发器审核数据更改。 I want to be able to associate a change with the currently logged in user in the spring application and the only way to do that is to send the id of that user to the database along with any queries, but just before the query gets executed so that the trigger can see the variable in the current connection session.
我希望能够将更改与 spring 应用程序中的当前登录用户相关联,唯一的方法是将该用户的 id 与任何查询一起发送到数据库,但就在查询执行之前即触发器可以看到当前连接session中的变量。
I'm using MySQL and it seems like there's no built in way of doing this.我正在使用 MySQL 似乎没有内置的方法可以做到这一点。 Postgresql does seem to support sending client contexts to the DBMS.
Postgresql 似乎确实支持将客户端上下文发送到 DBMS。
The application is quite huge to refactor to manually send the id.该应用程序非常庞大,需要重构以手动发送 id。
Do you know any other place I could place a global hook in hibernate configuration to be able to intercept both native and managed queries?您知道我可以在 hibernate 配置中放置一个全局挂钩以拦截本机和托管查询的其他地方吗?
If you're using spring-security in your application to authenticate users, you can utilize spring-data-jpa auditing system for your needs.如果您在应用程序中使用 spring-security 对用户进行身份验证,则可以根据需要使用 spring-data-jpa 审核系统。
For example, with a Product
entity it can look like this:例如,对于
Product
实体,它可能如下所示:
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Product {
// id and other fields
@Column(name = "created_by")
@CreatedBy
private String createdBy;
@Column(name = "modified_by")
@LastModifiedBy
private String modifiedBy;
// getters, setters, etc.
}
Also you should put @EnableJpaAuditing
annotation on any of configuration classes.此外,您应该将
@EnableJpaAuditing
注释放在任何配置类上。
By doing this you will tell spring-data to automatically insert created_by
and modified_by
fields into the DB relation on save or update operations, using the name of the principal that is stored in SecurityContext
's Authentication
object and who called the save or update.通过这样做,您将告诉 spring-data 在保存或更新操作时使用存储在
SecurityContext
的Authentication
object 中的主体名称以及调用保存或更新的主体名称自动将created_by
和modified_by
字段插入到数据库关系中。
You can change this default behavior by implementing AuditorAware<T>
interface您可以通过实现
AuditorAware<T>
接口来更改此默认行为
public class CustomAuditorAware implements AuditorAware<String> {
@Override
public Optional<String> getCurrentAuditor() {
// retrieve name, id or anything else from your SecurityContext
}
}
Then you just need to register this AuditorAware
as a bean and point your application to it:然后你只需要将这个
AuditorAware
注册为一个 bean 并将你的应用程序指向它:
@EnableJpaAuditing(auditorAwareRef = "auditor")
@Configuration
public class ApplicationConfig {
@Bean
AuditorAware<String> auditor() {
return new CustomAuditorAware();
}
}
Note, that this auditing mechanism works only with entities, so it won't work with native queries.请注意,此审核机制仅适用于实体,因此不适用于本机查询。 Also there are other ways to implement entity auditing - take a look at this article at Baeldung
还有其他实施实体审计的方法 - 看看Baeldung 上的这篇文章
If you want to modify native sql queries before they are executed you can utilize Hibernate's StatementInspector
:如果你想在执行之前修改原生 sql 查询,你可以使用 Hibernate 的
StatementInspector
:
public class CustomStatementInspector implements StatementInspector {
@Override
public String inspect(String sql) {
// check if query is modifying and change sql query
}
}
Then you should let Spring know you want to use this inspector, and there's an easy way to do this in spring-boot:然后你应该让 Spring 知道你想使用这个检查器,在 spring-boot 中有一个简单的方法来做到这一点:
@Configuration
public class ApplicationConfig {
@Bean
public HibernatePropertiesCustomizer hibernateCustomizer() {
return (properties) -> properties.put(AvailableSettings.STATEMENT_INSPECTOR, new CustomStatementInspector());
}
}
Other ways of configuring StatementInspector
can be found here: How I can configure StatementInspector in Hibernate?可以在此处找到其他配置
StatementInspector
的方法:如何在 Hibernate 中配置 StatementInspector?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.