springboot+shardingsphere+druid的动态数据表创建demo搭建

背景

项目需要给不同的用户分不同的表记录数据,因此需要使用分库分表的中间件进行多数据源查询,本项目使用beetlsql,因此需要手动创建表。

为什么选择shardingsphere不选择mycat

mycat无代码侵入性,但需要提前配置好相关配置,与需求不符。

具体使用

pom配置

<dependency>
    <groupId>io.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>3.0.0}</version>
</dependency>

使用shardingsphere3.0.0版本

application.properties配置

#可配置多数据源,本demo只使用单数据源
#sharding.jdbc.datasource.names=ds0,ds1
sharding.jdbc.datasource.names=ds
sharding.jdbc.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
sharding.jdbc.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.ds.url=jdbc:mysql://localhost:3306/ds?useSSL=false&characterEncoding=utf-8
sharding.jdbc.datasource.ds.username=root
sharding.jdbc.datasource.ds.password=123456

#下方是多数据源ds0配置,本demo不使用
#sharding.jdbc.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
#sharding.jdbc.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
#sharding.jdbc.datasource.ds0.url=jdbc:mysql://localhost:3306/ds0?useSSL=false&characterEncoding=utf-8
#sharding.jdbc.datasource.ds0.username=root
#sharding.jdbc.datasource.ds0.password=123456

#下方是多数据源ds1配置,本demo不使用
#sharding.jdbc.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
#sharding.jdbc.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
#sharding.jdbc.datasource.ds1.url=jdbc:mysql://localhost:3306/ds1?useSSL=false&characterEncoding=utf-8
#sharding.jdbc.datasource.ds1.username=root
#sharding.jdbc.datasource.ds1.password=123456

#sharding.jdbc.sharding.tables.order.actual-data-nodes=ds$->{0..1}.order$->{0..1}
#sharding.jdbc.sharding.tables.order.actual-data-nodes=ds.order$->{0..1}
sharding.jdbc.sharding.tables.order.dynamic=true
sharding.jdbc.sharding.tables.order.table-strategy.standard.sharding-column=user_id
sharding.jdbc.sharding.tables.order.table-strategy.standard.precise-algorithm-class-name=com.per.algorithm.ModuleSharingTableAlgorithm
#sharding.jdbc.sharding.tables.order.table-strategy.standard.sharding-column=user_id
#sharding.jdbc.sharding.tables.order.table-strategy.standard.precise-algorithm-class-name=com.per.algorithm.ModuleSharingTableAlgorithm
#sharding.jdbc.sharding.tables.order.table-strategy.inline.sharding-column=user_id
#sharding.jdbc.sharding.tables.order.table-strategy.inline.algorithm-expression=order$->{user_id % 2}
sharding.jdbc.sharding.tables.order.key-generator-column-name=order_id
#sharding.jdbc.sharding.tables.order.key-generator-type=SNOWFLAKE
sharding.jdbc.sharding.tables.order.key-generator-class-name=io.shardingsphere.core.keygen.DefaultKeyGenerator
#sharding.jdbc.sharding.tables.order_item.actual-data-nodes=ds$->{0..1}.order_item$->{0..1}
sharding.jdbc.sharding.tables.order_item.actual-data-nodes=ds.order_item$->{0..1}
sharding.jdbc.sharding.tables.order_item.table-strategy.inline.sharding-column=order_id
sharding.jdbc.sharding.tables.order_item.table-strategy.inline.algorithm-expression=order_item$->{order_id % 2}
sharding.jdbc.sharding.tables.order_item.key-generator.column=order_item_id
sharding.jdbc.sharding.tables.order_item.key-generator.type=SNOWFLAKE
sharding.jdbc.sharding.binding-tables=order,order_item
sharding.jdbc.sharding.broadcast-tables=config

#sharding.jdbc.sharding.default-database-strategy.inline.sharding-column=user_id
#sharding.jdbc.sharding.default-database-strategy.inline.algorithm-expression=ds$->{user_id % 2}
#该处配置默认数据源
#sharding.jdbc.config.sharding.default-data-source-name=ds0

#sharding.jdbc.config.sharding.default-database-strategy.standard.sharding-column=user_id
#sharding.jdbc.config.sharding.default-database-strategy.standard.precise-algorithm-class-name=com.per.algorithm.ModuleSharingTableAlgorithm

sharding.jdbc.config.sharding.default-table-strategy.standard.sharding-column=user_id
sharding.jdbc.config.sharding.default-table-strategy.standard.precise-algorithm-class-name=com.per.algorithm.ModuleSharingTableAlgorithm


sharding.jdbc.config.props.sql.show=true

bean

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class Order implements Serializable {
    private static final long serialVersionUID = -21353099551913779L;

    @AutoID
    private Integer orderId;

    private Integer userId;

    private String name;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class OrderItem implements Serializable {
    private static final long serialVersionUID = -21343099551913779L;

    @AutoID
    private Integer orderId;

    private String item;

    private Integer userId;
}

dao

@Repository
public interface OrderDao extends BaseMapper<Order> {
}
@Repository
public interface OrderItemDao extends BaseMapper<OrderItem> {
}

service

orderService:

@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
public class OrderService {
    private final OrderDao orderDao;

    private final CreateTableUtil createTableUtil;

    public void addOrder(Integer userId, String name) {
        String tableName = "`order" + userId + "`";
        String sql = "create table IF NOT EXISTS " + tableName + " (\n" +
                "  `order_id` bigint(20) NOT NULL AUTO_INCREMENT,\n" +
                "  `user_id` bigint(20) NOT NULL,\n" +
                "  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,\n" +
                "  PRIMARY KEY (`order_id`) USING BTREE\n" +
                ") ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;";
        try {
            createTableUtil.createTable(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        Order order = Order.builder()
                .userId(userId)
                .name(name)
                .build();
        orderDao.insertTemplate(order);
    }

    public Order getOrder(Integer orderId, Integer userId) {
        return orderDao.createLambdaQuery()
                .andEq(Order::getOrderId, orderId)
                .andEq(Order::getUserId, userId)
                .single();
    }

建表的工具类

@Component
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
public class CreateTableUtil {

    private final DataSource dataSource;

    public void createTable(String sql) throws SQLException {
        Connection connection = dataSource.getConnection();
        Statement statement = connection.createStatement();
        statement.executeUpdate(sql);
        statement.close();
        connection.close();
    }
}

算法

需要实现相应的算法接口

public class ModuleSharingTableAlgorithm implements PreciseShardingAlgorithm<Integer> {

    public ModuleSharingTableAlgorithm() {

    }

    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Integer> preciseShardingValue) {
        System.out.println("进入分片算法");
        for (String a : collection) {
        	//该处可以查询到具体的数据源或表名
            System.out.println(a);
        }
        //该方法可以查询到配置的列名
        System.out.println("column = " + preciseShardingValue.getColumnName());
        //该方法可以查询到逻辑表名
        System.out.println("table = " + preciseShardingValue.getLogicTableName());
        //该方法可以查询到列的数据
        System.out.println("value = " + preciseShardingValue.getValue());
        for (String each : collection) {
        	//该处根据userId决定要进入的分表,然后返回表名
            return each + preciseShardingValue.getValue();
        }
        throw new UnsupportedOperationException();
    }
}

结语

该demo只是验证技术可行性,确定了可以通过动态创建表的方式进行分表,正式使用时需要进行对应的封装以及配置的修改,可引入配置中心进行配置管理等。

发布了14 篇原创文章 · 获赞 3 · 访问量 7064
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章