SpringBoot整合ShardingSphere实现分表分库&读写分离&读写分离+数据库分表

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: SpringBoot整合ShardingSphere实现分表分库&读写分离&读写分离+数据库分表

前言


Apache ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力。具体内容请看官方ShardingSphere。本文主要记录一下Springboot整合ShardingSphere,并实现精确分片算法、范围分片算法、复合分片算法、读写分离、读写分离+分表的配置记录。


正文


SpringBoot整合ShardingSphere


maven依赖


 <dependencies>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>4.1.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/sharding-jdbc-core -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-core</artifactId>
            <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.14</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
    </dependencies>


行表达式分片策略


行表达式分辨策略使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作并且只支持单分片(针对一个字段分片例如id)的操作。例如tb_user_$->{id%2}表示通过id对2取模,实现的效果是tb_user_0存放id为偶数的数据,tb_user_1存放id为奇数的数据。


配置文件如下


#基于行策略实现的分表分库
spring:
  shardingsphere:
    datasource:
      #数据源名称,多个值用逗号隔开
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test_1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test_2?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
    sharding:
      tables:
        tb_user: #逻辑表名,需要与mapper中sql语句中的表名一致
          actual-data-nodes: ds$->{0..1}.tb_user_$->{0..1} #实际的节点名称 例如 ds0.tb_user_0,ds0.tb_user_1,ds1.tb_user_0,ds1.tb_user_1
          table-strategy:
            inline:
              sharding-column: id #分片字段
              algorithm-expression: tb_user_$->{id % 2} #分表表达式
          database-strategy:
            inline:
              sharding-column: id
              algorithm-expression: ds$->{id % 2} #分库表达式
          key-generator:
            column: id #id生成策略,雪花算法,uuid
            type: SNOWFLAKE
    default-data-source-name: ds0 #不进行分表分库的表,操作的默认数据源
    props:
      sql:
        show: true #显示sql
#注意
#没有分库,只分表的情况下,不需要配置分库策略,配置如下 。结果是ds0.tb_user_0,ds0.tb_user_1
#sharding:
#  tables:
#    tb_user: #逻辑表名,需要与mapper中sql语句中的表名一致
#      actual-data-nodes: ds0.tb_user_$->{0..1} #实际的节点名称 例如 ds0.tb_user_0,ds0.tb_user_1
#      table-strategy:
#        inline:
#          sharding-column: id #分片字段
#          algorithm-expression: tb_user_$->{id % 2} #分表表达式
#      key-generator:
#        column: id #id生成策略,雪花算法,uuid
#        type: SNOWFLAKE
#如果只分库,不分表,那么需要每个库中的表名称表结构是一样的,那么配置格式如下
#sharding:
#  tables:
#    tb_user: #逻辑表名,需要与mapper中sql语句中的表名一致
#      actual-data-nodes: ds$->{0..1}.tb_user  #实际的节点名称 例如 ds0.tb_user,ds1.tb_user
#      database-strategy:
#        inline:
#          sharding-column: id
#          algorithm-expression: ds$->{id % 2} #分库表达式
#      key-generator:
#        column: id #id生成策略,雪花算法,uuid
#        type: SNOWFLAKE
#如果按照最上面的配置,结果将是ds0.tb_user_0,ds1.tb_user_1两张表有数据,其他的表将不会存放数据,此时就需要标准分片算法来实现。


标准分片策略


标准分片策略提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。


配置文件


#标准分片策略
spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test_1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test_2?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
    sharding:
      tables:
        tb_user: #逻辑表名
          actual-data-nodes: ds$->{0..1}.tb_user_$->{0..1} #实际的数据库节点
          key-generator:
            column: id
            type: SNOWFLAKE
          database-strategy:
            standard: #自定义数据库分片算法
              sharding-column: age
              range-algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyDBShardingAlgorithm
              precise-algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyDBShardingAlgorithm
          table-strategy:
            standard: #自定义表分片算法
              sharding-column: id
              range-algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyTableShardingAlgorithm
              precise-algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyTableShardingAlgorithm
      default-data-source-name: ds0 #不使用分表分库策略的数据源
    props:
      sql:
        show: true #显示sql


自定义算法类


自定义分片算法可以根据自己的需要,如按照年、季度、月、星期、天、或者地区等等需要自己实现规则。


数据库自定义分片算法


package com.xiaojie.sharding.sphere.shardingalgorithm;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
/**
 * @Description:自定义数据库分片算法 数据库的分片字段可以和分表分片字段一样,也可以不一样
 * 下面配置 分库字段按照age字段,如果年龄超过30那么放在ds0,如果没有超过放在ds1,
 * 分表字段按照id字段存放。偶数存放到tb_user_0、奇数存放到tb_user_1
 * @author: yan
 * @date: 2022.03.12
 */
@Component
public class MyDBShardingAlgorithm implements PreciseShardingAlgorithm<Integer>, RangeShardingAlgorithm<Long> {
    @Override
    public String doSharding(Collection<String> dbNames, PreciseShardingValue<Integer> shardingValue) {
//        for (String dbName : dbNames) {
//            /**
//             * 取模算法,分片健 % 表数量 数据库
//             */
//            Integer age = shardingValue.getValue();
//            String tableIndex = age%dbNames.size()+"";
//            if (dbName.endsWith(tableIndex)) {
//                return dbName;//返回数据库名称 比如db0,db1
//            }
//        }
        //如果大于30岁放在db0,小于等于30放在db1
        if (shardingValue.getValue() > 30) {
            return (String) dbNames.toArray()[0];
        } else {
            return (String) dbNames.toArray()[1];
        }
//        throw new IllegalArgumentException();
    }
    @Override
    public Collection<String> doSharding(Collection<String> dbNames, RangeShardingValue<Long> shardingValue) {
        Collection<String> collect = new ArrayList<>();//数据库节点名称
        Range valueRange = shardingValue.getValueRange();//查询返回
        String lowerPoint = String.valueOf(valueRange.hasLowerBound() ? valueRange.lowerEndpoint() : "");//下限
        String upperPoint = String.valueOf(valueRange.hasUpperBound() ? valueRange.upperEndpoint() : "");//上限
        //判断上限,下限值是否存在,如果不存在赋给默认值。用于处理查询条件中只有 >或<一个条件,不是一个范围查询的情况
        long lowerEndpoint = 0; //最小值
        long lupperEndpoint = 0;//最大值
        if (!lowerPoint.isEmpty() && !upperPoint.isEmpty()) {
            lowerEndpoint = Math.abs(Long.parseLong(lowerPoint));
            lupperEndpoint = Math.abs(Long.parseLong(upperPoint));
        } else if (lowerPoint.isEmpty() && !upperPoint.isEmpty()) {
            lupperEndpoint = Math.abs(Long.parseLong(upperPoint));
            lowerEndpoint = 0;
        } else if (!lowerPoint.isEmpty() && upperPoint.isEmpty()) {
            lowerEndpoint = Math.abs(Long.parseLong(lowerPoint));
            lupperEndpoint = 40;
        }
        // 循环范围计算分库逻辑
        for (long i = lowerEndpoint; i <= lupperEndpoint; i++) {
            for (String db : dbNames) {
                if (db.endsWith(i % dbNames.size() + "")) {
                    collect.add(db);
                }
            }
        }
        return collect;
    }
}


表自定义分片算法


package com.xiaojie.sharding.sphere.shardingalgorithm;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
/**
 * @Description:自定义表分片算法 #范围分片算法类名称,用于BETWEEN,可选。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器
 * shardingsphare默认查询只支持=,between and 这种查询,像>,<,>=,<=这种查询目前不支持,
 * 除非通过继承自定义接口RangeShardingAlgorithm实现,否则无法使用>,<,>=,<=。
 * 同时也需要实现PreciseShardingAlgorithm<String>接口
 * @author: yan
 * @date: 2022.03.12
 */
@Component
public class MyTableShardingAlgorithm implements PreciseShardingAlgorithm<String>, RangeShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        Range<Long> valueRange = shardingValue.getValueRange();//获得输入的查询条件范围
        String slowerEndpoint = String.valueOf(valueRange.hasLowerBound() ? valueRange.lowerEndpoint() : "");//查询条件下限
        String supperEndpoint = String.valueOf(valueRange.hasUpperBound() ? valueRange.upperEndpoint() : "");//查询条件上限
        //处理只有下限或上限的范围
        long lowerEndpoint = 0;
        long lupperEndpoint = 0;
        if (!slowerEndpoint.isEmpty() && !supperEndpoint.isEmpty()) {
            lowerEndpoint = Math.abs(Long.parseLong(slowerEndpoint));
            lupperEndpoint = Math.abs(Long.parseLong(supperEndpoint));
        } else if (slowerEndpoint.isEmpty() && !supperEndpoint.isEmpty()) {
            lupperEndpoint = Math.abs(Long.parseLong(supperEndpoint));
            lowerEndpoint = 18;
        } else if (!slowerEndpoint.isEmpty() && supperEndpoint.isEmpty()) {
            lowerEndpoint = Math.abs(Long.parseLong(slowerEndpoint));
            lupperEndpoint = 40;
        }
        Collection<String> collect = new ArrayList<>();
//        逐个读取查询范围slowerEndpoint~lupperEndpoint的值,得对应的表名称
        for (long i = lowerEndpoint; i <= lupperEndpoint; i++) {
            for (String each : availableTargetNames) {
                if (each.endsWith("_" + (i % availableTargetNames.size()))) {
                    if (!collect.contains(each)) {
                        collect.add(each);
                    }
                }
            }
        }
        return collect;
    }
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {
        for (String each : availableTargetNames) {
            {
                String hashCode = String.valueOf(shardingValue.getValue());//配置文件中,分表字段对应的值,也是查询条件中输入的查询条件
                long segment = Math.abs(Long.parseLong(hashCode)) % availableTargetNames.size();
                if (each.endsWith("_" + segment + "")) {//
                    return each;
                }
            }
        }
        throw new RuntimeException(shardingValue + "没有匹配到表");
    }
}


符合分片策略


复合分片策略提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,自定义分片规则需要实现ComplexKeysShardingAlgorithm接口


配置文件


#复合分片策略
spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test_1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test_2?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
    sharding:
      tables:
        tb_user:
          actual-data-nodes: ds$->{0..1}.tb_user_$->{0..1}
          key-generator:
            column: id
            type: SNOWFLAKE
          database-strategy: #库分片策略
            complex:
              sharding-columns: age,id #分片字段
              algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyDBComplexShardingStrategy
          table-strategy: #表分片策略
            complex:
              sharding-columns: age,id #分片字段
              algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyTableComplexShardingStrategy
      default-data-source-name: ds0
    props:
      sql:
        show: true


分库算法


package com.xiaojie.sharding.sphere.shardingalgorithm;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
/**
 * @Description: 复合分片 分库算法
 * @author: yan
 * @date: 2022.03.12
 */
@Component
public class MyDBComplexShardingStrategy implements ComplexKeysShardingAlgorithm {
    @Override
    public Collection<String> doSharding(Collection availableTargetNames, ComplexKeysShardingValue shardingValue) {
        //分片的字段集合
        Map<String, Collection> columnMap = shardingValue.getColumnNameAndShardingValuesMap();
        //分片的范围规则
        Map<String, Range> rangeValuesMap = shardingValue.getColumnNameAndRangeValuesMap();
        //获取分片字段的集合
        Collection<Integer> agesColumn = columnMap.get("age");
        Collection<Long> idColumn = columnMap.get("id");
        ArrayList<String> list = new ArrayList();
        for (Integer age : agesColumn) {
            for (Long id : idColumn) {
                String suffix = null;
                if (age > 30) {
                    suffix = id % age % availableTargetNames.size() + "";
                } else {
                    suffix = (id + age) % availableTargetNames.size() + "";
                }
                for (Object db : availableTargetNames) {
                    String dbName = (String) db;
                    if (dbName.endsWith(suffix)) {
                        list.add(dbName);
                    }
                }
            }
        }
        return list;
    }
}


读写分离


支持


提供一主多从的读写分离配置,可独立使用,也可配合分库分表使用。

独立使用读写分离支持SQL透传。

同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性。

基于Hint的强制主库路由。


不支持


主库和从库的数据同步。

主库和从库的数据同步延迟导致的数据不一致。

主库双写或多写。

跨主库和从库之间的事务的数据不一致。主从模型中,事务中读写均用主库。


配置文件


##读写分离配置
spring:
  shardingsphere:
    datasource:
      names: master,slave0
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/my_test?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
      slave0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:33060/my_test?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
    masterslave:
      load-balance-algorithm-type: round_robin
      name: ms
      master-data-source-name: master
      slave-data-source-names: slave0
    props:
      sql:
        show: true


读写分离+数据库分表


由于只有一个主库,只实现了分表功能,分库策略同非读写分离的配置一样。

配置文件


#主从复制+分表
spring:
  shardingsphere:
    datasource:
      names: master0,master0slave0
      master0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/my_test?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
      master0slave0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/my_test?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: root
    sharding:
      tables:
        tb_user: #逻辑表名
          actual-data-nodes: ds0.tb_user_$->{0..1}
          table-strategy: #分表策略
            inline:
              sharding-column: id
              algorithm-expression: tb_user_$->{id % 2}
          key-generator:
            column: id
            type: SNOWFLAKE
      #绑定表,指分片规则一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,则此两张表互为绑定表关系。
      #绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升
#      binding-tables: t_order,t_order_item
      #广播表,适用于数据量不大且需要与海量数据的表进行关联查询的场景
      #广播表概念只存在有分库的情况,如果只是分表或主从,不涉及这个概念,配置了也没啥意义。以下论述均依据存在分库的情况
      #广播表在每个数据库都有一个,且数据一样,适合字典表场景,数据量少。
      #当插入一条数据时,所有库的tb_user表都会插入一条一模一样数据(可能出现分布式事务问题)
#      broadcast-tables:t_config
      #分库策略
#      default-database-strategy:
#        inline:
#          sharding-column: id
#          algorithm-expression: master$->{id % 2}
      master-slave-rules:
        ds0:
          master-data-source-name: master0
          slave-data-source-names: master0slave0
    props:
      sql:
        show: true #显示sql


注意:


1、数据库如图


222.png


2、本整合基于shardingsphere4.1.1;jdk17


3、如果你的jdk是大于8的运行过程可能报如下错误


111.png


这种情况一般在使用高于 Java 8 版本的 JDK 时会出现,原因是在 Java 9 及之后的版本对源码进行了模块化重构,public 不再意味着完全开放,而是使用了 export 的机制来更细粒度地控制可见性。


解决方法


在JVM启动参数上添加如下参数


--add-opens java.base/java.lang=ALL-UNNAMED


完整项目和sql文件请自取

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
NoSQL Java 数据库
【问题篇】springboot项目通过数据库限制实例端口号
【问题篇】springboot项目通过数据库限制实例端口号
19 0
|
14天前
|
存储 关系型数据库 MySQL
【mybatis-plus】Springboot+AOP+自定义注解实现多数据源操作(数据源信息存在数据库)
【mybatis-plus】Springboot+AOP+自定义注解实现多数据源操作(数据源信息存在数据库)
|
15天前
|
Java 测试技术 数据库
SpringBoot启动时设置不加载数据库
SpringBoot启动时设置不加载数据库
10 0
|
1月前
|
SQL Java 数据库连接
springboot解析txt文件顺便加到数据库中(nohup文件)
springboot解析txt文件顺便加到数据库中(nohup文件)
112 1
|
1月前
|
Oracle Java 关系型数据库
SpringBoot整合Mybatis连接Oracle数据库
SpringBoot整合Mybatis连接Oracle数据库
SpringBoot整合Mybatis连接Oracle数据库
|
1月前
|
前端开发 Java 数据库
基于Springboot的漫画网站22(程序+数据库+论文)可帮忙远程调试
基于Springboot的漫画网站22(程序+数据库+论文)可帮忙远程调试
|
1月前
|
Java 关系型数据库 MySQL
基于springboot+vue网吧管理系统(程序+数据库+文档)
基于springboot+vue网吧管理系统(程序+数据库+文档)
|
1月前
|
搜索推荐 Java 数据库
基于springboot+vue网上图书商城(程序+数据库+文档)
基于springboot+vue网上图书商城(程序+数据库+文档)
|
1月前
|
Java 关系型数据库 数据库
基于SpringBoot大药房管理系统(程序+数据库+文档)
基于SpringBoot大药房管理系统(程序+数据库+文档)
|
1月前
|
JavaScript Java 数据库
基于springboot的地方美食分享网站(程序+数据库+文档)
基于springboot的地方美食分享网站(程序+数据库+文档)