我现在在数据库中有2个表:
在用户中我存储登录名,密码,角色
在user_database中,我存储数据库驱动程序,URL,密码和用户。
图数据库
我希望用户登录我的页面,下一次连接他所做的将被发送到用户数据库。为什么我需要什么?我刨图流行电子商务并创建用户登录和查看商店数据的Android应用程序,可以添加和查看产品订单。
现在是时候去练习了,我对弹簧技术的知识很小,请在我做错的时候向我解释一下。
web AbstractRoutingDataSource
上的所有示例都在持久性文件中创建声明数据源或创建数据源bean并开始使用AbstractRoutingDataSource
。
在我的项目中,我现在没有用户连接,我需要从数据库中获取此信息。我试着使用存储库和这个例子
https://stackoverflow.com/a/17575648/3037869
但我在控制器的@Autowired
上得到null,我认为存储库的连接是空的。如何为此存储库设置连接并设置Route?缺陷此方法是当我添加用户时我需要重启服务器来刷新连接。
接下来尝试我现在使用的是User
类UserDetails
用户登录后我可以从getPrincipal()
获取用户连接并添加到地图。
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
}
我在constuctor和determineCurrentLookupKey
上运行此方法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我改变了你的例子中的一些代码 这是我的地图类
@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()
beacuse数据源不刷新。我做了一些刷新,我没有得到错误,我认为这是有效的。我需要在将来为更多数据库测试这个
@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());
}
}
答案 0 :(得分:2)
首先,每个用户数据库是一种非常罕见的设计。如果所有这些数据库都以相同的结构结束,请不要在真实世界的应用程序中执行此操作,而只需在表和查询中添加user_id。
接下来,我在我的another answer中找到了动态AbstractRoutingDataSource的另一个(不完整)示例。
我的代码(谨防从未测试过)与您的问题之间的一个重大区别是我使用SessionListener来关闭数据库,以避免开放数据库的数量无法正常增长。
如果您要学习Spring,可以尝试以下模式(自下而上的描述):
AbstractRoutingDataSource
,将向代理注入上方持有者,并将实际数据源提供给持有者与另一个答案一样,如果同一个用户可能同时拥有多个会话,那么您可以在会话持有者中注入一个单例,以保持实际数据库连接以及活动会话数。这样,无论他有多少并发会话,每个用户都可以获得一个连接。