当前位置: 首页 > 知识库问答 >
问题:

如何使用hibernate作为orm独立数据库和模式构建spring mvc多租户应用程序

宗政楚
2023-03-14
package com.domain.model;


import javax.persistence.*;

@Entity
@Table
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int employeeId;
    @Column
    private String employeeName;
    public String getEmployeeName() {
        return employeeName;
    }
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
    public int getEmployeeId() {
        return employeeId;
    }
    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }
}

package com.domain.multitenancy;

import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class CurrentTenantIdentifierResolverimpl implements CurrentTenantIdentifierResolver {

    @Override
    public String resolveCurrentTenantIdentifier() {
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String tenantId = attr.getRequest().getParameter("tenantId");
        return tenantId;
    }

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



package com.domain.multitenancy;

import com.domain.master.MasterService;
import org.hibernate.service.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl;
import javax.sql.DataSource;

public class MultiTenantConnectionprovideImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {

    @Override
    protected DataSource selectAnyDataSource() {
        return MasterService.getDataSourceHashMap().get("tenantId1");
    }

    @Override
    protected DataSource selectDataSource(String tenantIdentifier) {
        return MasterService.getDataSourceHashMap().get(tenantIdentifier);
    }
}
package com.domain.master;

import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import java.util.HashMap;

public class MasterService {
    public static HashMap<String, DataSource> getDataSourceHashMap() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/multiten");
        dataSource.setUsername("root");
        dataSource.setPassword("root");

        DriverManagerDataSource dataSource1 = new DriverManagerDataSource();
        dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource1.setUrl("jdbc:mysql://localhost:3306/multiten_1");
        dataSource1.setUsername("root");
        dataSource1.setPassword("root");

        HashMap hashMap = new HashMap();
        hashMap.put("tenantId1", dataSource);
        hashMap.put("tenantId2", dataSource1);
        return hashMap;
    }
}
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
         http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.domain"/>
    <mvc:annotation-driven/>
    <context:property-placeholder location="classpath:application.properties"/>
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
        <property name="packagesToScan">
            <list>
                <value>com.domain.model</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql:false}</prop>
                <prop key="hibernate.multiTenancy">DATABASE</prop>
                <prop key="hibernate.tenant_identifier_resolver">com.domain.multitenancy.CurrentTenantIdentifierResolverimpl</prop>
                <prop key="hibernate.multi_tenant_connection_provider">com.domain.multitenancy.MultiTenantConnectionprovideImpl</prop>
            </props>
        </property>
    </bean>
    <bean id="transactionManager"  class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
 #Application.properties file in classpath
jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/multiten
jdbc.username = root
jdbc.password = root
hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql = true
hibernate.format_sql = false

我举了这个例子

以下是我得到的错误:

org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常为org.springframework.transaction.CanNotCreateTransactionException:无法打开事务的Hibernate会话;嵌套异常为org.hibernate.hibernateException:SessionFactory配置为多租户,但未指定租户标识符org.springframework.web.servlet.frameworkservlet.processRequest(frameworkservlet.java:979)org.springframework.web.servlet.frameworkservlet.doPost(frameworkservlet.java:869)javax.servet.http.servlet.service(httpservlet.java:660)org.springframework.web.servet.service

注意服务器日志中提供了根本原因的完整堆栈跟踪。

共有1个答案

孔鸿云
2023-03-14

事务处理会话;嵌套异常为org.hibernate.hibernateException:SessionFactory配置为多租户,但未指定租户标识符

上面的错误表明没有指定承租人标识符。请仔细检查您的配置和标识符类实现名称。

出现此错误的原因是承租人标识符解析程序需要返回一些默认内容,以防它无法从您选择的策略中找到适当的承租人id(在您的情况下,您试图从请求参数中获取承租人id)。我使用了下面更新的代码,它不再显示错误。

public class CurrentTenantIdentifierResolverimpl implements CurrentTenantIdentifierResolver {

    @Override
    public String resolveCurrentTenantIdentifier() {
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String tenantId = attr.getRequest().getParameter("tenantId");
        if (tenantId==null) {
            //return default tenant
            return "tenantId1";
        }
        return tenantId;
    }

    @Override
    public boolean validateExistingCurrentSessions() {
        return true;
    }
}
 类似资料:
  • 我正在将当前的应用程序迁移到多租户体系结构。由于只有一个代码库,我需要解决多个租户的问题。我使用的是单数据库、多模式的方法。每个租户将被分配一个单独的模式,其中元数据保存在默认模式中。 应用程序是用ASP构建的。NET MVC。我使用Dapper连接到我的SQL Server。我有50个函数,使用直接查询和存储过程调用数据库。当为每个租户初始化dapper时,是否有任何方法可以在不改变函数的情况下

  • 我正在使用spring boot开发一个多租户应用程序。 系统的业务逻辑将根据每个租户进行更改。 例如,应用程序上的特定租户租赁空间可能希望改变使用一些复杂的自定义逻辑计算值的方式。我想为应用程序注册默认行为/依赖项,并允许特定租户覆盖它。 这可以使用Spring Boot完成吗?

  • 任何帮助都将真正用于如何实现这一目标。 我目前有三个独立的应用程序,两个前端运行vue.js和一个后端应用程序,与laravel租赁,只服务于API的,没有前端。 主基URL或后端URL设置为example。com,这是租赁申请。它会自动生成URL子域。实例为租户提供的com 另一个安全域设置。实例com指向我们注册的另一个vue应用程序。效果非常好。 现在我在vue上有了第三个应用程序。js,对

  • 我想知道如何为每个租户提供定制。我想提供在租户想要的每种形式中添加新字段的设施,包括字段名、数据类型等。现在我的问题是如何为这种类型的场景设计数据库表?正如我所想的那样,我们必须给每个表单赋予表单id,每当租户在表单中创建新字段时,应该在数据库表中创建一个新的行,该行应该具有租户id、表单id、字段名称、数据类型等... 现在请给我真正的解决方案的朋友......我需要这个数据库表设计解决方案立即

  • 我正在学习多租户应用程序,以及如何使用PostgreSQL的模式来实现这一点。 在研究这个主题时,我发现了一篇文章,作者描述了在多租户应用程序中使用PostgreSQL模式时的糟糕体验。主要问题是迁移性能差和数据库资源使用率高。 似乎只有一个模式(在租户之间共享表)会比每个租户有一个单独的模式带来更好的性能。但我觉得很奇怪。我的想法正好相反,因为较小表上的索引往往比较大表上的索引轻。 为什么在许多

  • 问题内容: 我需要使用Visual Studio在WinForms中开发一个简单的会计应用程序,例如客户,供应商和会计资料(借方/贷方)等。 我从未开发过使用数据库的独立应用程序,我总是开发过服务器端应用程序(现有的SQL Server等)… 我喜欢用DB开发一个独立的应用程序。我的意思是:创建一个安装项目(setup.exe / setup.msi)并发送给客户,他/她应在Windows pc上