ShardingSphere-JDBC實戰

来源:https://www.cnblogs.com/yuanbeier/archive/2022/08/14/16584622.html
-Advertisement-
Play Games

一、環境準備 1.資料庫 創建2個庫2個表: xdclass_shop_order_0 product_order_0 product_order_1 ad_config product_order_item_0 product_order_item_1 xdclass_shop_order_1 p ...


一、環境準備

1.資料庫

創建2個庫2個表:

  • xdclass_shop_order_0
    • product_order_0
    • product_order_1
    • ad_config
    • product_order_item_0
    • product_order_item_1
  • xdclass_shop_order_1
    • product_order_0
    • product_order_1
    • ad_config
    • product_order_item_0
    • product_order_item_1

資料庫腳本:

CREATE TABLE `product_order_0` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `out_trade_no` varchar(64) DEFAULT NULL COMMENT '訂單唯一標識',
  `state` varchar(11) DEFAULT NULL COMMENT 'NEW 未支付訂單,PAY已經支付訂單,CANCEL超時取消訂單',
  `create_time` datetime DEFAULT NULL COMMENT '訂單生成時間',
  `pay_amount` decimal(16,2) DEFAULT NULL COMMENT '訂單實際支付價格',
  `nickname` varchar(64) DEFAULT NULL COMMENT '昵稱',
  `user_id` bigint DEFAULT NULL COMMENT '用戶id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

CREATE TABLE `ad_config` (
  `id` bigint unsigned NOT NULL COMMENT '主鍵id',
  `config_key` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '配置key',
  `config_value` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '配置value',
  `type` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '類型',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

CREATE TABLE `product_order_item_0` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `product_order_id` bigint DEFAULT NULL COMMENT '訂單號',
  `product_id` bigint DEFAULT NULL COMMENT '產品id',
  `product_name` varchar(128) DEFAULT NULL COMMENT '商品名稱',
  `buy_num` int DEFAULT NULL COMMENT '購買數量',
  `user_id` bigint DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

2.代碼工程

1.工程創建

  1. 創建Maven工程,添加相關Maven依賴,
 <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring.boot.version>2.5.5</spring.boot.version>
        <mybatisplus.boot.starter.version>3.4.0</mybatisplus.boot.starter.version>
        <lombok.version>1.18.16</lombok.version>
        <sharding-jdbc.version>4.1.1</sharding-jdbc.version>
        <junit.version>4.12</junit.version>
        <druid.version>1.1.16</druid.version>
        <!--跳過單元測試-->
        <skipTests>true</skipTests>
    </properties>
     <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${spring.boot.version}</version>
            <scope>test</scope>
        </dependency>
        <!--mybatis plus和springboot整合-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatisplus.boot.starter.version}</version>
        </dependency>
	<!-- mysql資料庫 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
	<!-- shardingshpere-jdbc-->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>${sharding-jdbc.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.boot.version}</version>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
  1. 添加資料庫配置文件,根據配置文件可知,配置了兩個資料庫ds0,ds1;
spring.application.name=yb-sharding-jdbc
server.port=8080

logging.level.root=INFO
# 列印執行的資料庫以及語句
spring.shardingsphere.props.sql.show=true

# 數據源 ds0 ds1
spring.shardingsphere.datasource.names=ds0,ds1
# 第一個資料庫
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/ybe_shop_order0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=*****

# 第二個資料庫
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://localhost:3306/ybe_shop_order1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=*****

2.廣播表介紹和配置實戰

  • 指所有的分片數據源中都存在的表,表結構和表中的數據在每個資料庫中均完全一致
  • 適用於數據量不大且需要與海量數據的表進行關聯查詢的場景
  • 例如:字典表、配置表
  1. 添加AdConfigDO實體類和添加ProductOrderDOMapper類
//資料庫實體類
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("ad_config")
public class AdConfigDO {
    private Long id;
    private String configKey;
    private String configValue;
    private String type;
}

//資料庫實體配置類
public interface AdConfigMapper extends BaseMapper<AdConfigDO> {
}
  1. 設置ad_config為廣播表,如果需要配置多個用 逗號 (,) 分開;設置id為生成演算法為雪花演算法。配置文件中添加如下代碼,
#配置廣播表
spring.shardingsphere.sharding.broadcast-tables=ad_config
spring.shardingsphere.sharding.tables.ad_config.key-generator.column=id
spring.shardingsphere.sharding.tables.ad_config.key-generator.type=SNOWFLAKE
  1. 添加測試方法
@Test
public void testSaveAdConfig(){
    AdConfigDO adConfigDO = new AdConfigDO();
    adConfigDO.setConfigKey("banner");
    adConfigDO.setConfigValue("ybe.com");
    adConfigDO.setType("ad");
    adConfigMapper.insert(adConfigDO);
}
  1. 執行結果,兩個資料庫的表都進行了更新。如下圖

3.行表達式分片策略 InlineShardingStrategy

  • 只支持【單分片鍵】使用Groovy的表達式,提供對SQL語句中的 =和IN 的分片操作支持
  • 可以通過簡單的配置使用,無需自定義分片演算法,從而避免繁瑣的Java代碼開發
  1. 添加ProductOrderDO實體類和添加ProductOrderDOMapper類
//資料庫實體類
@Data
@TableName("product_order")
@EqualsAndHashCode(callSuper = false)
public class ProductOrderDO {
	// 不設置Mybatis-plus的主鍵規則,由sharding-jdbc 設置
    private  Long  id;
    private  String outTradeNo;
    private String state;
    private Date createTime;
    private Double payAmount;
    private String nickname;
    private Long userId;
}

//資料庫實體配置類
public interface ProductOrderMapper extends BaseMapper<ProductOrderDO> {

}
  1. 配置文件添加如下代碼,
# 指定product_order表的數據分佈情況,配置數據節點,行表達式標識符使用 ${...} 或 $->{...},但前者與 Spring 本身的文件占位符衝突,所以在 Spring 環境中建議使用 $->{...}
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds$->{0..1}.product_order_$->{0..1}

#id生成策略
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
#work_id 的設置
spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1

#配置分庫規則
spring.shardingsphere.sharding.tables.product_order.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.product_order.database-strategy.inline.algorithm-expression=ds$->{user_id % 2}

#配置分表規則
#指定product_order表的分片策略,分片策略包括【分片鍵和分片演算法】
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{id % 2}

由配置文件可知,

​ 設置了product_order為邏輯表,設置了它的真實數據節點為ds$->{0..1}.product_order_$->{0..1},使用了表達式$->{...},它表示實際的物理表為:ds0.product_order_0,ds0.product_order_1,ds1.product_order_0,ds1.product_order_1,總共對應了2個庫的2個物理表。

​ 設置了product_order表的id計算方式為雪花演算法;

​ 設置了product_order表的分庫規則,分庫規則為 user_id % 2;也就是說會根據user_id % 2的結果確定是ds0庫還是ds1庫。

​ 設置了product_order表的分表規則,分表規則為 id % 2;也就是說會根據id % 2的結果確定是product_order_0表還是product_order_1表。

  1. 添加測試方法
@Test
public void testSaveProductOrder(){
    Random random = new Random();
    for (int i = 0 ;i < 10 ; i++){
        // id是由配置的雪花演算法生成
        ProductOrderDO productOrderDO = new ProductOrderDO();
        productOrderDO.setCreateTime(new Date());
        productOrderDO.setNickname("ybe:"+i);
        productOrderDO.setOutTradeNo(UUID.randomUUID().toString().substring(0,32));
        productOrderDO.setPayAmount(100.00);
        productOrderDO.setState("PAY");
        // 隨機生成UserId
        productOrderDO.setUserId(Long.valueOf(random.nextInt(50)));
        productOrderMapper.insert(productOrderDO);
    }
}
  1. 執行結果根據不同的user_id 和 id ,生成的表記錄插入到了不同的庫和表,如下圖可以看到數據分散在了兩個不同的資料庫,以及不同的表中。

4.標準分片策略StandardShardingStrategy

  • 只支持【單分片鍵】,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個分片演算法
  • PreciseShardingAlgorithm 精準分片 是必選的,用於處理=和IN的分片
  • RangeShardingAlgorithm 範圍分片 是可選的,用於處理BETWEEN AND分片
  • 如果不配置RangeShardingAlgorithm,如果SQL中用了BETWEEN AND語法,則將按照全庫路由處理,性能下降
  1. 添加分表配置類CustomTablePreciseShardingAlgorithm
public class CustomTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    /**
     * @param collection 數據源集合
     *                    在分庫時值為所有分片庫的集合 databaseNames
     *                   分表時為對應分片庫中所有分片表的集合 tablesNames
     * @param preciseShardingValue 分片屬性,包括
     *                                    logicTableName 為邏輯表,
     *                                    columnName 分片健(欄位),
     *                                    value 為從 SQL 中解析出的分片健的值
     * @return
     */
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {
        //迴圈遍歷 數據源,根據演算法
        for (String databaseName : collection) {
            String value = preciseShardingValue.getValue() % collection.size() + "";
            //value是0,則進入0庫表,1則進入1庫表
            if (databaseName.endsWith(value)) {
                return databaseName;
            }
        }
        throw new IllegalArgumentException();
    }
}
  1. 添加分庫配置類CustomDBPreciseShardingAlgorithm
/**
     * @param collection 數據源集合
     *                    在分庫時值為所有分片庫的集合 databaseNames
     *                   分表時為對應分片庫中所有分片表的集合 tablesNames
     * @param preciseShardingValue 分片屬性,包括
     *                                    logicTableName 為邏輯表,
     *                                    columnName 分片健(欄位),
     *                                    value 為從 SQL 中解析出的分片健的值
     * @return
     */
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {
    for (String databaseName : collection) {
        String value = preciseShardingValue.getValue() % collection.size() + "";
        //value是0,則進入0庫表,1則進入1庫表
        if (databaseName.endsWith(value)) {
            return databaseName;
        }
    }
    throw new IllegalArgumentException();
}
  1. 添加分表範圍配置類CustomRangeShardingAlgorithm
public class CustomRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
    /**
     * @param collection 數據源集合
     *                    在分庫時值為所有分片庫的集合 databaseNames
     *                   分表時為對應分片庫中所有分片表的集合 tablesNames
     * @param rangeShardingValue 分片屬性,包括
     *                                    logicTableName 為邏輯表,
     *                                    columnName 分片健(欄位),
     *                                    value 為從 SQL 中解析出的分片健的值
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Long> rangeShardingValue) {
        Set<String> result = new LinkedHashSet<>();
        // between 起始值
        Long lower = rangeShardingValue.getValueRange().lowerEndpoint();
        // between 結束值
        Long upper = rangeShardingValue.getValueRange().upperEndpoint();
        // 迴圈範圍計算分庫邏輯
        for (long i = lower; i <= upper; i++) {
            for (String databaseName : collection) {
                if (databaseName.endsWith(i % collection.size() + "")) {
                    result.add(databaseName);
                }
            }
        }
        return result;
    }
}
  1. 配置文件添加圖下代碼,
# 分庫分片演算法
spring.shardingsphere.sharding.tables.product_order.database-strategy.standard.sharding-column=user_id
spring.shardingsphere.sharding.tables.product_order.database-strategy.standard.precise-algorithm-class-name=com.ybe.algorithm.CustomDBPreciseShardingAlgorithm
#精準水平分表下,增加一個範圍分片
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.range-algorithm-class-name=com.ybe.algorithm.CustomRangeShardingAlgorithm

# 分表分片健
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.precise-algorithm-class-name=com.ybe.algorithm.CustomTablePreciseShardingAlgorithm
  1. 添加測試方法
@Test
public void testRand(){
    Random random = new Random();
    for (int i = 0 ;i < 10 ; i++){
        ProductOrderDO productOrderDO = new ProductOrderDO();
        productOrderDO.setCreateTime(new Date());
        productOrderDO.setNickname("ybe:"+i);
        productOrderDO.setOutTradeNo(UUID.randomUUID().toString().substring(0,32));
        productOrderDO.setPayAmount(100.00);
        productOrderDO.setState("PAY");
        productOrderDO.setUserId(Long.valueOf(random.nextInt(50)));
        productOrderMapper.insert(productOrderDO);
    }
    productOrderMapper.selectList(new QueryWrapper<ProductOrderDO>().between("id",1L,1L));
}
  1. 執行結果:1.會根據配置的分庫、分表規則進行插入不同的資料庫和表;2.範圍(between)查詢的時候會根據id的範圍值查詢映射的物理表集合。

5.複合分片演算法ComplexShardingStrategy

  • 提供對SQL語句中的=, IN和BETWEEN AND的分片操作,支持【多分片鍵】
  • 由於多分片鍵之間的關係複雜,Sharding-JDBC並未做過多的封裝
  • 而是直接將分片鍵值組合以及分片操作符交於演算法介面,全部由應用開發者實現,提供最大的靈活度
  1. 添加分表配置類CustomComplexKeysShardingAlgorithm
public class CustomComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {

    @Override
    public Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<Long> complexKeysShardingValue) {
        // 得到每個分片健對應的值
        Collection<Long> orderIdValues = this.getShardingValue(complexKeysShardingValue, "id");
        Collection<Long> userIdValues = this.getShardingValue(complexKeysShardingValue, "user_id");

        List<String> shardingSuffix = new ArrayList<>();
        // 對兩個分片健取模的方式
        for (Long userId : userIdValues) {
            for (Long orderId : orderIdValues) {
                String suffix = userId % 2 + "_" + orderId % 2;
                for (String databaseName : collection) {
                    if (databaseName.endsWith(suffix)) {
                        shardingSuffix.add(databaseName);
                    }
                }
            }
        }
        return shardingSuffix;
    }
    /**
     * shardingValue  分片屬性,包括
     * logicTableName 為邏輯表,
     * columnNameAndShardingValuesMap 存儲多個分片健 包括key-value
     * key:分片key,id和user_id
     * value:分片value,66和99
     *
     * @return shardingValues 集合
     */
    private Collection<Long> getShardingValue(ComplexKeysShardingValue<Long> shardingValues, final String key) {
        Collection<Long> valueSet = new ArrayList<>();
        Map<String, Collection<Long>> columnNameAndShardingValuesMap = shardingValues.getColumnNameAndShardingValuesMap();

        if (columnNameAndShardingValuesMap.containsKey(key)) {
            valueSet.addAll(columnNameAndShardingValuesMap.get(key));
        }
        return valueSet;
    }
  1. 配置文件添加如下代碼,多個列的類型必須一樣。
# 複合分片演算法,order_id,user_id 同時作為分片健
spring.shardingsphere.sharding.tables.product_order.table-strategy.complex.sharding-columns=user_id,id
spring.shardingsphere.sharding.tables.product_order.table-strategy.complex.algorithm-class-name=com.ybe.algorithm.CustomComplexKeysShardingAlgorithm
  1. 添加測試方法
@Test
public void testComplex(){
    productOrderMapper.selectList(new QueryWrapper<ProductOrderDO>().eq("id",66L).eq("user_id",99L));
}
  1. 執行結果:1.會根據配置的複合分片演算法去查找相關的物理表。

6.Hint分片演算法HintShardingStrategy

  • 這種分片策略無需配置文件進行配置分片健,分片健值也不再從 SQL中解析,外部手動指定分片健或分片庫,讓 SQL在指定的分庫、分表中執行
  • 通過Hint代碼指定的方式而非SQL解析的方式分片的策略
  • Hint策略會繞過SQL解析的,對於這些比較複雜的需要分片的查詢,Hint分片策略性能可能會更好
  • 可以指定sql去某個庫某個表進行執行
  1. 添加分表配置類CustomTableHintShardingAlgorithm
public class CustomTableHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> collection, HintShardingValue<Long> hintShardingValue) {
        Collection<String> result = new ArrayList<>();
        for (String tableName : collection) {
            for (Long shardingValue : hintShardingValue.getValues()) {
                if (tableName.endsWith(String.valueOf(shardingValue % collection.size()))) {
                    result.add(tableName);
                }
            }
        }
        return result;
    }
}
  1. 添加分庫配置類CustomDBHintShardingAlgorithm
public class CustomDBHintShardingAlgorithm implements HintShardingAlgorithm<Long>
{
    @Override
    public Collection<String> doSharding(Collection<String> collection, HintShardingValue<Long> hintShardingValue) {
        Collection<String> result = new ArrayList<>();
        for (String dbName : collection) {
            for (Long shardingValue : hintShardingValue.getValues()) {
                if (dbName.endsWith(String.valueOf(shardingValue % collection.size()))) {
                    result.add(dbName);
                }
            }
        }
        return result;
    }
}
  1. 配置文件添加如下代碼
# Hint分片演算法
spring.shardingsphere.sharding.tables.product_order.table-strategy.hint.algorithm-class-name=com.ybe.algorithm.CustomTableHintShardingAlgorithm
spring.shardingsphere.sharding.tables.product_order.database-strategy.hint.algorithm-class-name=com.ybe.algorithm.CustomDBHintShardingAlgorithm
  1. 添加測試方法
@Test
public void testHint(){
    // 清除掉歷史的規則
    HintManager.clear();
    //Hint分片策略必須要使用 HintManager工具類
    HintManager hintManager = HintManager.getInstance();
    // 設置庫的分片健,value用於庫分片取模,
    hintManager.addDatabaseShardingValue("product_order",4L);
    // 設置表的分片健,value用於表分片取模,
    hintManager.addTableShardingValue("product_order", 5L);
    //對應的value只做查詢,不做sql解析
    productOrderMapper.selectList(new QueryWrapper<ProductOrderDO>().eq("id", 66L));
}
  1. 執行結果:1.不會解析Sql中的分片鍵,會把hintManager配置的值作為分片鍵,在CustomTableHintShardingAlgorithm分片演算法的中使用。

7.綁定表介紹和配置實戰

  • 指分片規則一致的主表和子表
  • 比如product_order表和product_order_item表,均按照order_id分片,則此兩張表互為綁定表關係
  • 綁定表之間的多表關聯查詢不會出現笛卡爾積關聯,關聯查詢效率將大大提升
  1. 添加ProductOrderItemDO實體類和添加ProductOrderDOMapper類
//資料庫實體類
@Data
@TableName("product_order_item")
@EqualsAndHashCode(callSuper = false)
public class ProductOrderItemDO {
    private Long id;
    private Long productOrderId;
    private Long productId;
    private String productName;
    private  Integer buyNum;
    private  Long userId;
}

//資料庫實體配置類
public interface ProductOrderItemMapper extends BaseMapper<ProductOrderItemDO> {
}
  1. 添加配置文件,設置product_order_item的分表邏輯,設置product_order和product_order_item為廣播表,如果需要配置多個需要配置多行,binding-tables是個數組。
spring.shardingsphere.sharding.tables.product_order_item.actual-data-nodes=ds$->{0..1}.product_order_item_$->{0..1}
# 指定product_order表的分片策略,分片策略包括【分片鍵和分片演算法】
spring.shardingsphere.sharding.tables.product_order_item.table-strategy.inline.sharding-column=product_order_id
spring.shardingsphere.sharding.tables.product_order_item.table-strategy.inline.algorithm-expression=product_order_item_$->{product_order_id % 2}
#配置綁定表
spring.shardingsphere.sharding.binding-tables[0]=product_order,product_order_item
  1. 添加測試方法
@Test
public void testBinding(){
    List<Object> objects = productOrderMapper.listProductOrderDetail();
    System.out.println(objects);
}
  1. 執行結果:

    • 添加綁定表配置之前,可以看到查詢的sql語句,主表和子表是笛卡爾積的關聯關係。如下圖,

    • 添加綁定表配置之後,可以看到查詢的sql語句,主表和子表是一一對應的。如下圖,


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 八個解決你80%需求的CSS動畫庫 點擊打開視頻講解 在學習和工作的過程中,我們總免不了要寫各種各樣的css動畫,給某個部分添加動畫效果,如果覺得自己寫的動畫效果單一乏味,不妨試試這8個CSS動畫庫,值得收藏使用。 一、hover.css 開箱即用的滑鼠懸停動畫,支持的動畫類型有: 2D Trans ...
  • 重繪和迴流: repaint(重繪) ,repaint發生更改時,元素的外觀被改變,且在沒有改變佈局的情況下發生,如改變outline,visibility,background color,不會影響到dom結構渲染。 reflow(渲染),與repaint區別就是他會影響到dom的結構渲染,同時他 ...
  • 註意:只有類組件才有生命周期鉤子函數,函數組件沒有生命周期鉤子函數。 生命周期 裝載階段:constructor() render() componentDidMount() 更新階段:render() componentDidupDate() 卸載階段:componentWillUnmount() ...
  • 原視頻鏈接:https://www.youtube.com/watch?v=Wo0qiGPSV-s by Anjana Vakil@JSConf 概述 函數式編程避免了很多命令式和麵向對象的編程的問題。 在函數中,數據輸入,數據輸出和數據轉換就是這個函數的目的功能。 與之緊密相連的,就是要避免可變性 ...
  • 如何定義state 在類組件 中,在constructor()中使用this.state={}來定義 class A extends Component { constructor (props) { super(props) // 調用Component的構造函數 // 定義state this. ...
  • 前言 將 markdown 字元串轉成 html 顯示出來,同時把目錄也提取出來一起顯示。可以使用 marked 來讀取 markdown 字元串解析成 html marked官網:https://marked.js.org/ marked 安裝 使用 marked 前需要對其進行安裝 npm in ...
  • 前言 最近在做需求的時候,涉及到登錄token,產品提出一個問題:能不能讓token過期時間長一點,我頻繁的要去登錄。 前端:後端,你能不能把token 過期時間設置的長一點。 後端:可以,但是那樣做不安全,你可以用更好的方法。 前端:什麼方法? 後端:給你刷新token的介面,定時去刷新token ...
  • 當微服務是個壞主意時 這篇文章可能是給大家潑冷水,請各位理性看待。從書面上看,微服務聽起來很好。它們是模塊化、可擴展和容錯的。很多公司使用這種模式取得了巨大的成功,所以微服務可能自然而然地成為卓越的架構和啟動新應用程式的最佳方式。然而,大多數利用微服務取得成功的公司並不是從微服務開始的。考慮一下Ai ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...