简体   繁体   English

Spring Boot + Hibernate Web 应用:如何全局拦截本机和托管实体查询?

[英]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 在保存或更新操作时使用存储在SecurityContextAuthentication object 中的主体名称以及调用保存或更新的主体名称自动将created_bymodified_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.

相关问题 如何在Spring Boot应用程序中测试本地查询? - How to test native queries in Spring Boot application? 如何在Web应用程序中使用托管的Hibernate会话 - How to use managed Hibernate sessions with a web application 在没有实体的文件中休眠本机查询 - Hibernate native queries in a file with no Entity Spring 引导:全局设置 hibernate 序列 - Spring Boot: Set hibernate sequence globally Spring Boot Web绑定时如何拦截错误信息? - How to intercept the error message when spring boot web binding? 如何在 Spring Boot 控制台应用程序中验证实体? - How to validate entity in Spring Boot console application? 使用JPA和Hibernate Web应用程序在Spring-Boot上配置多个数据库 - Configure Multiple Database on Spring-Boot with JPA and Hibernate Web Application 使用spring-boot和spring-data全局启用hibernate过滤器 - Enable hibernate filter globally with spring-boot & spring-data 在非弹簧管理的 web 应用程序中向 spring 引导自动配置类注入属性 - Injecting properties to spring boot auto-configure classes in a non-spring managed web application Hibernate/Spring Boot:如何从回滚中排除实体 - Hibernate/Spring Boot: How to exclude an entity from rollback
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM