[Practical Project] Single data source and multiple databases to achieve multi-tenancy

Preface

Multi-Tenancy is a software architecture design pattern that aims to enable a single application to provide services to multiple tenants (such as different organizations, users, or customers) at the same time. Each tenant has independent data and configuration. and are isolated from each other. Implementing a multi-tenant architecture can help enterprises reduce costs, simplify management, and increase efficiency.

Before designing a multi-tenant system, we need to clarify the business requirements and expected goals. Do you want complete isolation between tenants, or allow some shared resources? We need to consider the following aspects:

Data isolation: The data of each tenant should be isolated from each other, and different tenants cannot directly access or share data. Data isolation can be achieved by using separate databases or using tenant IDs in data tables to differentiate.

Identity authentication and authorization: A multi-tenant system needs to support the identity authentication and authorization of each tenant to ensure that only legitimate users can access their own tenant resources.

Horizontal expansion: Multi-tenant systems may face the challenge of a large number of users and data growth, so they need to have the ability to horizontally expand to maintain high performance and reliability of the system.

Configuration management: Each tenant may have different configuration needs, such as parameter settings for integration with mail, payment, storage, etc. Therefore, a flexibly configurable mechanism should be provided to enable tenants to customize it according to their needs.

Security and Isolation: Multi-tenant systems require secure isolation between tenants to prevent potential data leaks and access conflicts. When designing the system, the protection of sensitive data and the prevention of various attacks should be taken into consideration.

Resource utilization: In order to improve resource utilization, you can consider sharing certain common resources, such as computing resources, storage space, and network bandwidth. This reduces costs and provides greater efficiency.

Four implementation options for multi-tenancy

Common design solutions are roughly divided into 4 types:

1. All tenants use the same data source and the same data table in the same database (single data source, single database, single data table) 2.
All tenants use the same data source and different data tables in the same database (single data source, single database, multiple data tables)
3. All tenants use different data tables in different databases under the same data source (single data source, multiple databases, multiple data tables)
4. All tenants use different data tables in different databases under different data sources (multiple data sources, multiple databases, multiple data tables)
Insert image description here

The first and second types are relatively simple. Our article mainly explains the third type

Single data source multiple databases

The ultimate goal of multi-tenancy is to achieve data isolation. In multiple databases with multiple data sources, that is, when a new tenant is registered, a database and corresponding database tables must be created.
Now there is a question, how to dynamically create a database?

Implementation ideas

1. Create a database: You can use the traditional method to create it through sql statements.
2. Create a database table: After creating the database, use sql statements to create the table.

The following code uses sql to read the xml file to create

Code

Create an xml file under resources:
Insert image description here

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <statement>
        <name>create-tenant</name>
        <script>
            DROP DATABASE IF EXISTS `sys_user${
    
    tenant_id}`;
            CREATE DATABASE ${
    
    database};
            USE ${
    
    database};

            CREATE TABLE `sys_user` (
            `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
            `dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
            `user_name` varchar(30) NOT NULL COMMENT '用户账号',
            `nick_name` varchar(30) NOT NULL COMMENT '用户昵称',
            `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)',
            `email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
            `phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码',
            `sex` char(1) DEFAULT '0' COMMENT '用户性别(012未知)',
            `avatar` varchar(100) DEFAULT '' COMMENT '头像地址',
            `password` varchar(100) DEFAULT '' COMMENT '密码',
            `status` char(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
            `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
            `login_ip` varchar(128) DEFAULT '' COMMENT '最后登录IP',
            `login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
            `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
            `create_time` datetime DEFAULT NULL COMMENT '创建时间',
            `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
            `update_time` datetime DEFAULT NULL COMMENT '更新时间',
            `remark` varchar(500) DEFAULT NULL COMMENT '备注',
            `auth_id` varchar(30) DEFAULT NULL COMMENT '其他项目用户id(积分)',
            `ding_id` varchar(50) DEFAULT NULL COMMENT '用户dingid',
            `tenant_id` varchar(100) DEFAULT NULL COMMENT '公司id',
            `open_id` varchar(50) DEFAULT NULL COMMENT '微信用户唯一标识',
            PRIMARY KEY (`user_id`) USING BTREE
            ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='用户信息表';
                 </script>
    </statement>
</document>

This is the corresponding statement to create a database.

Get information from xml file:

@Component
public class ExecSqlConfig {
    
    
    private final Map<String, String> sqlContainer = new HashMap<>();

    public ExecSqlConfig() throws Exception {
    
    
        // 1.创建Reader对象
        SAXReader reader = new SAXReader();
        // 2.加载xml
        InputStream inputStream = new ClassPathResource("create-library.xml").getInputStream();
        Document document = reader.read(inputStream);
        // 3.获取根节点
        Element root = document.getRootElement();

        // 4.遍历每个statement
        List<Element> statements = root.elements("statement");
        for (Element statement : statements) {
    
    
            String name = null;
            String sql = null;
            List<Element> elements = statement.elements();
            // 5.拿到name和script加载到内存中管理
            for (Element element : elements) {
    
    
                if ("name".equals(element.getName())) {
    
    
                    name = element.getText();
                } else if ("script".equals(element.getName())) {
    
    
                    sql = element.getText();
                }
            }
            sqlContainer.put(name, sql);
        }
    }

    public String get(String name) {
    
    
        return sqlContainer.get(name);
    }

}

sql execution script:
read the information in the ExecSqlConfig file in the script

@Component
public class ExecSqlUtil {
    
    
    @Autowired
    private   ExecSqlConfig execSqlConfig ;

    @Autowired
    private  DataSource dataSource ;
/**
 * @description: 把模板中的数据库名称替换为新租户的名称
 * @author: 
 * @date: 2023/9/27 15:05
 * @param: [name , replaceMap]
 * @return: void
 **/
    @SneakyThrows
    public  void execSql(String name, Map<String, String> replaceMap) {
    
    
        try {
    
    
            // 获取SQL脚本模板
            String sql = execSqlConfig.get(name);

            // 替换模板变量
            for (Map.Entry<String, String> entity : replaceMap.entrySet()) {
    
    
                sql = sql.replace(entity.getKey(), entity.getValue());
            }
            ScriptRunner scriptRunner = new ScriptRunner(dataSource.getConnection());

            // 执行SQL
           scriptRunner.runScript(new StringReader(sql));
        }catch (Exception e){
    
    
            e.printStackTrace();
        }

    }

}

Business logic

public void addTenantLibrary(TanentModel tanentModel) {
    
    
        try {
    
    
            if (!(tanentModel.getDescription().isEmpty()||tanentModel.getTenantContact().isEmpty()||tanentModel.getTel().isEmpty()||tanentModel.getTenantName().isEmpty())){
    
    
                //判断数据源中是否已经存在该数据库
               int flag= tantentMapper.insertTantentAdmin(tanentModel.getTenantName());
               if (flag>0){
    
    
                   throw new Exception("已存在该数据库");
               }else {
    
    
                   Map<String,String> map=new HashMap<>();
                   map.put("${database}",tanentModel.getTenantName());
                   map.put("${project_name}",tanentModel.getTenantName());
                   map.put("${leader}",tanentModel.getTenantContact());
                   map.put("${phone}",tanentModel.getTel());
                   map.put("${description}",tanentModel.getDescription());
                   execSqlUtil.execSql("create-tenant",map);

               }
            }
        }catch (Exception e){
    
    
            e.printStackTrace();
            throw new RuntimeException(e.getMessage()); // 将异常信息作为响应的一部分返回给前端
        }
    }

In the business logic code, map.put(“${database}”,tanentModel.getTenantName()); is the variable in the replaced xml file

Summarize

In a multi-tenant architecture, single data source multiple databases is a common implementation solution. By using different database instances or database schemas, we can achieve independent data storage for each tenant and maintain isolation from each other. In this article, we discuss implementation options and some key considerations for single data source multiple databases.

In summary, the single data source multi-database solution provides the following advantages for multi-tenant systems:

Data isolation: Each tenant has an independent database, and data does not interfere with each other, ensuring the isolation and security of tenant data.

Performance optimization: By dispersing tenant data into multiple databases, the load pressure on a single database can be reduced and the system performance and throughput can be improved.

Scalability: When the number of tenants increases, the system can be expanded horizontally by adding new database instances or database servers to meet growing business needs.

Fault tolerance: The single data source and multiple database solution reduces the interaction between tenants. When a database fails, other databases can still run normally, improving the fault tolerance and availability of the system.

When implementing a single data source multi-database solution, we need to pay attention to the following key factors:

Data migration and synchronization: For existing multi-tenant systems, migrating existing data to a new database may require a certain amount of work. At the same time, in order to maintain data consistency, we need to ensure data synchronization between multiple databases.

Tenant management and routing strategies: Dynamic management and routing strategies for tenants need to be implemented to ensure that each request can be correctly routed to the corresponding database. This can be achieved by maintaining a tenant-to-database mapping or using middleware for request routing.

Database connection and resource management: In system design, the management and resource allocation of database connections need to be considered. Properly configuring the database connection pool and optimizing database queries can improve system performance and resource utilization.

Security and permission control: When designing the database architecture, you need to consider the requirements for security and permission control. Ensure that data access and operations between different tenants are restricted and comply with legal requirements for data privacy and protection.

To sum up, single data source and multiple databases are an effective solution to implement a multi-tenant system, which provides good data isolation, performance optimization and scalability. However, factors such as data migration, tenant management, resource management, and security need to be comprehensively considered during the implementation process to ensure the stability and reliability of the system. With proper design and implementation, the single data source multi-database solution can provide an efficient, secure and scalable data storage solution for multi-tenant systems.

Guess you like

Origin blog.csdn.net/weixin_45309155/article/details/133409083