Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/396.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java AbstractRoutingDataSource运行时更改映射_Java_Spring_Spring Security - Fatal编程技术网

Java AbstractRoutingDataSource运行时更改映射

Java AbstractRoutingDataSource运行时更改映射,java,spring,spring-security,Java,Spring,Spring Security,我现在在数据库中有2个表: 使用者 用户数据库 在用户I中存储登录名、密码、角色 在user_数据库中,我存储数据库驱动程序、url、密码和用户。 图表数据库 我希望用户登录到我的页面,下一个连接他所做的将被发送到用户数据库。为什么我需要什么?我正在规划流行的电子商务地图,并创建android应用程序,用户可以登录并查看商店数据,添加和查看产品订单。 现在是时候去实践了,我在spring技术方面的知识不多,请解释一下我做错了什么。 web上所有关于AbstractRoutingDataSo

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

  • 使用者
  • 用户数据库
  • 在用户I中存储登录名、密码、角色
    在user_数据库中,我存储数据库驱动程序、url、密码和用户。 图表数据库

    我希望用户登录到我的页面,下一个连接他所做的将被发送到用户数据库。为什么我需要什么?我正在规划流行的电子商务地图,并创建android应用程序,用户可以登录并查看商店数据,添加和查看产品订单。
    现在是时候去实践了,我在spring技术方面的知识不多,请解释一下我做错了什么。 web上所有关于
    AbstractRoutingDataSource
    的示例都在持久性文件中声明了datasource,或者创建DataSourcebean并开始使用
    AbstractRoutingDataSource
    。 在我的项目中,我现在不需要用户连接,我需要从数据库中获取它。我正在尝试使用存储库和这个示例获取 但我在控制器中的
    @Autowired
    上得到null,我认为存储库的连接为null。如何为此存储库设置连接并设置路由?此方法的缺陷是,当我添加用户时,我需要重新启动服务器以刷新连接。
    下一步尝试我现在使用的是class
    User
    implement
    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
    
    }
    
    这是可行的,但当我刷新3-4次用户数据库请求时,我得到了

    User 3450_Menadzer already has more than 'max_user_connections' active connections
    
    手动设置连接映射,不刷新每个方法
    determineCurrentLookupKey
    run我没有这个问题。我认为我的方法不是封闭连接。我怎样才能清洗这个?这是否可能是路由连接的更好方法

    编辑 @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);
        }
    }
    

    首先,每用户数据库是一种非常罕见的设计。如果所有这些数据库都以相同的结构结束,请不要在实际应用程序中这样做,而只需在表和查询中添加用户id即可

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

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

    如果您想学习Spring,可以尝试以下模式(自下而上的描述):

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

    与另一个答案一样,如果同一用户可能同时拥有多个会话,则可以在会话持有者中注入一个单例,该会话持有者将保留实际的数据库连接以及活动会话的数量。这样,每个用户都可以获得一个连接,无论他可以有多少个并发会话。

    我看到了你的老例子,我认为这是可能的,但你需要我解释一下
    sessionDestroyed
    方法在类中实现了什么
    HttpSessionListener
    ?您在哪里执行AbstractRoutingDataSource这是组件?添加连接数据库是在servlet上下文或类中?@seti:我稍微修改了我的旧示例。其思想是map userId->dataSource是一个注入AbstractRoutingDataSource实现中的单例bean,注入HttpSessionListener中,它将关闭数据源并将其从映射中删除。您可以找到一个成功登录事件的侦听器示例,它可以将数据库存储在mapi中编辑我的问题您的逻辑帮助了我。你能解释一下我的旧代码和新代码有什么不同吗(这是可行的)。在旧代码中,我创建数据源映射集并刷新,在新代码中,我从
    @Autowired
    类集合中获取数据源并刷新。你能分享你的代码吗?我有同样的任务后,用户登录,连接到一个基本的数据库和获得数据源,然后CRUD塔特数据源!但我对Spring框架非常陌生,我尝试了一个月,但没有什么好结果。我希望你的代码能帮助我。
    @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);
        }
    }
    
    @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());
        }
    
    }