如何使用Hibernate/Spring/Tomcat拦截JDBC查询



我正在尝试实现这个答案中概述的解决方案。简而言之:我想为每个数据库连接设置角色,以便为不同的客户提供更好的数据分离。这需要拦截JDBC查询或事务,在查询运行之前设置用户,然后重置用户。这样做主要是为了遵守一些监管要求。

目前,我正在使用Tomcat和Tomcat的JDBC池来连接PostgreSQL数据库。该应用程序是用Spring和Hibernate构建的。到目前为止,我找不到任何拦截查询的方法。

我尝试了Tomcat内置池的JDBC拦截器,但它们必须是全局的,并且我需要访问Web应用程序中的数据,以便将请求关联到数据库用户。据我所见,Hibernate的拦截器只适用于对于这个用例来说级别太高的实体。

我需要的是以下内容:

类ConnectionPoolCallback{void onConnectionRetrieved(连接连接){conn.execute("SET ROLE"+getRole());//getRole有些神奇}void onConnectionReturned(连接连接){conn.execute("重置角色");}}

现在我需要一个地方来注册这个回调。。。有人知道如何实现这样的东西吗?

Hibernate 4支持多租户。对于普通sql,您将需要数据源路由,我相信spring现在已经拥有或是一个插件。

我不会把游泳池图书馆弄得一团糟。

选项1:

正如Adam提到的,使用Hibernate 4的多租户支持。阅读有关Hibernate多租户的文档,然后实现MultiTenantConnectionProvider和CurrentTenantIdentifierResolver接口。

在getConnection方法中,如上所述调用SET ROLE。尽管它处于Hibernate级别,但这个钩子在功能上与您在问题中所要求的非常接近。

选项2:

我尝试了Tomcat内置池的JDBC拦截器,但它们必须是全球性的,我需要从我的Web应用程序访问数据,以便将请求关联到数据库用户。

如果您可以重新配置您的应用程序,将连接池定义为Springbean,而不是从Tomcat获取,那么您可能可以通过代理数据源来添加自己的钩子:

<!-- I like c3p0, but use whatever pool you want -->
<bean id="actualDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${db.url}"/>
<property name="user" value="${db.user}" />
.....
<!-- uses the actual data source.  name it "dataSource".  i believe the Spring tx
stuff looks for a bean named "dataSource". -->
<bean id="dataSource" class="com.musiKk.RoleSettingDSProxy">
<property name="actualDataSource"><ref bean="actualDataSource" /></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource"><ref bean="dataSource" /></property>
....

然后像这样构建com.musiKk.RoleSettingDSProxy:

public class RoleSettingDSProxy implements DataSource {
private DataSource actualDataSource;
public Connection getConnection() throws SQLException {
Connection con = actualDataSource.getConnection();
// do your thing here. reference a thread local set by
// a servlet filter to get the current tenant and set the role
return con;
}
public void setActualDataSource(DataSource actualDataSource) {
this.actualDataSource = actualDataSource;
}

请注意,我实际上还没有尝试过选项2,这只是一个想法。我无法立即想到它不起作用的任何原因,但如果你试图实现它,它可能会因为某种原因而在你身上瓦解。

想到的一个解决方案是利用Hibernate侦听器/回调。但要注意的是,这是非常低的水平和相当容易出错。我自己使用它来获得一定程度的自动化审计日志记录;让它可靠地工作并不是一个很好的开发周期。不幸的是,我不能共享代码,因为我没有它。

http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/listeners.html

最新更新