Aplikacja jest napisana w Spring Boot'cie. Każdy użytkownik ma utworzoną swoją bazę danych (każda baza ma taki sam schemat).
Nazwę bazy użytkownika mam zapisaną w głównej bazie serwisu, wiec na podstawie nazwy użytkownika wiem na jakiej bazie powinienem operować.
Pytanie w jaki sposób na poziomie RESTa łączyć się z konkretną bazą użytkownika i wykonywać na niej zapytania? (Zmiana połączenia nie może być globalna, bo wtedy odpytanie RESTa przez innych mogłoby się odbyć przypadkowo na nieprawidłowej bazie)
zainteresuj się tematem multitenancy, tu masz przykład tutoriala
https://medium.com/swlh/multi-tenancy-implementation-using-spring-boot-hibernate-6a8e3ecb251a
Tworzysz sobie coś w stylu DataSourceProvider
z metodą DataSource getDataSource(String userName)
która w sposób lazy tworzy i zwraca kolejne obiekty DataSource
(z opcją cache w zwłykłej mapie). Tak wyciągnięte DataSource
dla tego usera opakowywujesz w dowolną abstrakcję do dostępu do bazy której używasz (pewnie ORM) i normalnie używasz.
Podejrzewam że chciałbyś żeby wszystkie magie Springowe typu repozytoria ze spring-data
działały - do tego potrzebujesz singleton DataSource
w kontekście aplikacji - można zrobić prostą implementację tego interfejsu, która może mieć wstrzyknięty request scoped bean zwracający nazwę usera wykonującego bieżący request i z pomocą tego beana będzie delegowała już do konkretnego DataSource
.
@IHaveHandedInMyResignation: Skorzystałem z tego artykułu, ale pojawił się problem z niezamykanymi połączeniami po zakończeniu restowego requesta. Close na DataSource.getConnection().close() nic nie daje.
org.postgresql.util.PSQLException: KATASTROFALNY: przepraszamy, mamy już zbyt wiele klientów (pgjdbc: autodetected server-encoding to be ISO-8859-2, if the message is not readable, please check database logs and/or host, port, dbname, user, password, pg_hba.conf)
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:613) ~[postgresql-42.2.16.jar:42.2.16]
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:161) ~[postgresql-42.2.16.jar:42.2.16]
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:213) ~[postgresql-42.2.16.jar:42.2.16]
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:51) ~[postgresql-42.2.16.jar:42.2.16]
Musiałbyś sprawdzić ile masz połączeń do bazy danych. Prawdopodobnie nie zamykasz gdzieś połączenia i masz, na przykład limit 20połączeń, które wykorzystałeś.
Nie rób tych połączeń ręcznie tylko za pomocą jakiegoś Hikari pool, to samo będzie ogarniać połączenia.
Możliwe, że to czego szukasz to Springowy AbstractRoutingDataSource
Pod spodem może leżeć wiele data sourców, mogą być np. podpięte do tych baz użytkowników. Konkretny data source jesteś w stanie wybrać na podstawie kontekstu żądania - nie ma potrzeby ustawiania niczego globalnie. Możesz mieć osobny datasource wskazujący na bazę / schemat należący do danego tenanta, jesteś w stanie zidentyfikować je po kluczu i każdorazowo wybierać datasource spięty z bazą tenanta, który wywołał żądanie.