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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章