java中怎么去实现多租户,多租户又是什么

1.什么是多租户

        在Java中,每个租户通常是一个独立的公司或组织,他们希望在共享的环境中隔离自己的数据和配置,多租户之间可以实现资源隔离,也可以共享某个共同的资源数据,在逻辑层面上来看,他们是隔离的,但是底层上还是使用的相同的硬件资源
        多租户的架构,通常应用在Saas程序当中,允许服务提供商通过单一实例为多个客户提供服务,从而提高资源利用率并降低成本。

2.常见的租户数据模型

  • 独立数据库模式(Separate Database Model):每个租户拥有独立的数据库。
  • 共享数据库,独立Schema模式(Shared Database, Separate Schema Model):多个租户共享一个数据库,但每个租户有独立的Schema。
  • 共享数据库,共享Schema模式(Shared Database, Shared Schema Model):多个租户共享一个数据库和一个Schema,租户数据通过逻辑隔离(如租户ID)来区分。

   (1)独立数据库模式实现

        配置多数据源

@Configuration
public class DataSourceConfig {

    @Bean(name = "tenantDataSource")
    @Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public DataSource tenantDataSource() {
        // 动态获取当前租户ID (通常从请求中获取)
        String tenantId = TenantContext.getTenantId();
        
        // 根据租户ID选择对应的数据源
        if (tenantId.equals("tenant1")) {
            return DataSourceBuilder.create()
                    .url("jdbc:mysql://localhost:3306/tenant1_db")
                    .username("root")
                    .password("password")
                    .build();
        } else if (tenantId.equals("tenant2")) {
            return DataSourceBuilder.create()
                    .url("jdbc:mysql://localhost:3306/tenant2_db")
                    .username("root")
                    .password("password")
                    .build();
        }
        throw new RuntimeException("Unknown tenant");
    }
}

使用TenanContext类去获取租客信息

public class TenantContext {

    private static ThreadLocal<String> currentTenant = new ThreadLocal<>();

    public static void setTenantId(String tenantId) {
        currentTenant.set(tenantId);
    }

    public static String getTenantId() {
        return currentTenant.get();
    }

    public static void clear() {
        currentTenant.remove();
    }
}

(2)共享数据库,独立Schema模式实现

        这里用Hibernate实现

        配置类

@Configuration
public class HibernateConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, MultiTenantConnectionProvider connectionProvider, CurrentTenantIdentifierResolver tenantResolver) {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource);
        emf.setPackagesToScan("com.example.demo.model");

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        emf.setJpaVendorAdapter(vendorAdapter);

        Map<String, Object> properties = new HashMap<>();
        properties.put("hibernate.multiTenancy", MultiTenancyStrategy.SCHEMA);
        properties.put("hibernate.tenant_identifier_resolver", tenantResolver);
        properties.put("hibernate.multi_tenant_connection_provider", connectionProvider);

        emf.setJpaPropertyMap(properties);
        return emf;
    }
}

        自定义多租户连接器

@Component
public class SchemaMultiTenantConnectionProvider implements MultiTenantConnectionProvider {

    @Override
    public Connection getConnection(String tenantIdentifier) throws SQLException {
        Connection connection = dataSource.getConnection();
        connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
        return connection;
    }

    @Override
    public Connection getAnyConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 释放连接
    @Override
    public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
        connection.close();
    }
}

        自定义租户解析器

@Component
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {

    @Override
    public String resolveCurrentTenantIdentifier() {
        return TenantContext.getTenantId();  // 返回当前租户的Schema名称
    }

    @Override
    public boolean validateExistingCurrentSessions() {
        return true;
    }
}

         (3)共享数据库,共享Schema模式实现

         实体类

@Entity
@Table(name = "orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "tenant_id")
    private String tenantId;  // 用于区分租户

    private String productName;
    private int quantity;

    // getters and setters
}

        Service层

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    public List<Order> getOrdersForCurrentTenant() {
        String tenantId = TenantContext.getTenantId();
        return orderRepository.findByTenantId(tenantId);
    }

    public Order createOrder(Order order) {
        String tenantId = TenantContext.getTenantId();
        order.setTenantId(tenantId);
        return orderRepository.save(order);
    }
}

        JPA

public interface OrderRepository extends JpaRepository<Order, Long> {

    List<Order> findByTenantId(String tenantId);
}

 3.多租户的实现

      常见的方法包括:

  • Hibernate的多租户支持:Hibernate提供了内置的多租户支持,可以通过配置来实现不同的数据隔离策略。
  • Spring Data JPA:与Spring Boot结合,提供了灵活的多租户数据访问层的实现。
  • 数据库层实现:通过在SQL查询中加入租户ID过滤条件,确保每个租户只能访问自己的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值