spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
3k stars 1.41k forks source link

Spring Data JPA support native multi-tenant #2591

Closed donhuvy closed 2 years ago

donhuvy commented 2 years ago

We very need this feature. Please implement Spring JPA multi-tenant feature.

Related https://github.com/spring-projects/spring-data-jpa/issues/949 (but it was many years ago).

I checked that, Jakarta EE JPA 3.1 specification (latest version at this time) https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1.html does not support multi-tenant. But Spring Data JPA is not JPA specification only.

Thank you very much! I am waiting this feature in reality.

schauder commented 2 years ago

Is anything keeping you from using the Hibernate/Eclipselink specific solutions?

donhuvy commented 2 years ago

I don't know how to integrated Spring Boot with Spring Data JPA without support multi-tenant. As you know, Spring Data JPA was out-of-the-box for single-tenant web-app, very quickly, just few lines in application.properties , but if I use Hibernate specific solution, I don't know how to get system up and running. Can you help me create a sample for your idea or give me few links, then I will study "Spring + Hibernate without Spring Data JPA"?

schauder commented 2 years ago

This integration would be for Spring Framework to do, not for Spring Data JPA, which would just use the beans provided by Spring Framework and possibly auto-configured by Spring Boot.

And such an integration is already available: https://github.com/spring-projects/spring-framework/issues/18644 Unfortunately I couldn't find comprehensive documentation or examples how to use this feature.

This https://stackoverflow.com/questions/16213573/setting-up-a-multitenantconnectionprovider-using-hibernate-4-2-and-spring-3-1-1 is helpful but kind of confusing and also quite old.

I started to play around with this and as a first step created something that works with data partitioning, although making the tenant information available in Spring is hacky, because I created it before I learned about the existing integration.

I'll leave this open, because I'll want to create more and better examples and maybe eventually a blog post.

schauder commented 2 years ago

Another valuable source is https://callistaenterprise.se/blogg/teknik/2020/10/03/multi-tenancy-with-spring-boot-part3/ It is a little outdated and contains lots of stuff that is specific to their solution and has nothing todo with the Spring Boot/Spring Data JPA/Hibernate integration in itself.

lucasvsme commented 2 years ago

Thank you all for the references.

I was also looking for documentation on this topic recently and made three examples demonstrating approaches to multi-tenancy using Spring Boot 3 and Spring Data JPA.

Hope that helps someone until official docs gets updated.

donhuvy commented 2 years ago

@schauder I tried the solution at https://callistaenterprise.se/blogg/teknik/2020/10/03/multi-tenancy-with-spring-boot-part3/ , as you know, it was out-of-date and inconvenient.

schauder commented 2 years ago

The promised article is done and published: https://spring.io/blog/2022/07/31/how-to-integrate-hibernates-multitenant-feature-with-spring-data-jpa-in-a-spring-boot-application

The examples live in the Spring Data Examples repository: https://github.com/spring-projects/spring-data-examples/tree/main/jpa/multitenant

rodrigorodrigues commented 2 years ago

Hi folks, is there some good way to implement multiple different databases(Oracle, Postgresql, Mysql) with Spring JPA Data?

It seems the SimpleJpaRepository cannot override the entityManager used by default.

I did a very workaround using reflection to set the correct entityManager but I'm pretty sure is not a good idea, would appreciate if someone has a better way to do this.

@Slf4j
@NoRepositoryBean
public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {
    public static MultiTenantEntityManagerFactoryBean multiTenantEntityManagerFactoryBean;

    public CustomRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);

        log.info("Using custom repository");
    }

    private void setDynamicEntityManager() {
        Field field = ReflectionUtils.findField(this.getClass(), "em");
        field.setAccessible(true);
        EntityManager entityManager = multiTenantEntityManagerFactoryBean.getEntityManagerInterface();
        ReflectionUtils.setField(field, this, entityManager);
        log.info("setDynamicEntityManager:entityManagerAfter: {}", entityManager);
    }

    @Override
    public Page<T> findAll(Pageable pageable) {
        log.info("findlAll: {}", pageable);
        setDynamicEntityManager();
        return super.findAll(pageable);
    }
}
schauder commented 2 years ago

@rodrigorodrigues Please don't post new questions to closed tickets.

Anyway, this one does sound like a usage question, which are off topic for this issue tracker. Please post those on Stackoverflow.

rodrigorodrigues commented 2 years ago

Thanks @schauder just sharing the link on Stackoverflow https://stackoverflow.com/questions/73922298/how-to-use-spring-data-jpa-with-multitenant-different-database

robertolos commented 1 year ago

Is it possible to use @TenantId with Spring Data JPA and MongoDB?