gpt4 book ai didi

java - AbstractRoutingDataSource 在运行时更改映射

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:43:36 24 4
gpt4 key购买 nike

我现在在数据库中有 2 个表:

  1. 用户
  2. 用户数据库

在用户中我存储登录名、密码、角色
在 user_database 中,我存储数据库驱动程序、url、密码和用户。图数据库 enter image description here

我希望用户登录到我的页面,下一次连接他所做的将被发送到用户数据库。为什么我需要什么?我计划绘制流行的电子商务 map 并创建 Android 应用程序,用户可以在其中登录并查看商店数据,可以添加和查看产品订单。
现在该去实践了,我对 Spring 技术的了解很少,当我做错的时候请解释一下。AbstractRoutingDataSource 网络上的所有示例都在持久性文件中声明数据源或创建数据源 bean 并开始使用 AbstractRoutingDataSource。在我的项目中,我现在没有用户连接,我需要从数据库中获取它。我尝试使用存储库和这个例子 https://stackoverflow.com/a/17575648/3037869但是我在 Controller 中的 @Autowired 上得到 null,我认为存储库的连接是 null。如何为此存储库设置连接并设置路由?此方法的缺陷是当我添加用户时我需要重新启动服务器以刷新连接。
接下来尝试我现在​​使用的是类 User 在用户登录后实现 UserDetails 我可以从 getPrincipal() 获取用户连接并添加到 map 。

private void setDataSources() {
HashMap<Object, Object> targetDataSources = new HashMap<>();
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("org.h2.Driver");
dataSourceBuilder.url("jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
dataSourceBuilder.username("sa");
dataSourceBuilder.password("");
targetDataSources.put("auth", dataSourceBuilder.build());
setDefaultTargetDataSource(dataSourceBuilder.build());
if( SecurityContextHolder.getContext().getAuthentication()!=null) {
User user=(User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
System.out.println(user.getUserDatabase().getDriver());
dataSourceBuilder.driverClassName(user.getUserDatabase().getDriver());
dataSourceBuilder.url(user.getUserDatabase().getUrl());
dataSourceBuilder.username("3450_Menadzer");
dataSourceBuilder.password(user.getUserDatabase().getPassword());
targetDataSources.put("user", dataSourceBuilder.build());
}
setTargetDataSources(targetDataSources);
afterPropertiesSet(); //map is refresh when i add this

}

我在构造函数上运行此方法并确定 CurrentLookupKey

protected Object determineCurrentLookupKey() {
if( SecurityContextHolder.getContext().getAuthentication()!=null) {
setDataSources();

return "user";
}

return "auth";
}

这是有效的,但是当我刷新 3-4 次对用户数据库的请求时,我得到了

User 3450_Menadzer already has more than 'max_user_connections' active connections

手动设置连接映射而不刷新每个方法 determineCurrentLookupKey 运行我没有这个问题。我认为我的方法不是断开连接。我怎样才能清理这个?这可能是路由连接的更好方法吗?

编辑@SergeBallesta 我从你的示例中更改了一些代码这是我的 map 类

@Component
@Scope(value = "singleton")
public class DataSourceMap {
private Map<Object,Object> dataSourceMap;
public DataSourceMap()
{
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("org.h2.Driver");
dataSourceBuilder.url("jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
dataSourceBuilder.username("sa");
dataSourceBuilder.password("");
dataSourceMap=new HashMap<Object,Object>();
dataSourceMap.put("auth",dataSourceBuilder.build());
}
public void addDataSource(String session,DataSource dataSource)
{
this.dataSourceMap.put(session,dataSource);
}
public Map<Object,Object> getDataSourceMap()
{
return dataSourceMap;
}
public void removeSource(String session)
{
dataSourceMap.remove(session);
}
}

对于 AbstractRoutingDataSource 我做了一些更改,我添加了 afterPropertiesSet() 因为数据源没有刷新。我做了一些刷新,我没有收到错误,我认为这是有效的。我需要在未来对更多数据库进行测试

@Component
public class CustomRoutingDataSource extends AbstractRoutingDataSource{
@Autowired
DataSourceMap dataSources;
@Override
protected Object determineCurrentLookupKey() {
setDataSources(dataSources);
afterPropertiesSet();
System.out.println("test");
if( SecurityContextHolder.getContext().getAuthentication()!=null) {
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
return request.getSession().getId();
}

return "auth";
}
@Autowired
public void setDataSources(DataSourceMap dataSources) {
System.out.println("data adding");
setTargetDataSources(dataSources.getDataSourceMap());
}

}

最佳答案

首先,每个用户数据库是一种非常不常见的设计。如果所有这些数据库都以相同的结构结尾,请不要在现实世界的应用程序中这样做,而只需在您的表和查询中添加 user_id。

接下来,我在 another answer 中找到了动态 AbstractRoutingDataSource 的另一个(不完整)示例我的。

我的代码(注意从未测试过)和你的问题之间的一个很大区别是我使用 SessionListener 关闭数据库以避免打开的数据库数量无限增长。

如果你以此来学习Spring,你可以试试下面的模式(自下而上的描述):

  • 一个 session 范围的 bean,它将为用户保存实际的数据库连接,应该在第一次请求时创建连接(以确保用户 ID 存在于 session 中)并缓存以供后续使用。 destroy 方法( session 关闭时由 Spring 自动调用)应该关闭连接。
  • 一个AbstractRoutingDataSource,它会被注入(inject)到上述持有者的代理中,并且会向持有者询问实际的数据源

与另一个答案一样,如果同一用户可能有许多同时 session ,您可以在 session 持有者中注入(inject)一个单例,以保持实际的数据库连接以及 Activity session 的数量。这样一来,无论他有多少个并发 session ,每个用户都可以获得一个连接。

关于java - AbstractRoutingDataSource 在运行时更改映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30273593/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com