Estoy creando una REST-API con arranque de resorte y me gustaría implementar una estructura multiinquilino para manejar datos. Quiero tener una base de datos llamada Main que tendrá la tabla User , que tendrá datos sobre los usuarios (nombre de usuario, contraseña... y una base de database de campo que indicará qué base de datos se asigna a este usuario). Cada vez que un usuario se registre, se creará su respectivo DB (Este es uno de los puntos en los que estoy enfrentando dificultades). He leído diferentes tutoriales y todos tienen fuentes de Datasource predefinidas en el archivo application.properties . Claramente, este no es el caso aquí, ya que la base de datos para cada usuario se creará "sobre la marcha", o se accederá a ella si ya se creó.
El flujo de trabajo es así (explicado lo más simple posible):
Main y crea la base de datos respectiva para el usuario.Luego, hay muchas preguntas sobre el llenado de las bases de datos cuando se crean automáticamente. Pero lo primero es lo primero :)
Mi pila: POSTGRESQL, Spring Boot
Gracias de antemano.
la tenencia múltiple se puede lograr según lo requiera siguiendo los siguientes pasos.
Map<String, Object> properties = hibernateProperties.determineHibernateProperties( this.properties.getProperties(), new HibernateSettings()); properties.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA); properties.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, this.connectionProvider); properties.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, this.resolver); properties.put(Environment.DIALECT, "org.hibernate.dialect.MySQLDialect");Esta clase también debe implementar el administrador de transacciones de bean con nombre para cada tipo. p.ej
@Bean(name = "tenantTransactionManager") public PlatformTransactionManager transactionManager() { JpaTransactionManager tm = new JpaTransactionManager(); tm.setEntityManagerFactory(this.entityManagerFactory().getObject()); return tm; }implementar la interfaz CurrentTenantIdentifierResolver y el método resolveCurrentTenantIdentifier. Esto debería devolver el nombre de la base de datos del arrendatario en función del usuario que inició sesión actualmente. O el nombre de la base de datos predeterminada si ningún usuario ha iniciado sesión
Un contenedor de contexto seguro para subprocesos para recordar el nombre del inquilino actual
Anote las implementaciones de servicios para las clases de entidad con la anotación @Transactional y pase el nombre del bean del administrador de entidad apropiado, por ejemplo
@Transactional("tenantTransactionManager") // for tenant databasey
@Transactional("transactionManager") // for shared database.Configure un método de creación de esquema de base de datos cuando se registre un nuevo usuario. y mantenga el nombre de la base de datos del inquilino como una de las columnas en la tabla de usuarios en el esquema compartido.
Si usa Spring Security, implemente la interfaz UserDetailsService e implemente el método loadUserByUsername de modo que devuelva un objeto de la clase TenantUser que contenga información adicional (nombre de la base de datos del arrendatario) para el inicio de sesión del usuario.
public class TenantUser extends org.springframework.security.core.userdetails.User { /** The tenand id. */ private String tenantId;Espero que estos pasos te ayuden a lograr lo que quieres. Hay muchos artículos disponibles que explican todos estos pasos en detalle. Mi implementación está profundamente integrada en mi proyecto, por lo tanto, no está en un estado que pueda compartirse como ejemplo de trabajo.
Feliz de responder cualquier otra pregunta.
Encontré la solución completa a mi problema aquí:
Multiusuario: Gestión de múltiples fuentes de datos con Spring Data JPA
Muchas gracias al autor @Cepr0.
Lo único que falta es crear la base de datos sobre la marcha. Actualizaré la respuesta aquí cuando termine mi implementación.
ACTUALIZAR
Creé la base de datos con el siguiente código, fue recomendado por @Milind Barve. Así que gracias.
Class.forName("org.postgresql.Driver"); Connection con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/","postgres", "password"); Statement smt = con.createStatement(); smt.executeUpdate("CREATE DATABASE [name_of_db_here] WITH OWNER DEFAULT");ACTUALIZACIÓN: al inicializar el esquema de cada base de datos recién creada, creé un archivo .sql con todas las creaciones de tablas y uso FlyWay para inicializar cada base de datos recién creada
// INITIALIZE THE DB Flyway flyway = Flyway.configure() .dataSource(dataSource) .target(MigrationVersion.LATEST) .load(); flyway.migrate();