栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

根据登录用户在运行时更改数据库架构

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

根据登录用户在运行时更改数据库架构

假设条件

由于我尚无信誉在您的问题下发表评论,因此我的回答基于以下假设:

  • 可通过Spring JSR-330提供程序(如)访问用于当前用户的当前模式名称

    private javax.inject.Provider<User> user; String schema = user.get().getSchema();
    。理想情况下,这是基于ThreadLocal的代理。

  • 要构建以

    DataSource
    您需要的方式完全配置的,需要相同的属性。每次。唯一不同的是架构名称。(也很容易获得其他不同的参数,但这对于这个答案来说太过分了)

  • 每个模式都已经使用所需的DDL进行了设置,因此无需hibernate即可创建表或其他内容

  • 除了名称之外,每个数据库架构看起来都完全相同

  • 每当相应的用户向您的应用程序发出请求时,您都需要重用DataSource。但是,您不希望将每个用户的每个数据源都永久存储在内存中。

我的解决方案

结合使用ThreadLocal代理获得模式名称和一个Singleton-
DataSource,它在每个用户请求上的行为都不同。该解决方案的灵感来自您对

AbstractRoutingDataSource
Meherzad的评论和自己的经验的提示。

动态的
DataSource

我建议促进

AbstractDataSource
Spring的发展,并像实施它一样
AbstractRoutingDataSource
。代替静态
Map
方法,我们使用番石榴缓存来获得易于使用的缓存。

public class UserSchemaAwareRoutingDataSource extends AbstractDataSource {    private @Inject javax.inject.Provider<User> user;    private @Inject Environment env;    private LoadingCache<String, DataSource> dataSources = createCache();    @Override    public Connection getConnection() throws SQLException {        return determineTargetDataSource().getConnection();    }    @Override    public Connection getConnection(String username, String password) throws SQLException {        return determineTargetDataSource().getConnection(username, password);    }    private DataSource determineTargetDataSource() {        String schema = user.get().getSchema();        return dataSources.get(schema);    }    private LoadingCache<String, DataSource> createCache() {        return CacheBuilder.newBuilder().maximumSize(100).expireAfterWrite(10, TimeUnit.MINUTES).build(    new CacheLoader<String, DataSource>() {      public DataSource load(String key) throws AnyException {        return buildDataSourceForSchema(key);      }    });    }    private DataSource buildDataSourceForSchema(String schema) {        // e.g. of property: "jdbc:postgresql://localhost:5432/mydatabase?currentSchema="        String url = env.getRequiredProperty("spring.datasource.url") + schema;        return DataSourceBuilder.create() .driverClassName(env.getRequiredProperty("spring.datasource.driverClassName")) [...] .url(url) .build();    }}

现在,您有了一个“数据源”,它对每个用户的作用都不同。创建数据源后,它将被缓存10分钟。而已。

使应用程序知道我们的动态数据源

集成我们新创建的DataSource的地方是Spring上下文已知的DataSource单例,并在所有bean中使用,例如EntityManagerFactory

因此,我们需要一个等效的方法:

@Primary@Bean(name = "dataSource")@ConfigurationProperties(prefix="spring.datasource")public DataSource dataSource() {    return DataSourceBuilder.create().build();}

但它必须比基于DataSourceBuilder的普通属性更具动态性:

@Primary@Bean(name = "dataSource")public UserSchemaAwareRoutingDataSource dataSource() {    return new UserSchemaAwareRoutingDataSource();}

结论

我们有一个透明的动态数据源,它每次都使用正确的数据源。

公开问题

  • 没有用户登录时该怎么办?是否没有数据库访问权限?
  • 谁制定计划?

免责声明

我尚未测试此代码!

编辑:

Provider<CustomUserDetails>
使用Spring
实现,您需要将此定义为原型。您可以利用Spring对JSR-330和Spring Securitys SecurityContextHolder的支持:

@Bean @Scope("prototype")public CustomUserDetails customUserDetails() {    return return (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();}

您不再需要

RequestInterceptor
UserProvider
或控制器代码来更新用户。

这有帮助吗?

EDIT2
仅作记录:不要

CustomUserDetails
直接引用bean。由于这是一个原型,因此Spring将尝试为该类创建代理,
CustomUserDetails
在我们的情况下,这不是一个好主意。因此,只需使用
Provider
即可访问此bean。或使其成为接口。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/466327.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号