Sharding-JDBC之绑定表(关联表)

news2024/11/29 10:54:16

目录

    • 一、简介
    • 二、maven依赖
    • 三、数据库
      • 3.1、创建数据库
      • 3.2、创建表
    • 四、配置(二选一)
      • 4.1、properties配置
      • 4.2、yml配置
    • 五、实现
      • 5.1、实体层
      • 5.2、持久层
      • 5.3、服务层
      • 5.4、测试类
        • 5.4.1、保存订单数据
        • 5.4.2、查询订单详情数据(关联表)

一、简介

  这里的绑定表也叫关联表。指分片规则一致的主表和子表。例如:t_order 表和 t_order_item 表,均按照 order_id 分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

  本文示例大概架构,为了讲解采用最简单的水平分表+关联表,如下图:
在这里插入图片描述

二、maven依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.alian</groupId>
    <artifactId>sharding-jdbc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sharding-jdbc</name>
    <description>sharding-jdbc</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.15</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

  有些小伙伴的 druid 可能用的是 druid-spring-boot-starter

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>

  然后出现可能使用不了的各种问题,这个时候你只需要在主类上添加 @SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class}) 即可

package com.alian.shardingjdbc;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})
@SpringBootApplication
public class ShardingJdbcApplication {

    public static void main(String[] args) {
        SpringApplication.run(ShardingJdbcApplication.class, args);
    }

}

三、数据库

3.1、创建数据库

CREATE DATABASE `sharding_7` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

3.2、创建表

  在数据库sharding_7下面分别创建四张表:tb_order_1tb_order_2的结构是一样的,tb_order_item_1tb_order_item_2 的结构是一样的,这里 tb_ordertb_order_item 就是关联表。这里是订单详情表里存了订单表的order_id。

tb_order_1

CREATE TABLE `tb_order_1` (
  `order_id` bigint(20) NOT NULL COMMENT '主键',
  `user_id` int unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
  `price` int unsigned NOT NULL DEFAULT '0' COMMENT '价格(单位:分)',
  `order_status` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '订单状态(1:待付款,2:已付款,3:已取消)',
  `order_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `title` varchar(100)  NOT NULL DEFAULT '' COMMENT '订单标题',
  PRIMARY KEY (`order_id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_order_time` (`order_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

tb_order_2

CREATE TABLE `tb_order_2` (
  `order_id` bigint(20) NOT NULL COMMENT '主键',
  `user_id` int unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
  `price` int unsigned NOT NULL DEFAULT '0' COMMENT '价格(单位:分)',
  `order_status` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '订单状态(1:待付款,2:已付款,3:已取消)',
  `order_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `title` varchar(100)  NOT NULL DEFAULT '' COMMENT '订单标题',
  PRIMARY KEY (`order_id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_order_time` (`order_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

tb_order_item_1

CREATE TABLE `tb_order_item_1` (
  `id` bigint(20) NOT NULL COMMENT '主键',
  `order_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '订单id',
  `goods_name` varchar(100)  NOT NULL DEFAULT '' COMMENT '商品名称',
  `price` int unsigned NOT NULL DEFAULT '0' COMMENT '单价(单位:分)',
  `num` int unsigned NOT NULL DEFAULT '0' COMMENT '数量',
  PRIMARY KEY (`id`),
  KEY `idx_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单详情表';

tb_order_item_2

CREATE TABLE `tb_order_item_2` (
  `id` bigint(20) NOT NULL COMMENT '主键',
  `order_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '订单id',
  `goods_name` varchar(100)  NOT NULL DEFAULT '' COMMENT '商品名称',
  `price` int unsigned NOT NULL DEFAULT '0' COMMENT '单价(单位:分)',
  `num` int unsigned NOT NULL DEFAULT '0' COMMENT '数量',
  PRIMARY KEY (`id`),
  KEY `idx_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单详情表';

四、配置(二选一)

4.1、properties配置

application.properties

server.port=8899
server.servlet.context-path=/sharding-jdbc

# 允许定义相同的bean对象去覆盖原有的
spring.main.allow-bean-definition-overriding=true
# 数据源名称,多数据源以逗号分隔
spring.shardingsphere.datasource.names=ds1
# sharding_1数据库连接池类名称
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
# sharding_1数据库驱动类名
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
# sharding_1数据库url连接
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.0.129:3306/sharding_7?serverTimezone=GMT%2B8&characterEncoding=utf8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&autoReconnect=true&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=6000&maxReconnects=5
# sharding_1数据库用户名
spring.shardingsphere.datasource.ds1.username=alian
# sharding_1数据库密码
spring.shardingsphere.datasource.ds1.password=123456

# 指定tb_order表的数据分布情况,配置数据节点,使用Groovy的表达式,逻辑表tb_order对应的节点是:ds1.tb_order_1, ds1.tb_order_2
spring.shardingsphere.sharding.tables.tb_order.actual-data-nodes=ds1.tb_order_$->{1..2}
# 采用行表达式分片策略:InlineShardingStrategy
# 指定tb_order表的分片策略中的分片键
spring.shardingsphere.sharding.tables.tb_order.table-strategy.inline.sharding-column=order_id
# 指定tb_order表的分片策略中的分片算法表达式,使用Groovy的表达式
spring.shardingsphere.sharding.tables.tb_order.table-strategy.inline.algorithm-expression=tb_order_$->{order_id%2==0?2:1}
# 指定tb_order表的主键为order_id
spring.shardingsphere.sharding.tables.tb_order.key-generator.column=order_id
# 指定tb_order表的主键生成策略为SNOWFLAKE
spring.shardingsphere.sharding.tables.tb_order.key-generator.type=SNOWFLAKE
# 指定雪花算法的worker.id
spring.shardingsphere.sharding.tables.tb_order.key-generator.props.worker.id=124
# 指定雪花算法的max.tolerate.time.difference.milliseconds
spring.shardingsphere.sharding.tables.tb_order.key-generator.props.max.tolerate.time.difference.milliseconds=20

# 指定tb_order_item表的数据分布情况,配置数据节点,使用Groovy的表达式,逻辑表tb_order_item对应的节点是:ds1.tb_order_item_1, ds1.tb_order_item_2
spring.shardingsphere.sharding.tables.tb_order_item.actual-data-nodes=ds1.tb_order_item_$->{1..2}
# 采用行表达式分片策略:InlineShardingStrategy
# 指定tb_order_item表的分片策略中的分片键
spring.shardingsphere.sharding.tables.tb_order_item.table-strategy.inline.sharding-column=order_id
# 指定tb_order_item表的分片策略中的分片算法表达式,使用Groovy的表达式
spring.shardingsphere.sharding.tables.tb_order_item.table-strategy.inline.algorithm-expression=tb_order_item_$->{order_id%2==0?2:1}
# 指定tb_order_item表的主键为order_id
spring.shardingsphere.sharding.tables.tb_order_item.key-generator.column=id
# 指定tb_order_item表的主键生成策略为SNOWFLAKE
spring.shardingsphere.sharding.tables.tb_order_item.key-generator.type=SNOWFLAKE
# 指定雪花算法的worker.id
spring.shardingsphere.sharding.tables.tb_order_item.key-generator.props.worker.id=125
# 指定雪花算法的max.tolerate.time.difference.milliseconds
spring.shardingsphere.sharding.tables.tb_order_item.key-generator.props.max.tolerate.time.difference.milliseconds=20

# tb_order和tb_order_item是绑定表
spring.shardingsphere.sharding.binding-tables[0]=tb_order,tb_order_item
# 打开sql输出日志
spring.shardingsphere.props.sql.show=true

4.2、yml配置

application.yml

server:
  port: 8899
  servlet:
    context-path: /sharding-jdbc

spring:
  main:
    # 允许定义相同的bean对象去覆盖原有的
    allow-bean-definition-overriding: true
  shardingsphere:
    props:
      sql:
       # 打开sql输出日志
       show: true
    datasource:
      # 数据源名称,多数据源以逗号分隔
      names: ds1
      ds1:
        # 数据库连接池类名称
        type: com.alibaba.druid.pool.DruidDataSource
        # 数据库驱动类名
        driver-class-name: com.mysql.cj.jdbc.Driver
        # 数据库url连接
        url: jdbc:mysql://192.168.0.129:3306/sharding_7?serverTimezone=GMT%2B8&characterEncoding=utf8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&autoReconnect=true&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=6000&maxReconnects=5
        # 数据库用户名
        username: alian
        # 数据库密码
        password: 123456
    sharding:
      # 未配置分片规则的表将通过默认数据源定位
      default-data-source-name: ds1
      tables:
        tb_order:
          # 由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持inline表达式
          actual-data-nodes: ds1.tb_order_$->{1..2}
          # 分表策略
          table-strategy:
            # 行表达式分片策略
            inline:
              # 分片键
              sharding-column: order_id
              # 算法表达式
              algorithm-expression: tb_order_$->{order_id%2==0?2:1}
          # key生成器
          key-generator:
            # 自增列名称,缺省表示不使用自增主键生成器
            column: order_id
            # 自增列值生成器类型,缺省表示使用默认自增列值生成器(SNOWFLAKE/UUID)
            type: SNOWFLAKE
            # SnowflakeShardingKeyGenerator
            props:
              # SNOWFLAKE算法的worker.id
              worker:
                id: 100
              # SNOWFLAKE算法的max.tolerate.time.difference.milliseconds
              max:
                tolerate:
                  time:
                    difference:
                      milliseconds: 20
        tb_order_item:
          # 由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持inline表达式
          actual-data-nodes: ds1.tb_order_item_$->{1..2}
          # 分表策略
          table-strategy:
            # 行表达式分片策略
            inline:
              # 分片键
              sharding-column: order_id
              # 算法表达式
              algorithm-expression: tb_order_item_$->{order_id%2==0?2:1}
          # key生成器
          key-generator:
            # 自增列名称,缺省表示不使用自增主键生成器
            column: id
            # 自增列值生成器类型,缺省表示使用默认自增列值生成器(SNOWFLAKE/UUID)
            type: SNOWFLAKE
            # SnowflakeShardingKeyGenerator
            props:
              # SNOWFLAKE算法的worker.id
              worker:
                id: 101
              # SNOWFLAKE算法的max.tolerate.time.difference.milliseconds
              max:
                tolerate:
                  time:
                    difference:
                      milliseconds: 20
      binding-tables:
        - tb_order,tb_order_item
  • 这里演示没分库,就是水平分表
  • 对于逻辑表 tb_order actual-data-nodes 使用Groovy的表达式 ds1.tb_order_$->{1…2},对应的物理表是:ds1.tb_order_1ds1.tb_order_2
  • 对于逻辑表 tb_order_item actual-data-nodes 使用Groovy的表达式 ds1.tb_order_item_$->{1…2},对应的物理表是:ds1.tb_order_item_1ds1.tb_order_item_2
  • table-strategy 表的分片策略,这里只是一个简单的奇数偶数,采用的是 行表达式分片策略 ,需要指定分片键和分片算法表达式(算法支持Groovy的表达式),这里 tb_order tb_order_item 都是使用相同的键进行分片,这里是order_id (一定不要搞错)
  • key-generator :key生成器,需要指定字段和类型,比如这里如果是SNOWFLAKE,最好也配置下props中的两个属性: worker.id max.tolerate.time.difference.milliseconds 属性

五、实现

5.1、实体层

Order.java

@Data
@Entity
@Table(name = "tb_order")
public class Order implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "order_id")
    private Long orderId;

    @Column(name = "user_id")
    private Integer userId;

    @Column(name = "price")
    private Integer price;

    @Column(name = "order_status")
    private Integer orderStatus;

    @Column(name = "title")
    private String title;

    @Column(name = "order_time")
    private LocalDateTime orderTime;

}

OrderItem.java

@Data
@Entity
@Table(name = "tb_order_item")
public class OrderItem implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "order_id")
    private Long orderId;

    @ManyToOne
    @JoinColumn(name = "order_id", referencedColumnName = "order_id", updatable = false, insertable = false)
    private Order order;

    @Column(name = "goods_name")
    private String goodsName;

    @Column(name = "price")
    private Integer price;

    @Column(name = "num")
    private Integer num;

}

5.2、持久层

OrderRepository.java

public interface OrderRepository extends PagingAndSortingRepository<Order, Long> {

    /**
     * 根据订单id查询订单
     * @param orderId
     * @return
     */
    Order findOrderByOrderId(Long orderId);
}

OrderItemRepository.java

public interface OrderItemRepository extends PagingAndSortingRepository<OrderItem, Long> {

    /**
     * 根据用户orderId查询订单详情
     *
     * @param orderId
     * @return
     */
    List<OrderItem> findAllByOrderId(Long orderId);
}

5.3、服务层

OrderService.java

@Slf4j
@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    public void saveOrder(Order order) {
        orderRepository.save(order);
    }

    public Order queryOrder(Long orderId) {
        return orderRepository.findOrderByOrderId(orderId);
    }
}

OrderItemService.java

@Slf4j
@Service
public class OrderItemService {

    @Autowired
    private OrderItemRepository orderItemRepository;

    public void saveOrderItem(OrderItem orderItem) {
        orderItemRepository.save(orderItem);
    }

    public List<OrderItem> queryOrderItem(Long orderId) {
        return orderItemRepository.findAllByOrderId(orderId);
    }
}

5.4、测试类

OrderTests.java

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class OrderTests {

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderItemService orderItemService;

    @Test
    public void saveOrder() {
        for (int i = 0; i < 10; i++) {
            Order order = new Order();

            OrderItem orderItem = new OrderItem();
            // 随机生成50到100的金额
            int price = (int) Math.round(Math.random() * (10000 - 5000) + 5000);
            // 随机生成1到10的数量
            int num = (int) Math.round(Math.random() * (10 - 1) + 1);
            orderItem.setPrice(price);
            orderItem.setNum(num);
            orderItem.setGoodsName("商品-" + price);

            order.setUserId(1000);
            order.setPrice(price * num);
            order.setOrderStatus(2);
            order.setOrderTime(LocalDateTime.now());
            order.setTitle("");
            orderService.saveOrder(order);
            // 设置orderId
            log.info("订单id:{}", order.getOrderId());
            orderItem.setOrderId(order.getOrderId());
            orderItem.setOrder(order);
            orderItemService.saveOrderItem(orderItem);
        }
    }

    @Test
    public void queryOrder() {
        Long orderId = 847575584761856000L;
        List<OrderItem> orderItemList = orderItemService.queryOrderItem(orderId);
        log.info("查询的结果:{}", orderItemList);
    }

}

5.4.1、保存订单数据

效果图:

在这里插入图片描述
  从上面的数据来看,tb_order_1的关联数据都在tb_order_item_1 中,tb_order_2的关联数据都在tb_order_item_2 中,这样就可以避免掉笛卡尔积。具体的我们看下查询。

5.4.2、查询订单详情数据(关联表)

20:53:20 526 INFO [main]:Logic SQL: select orderitem0_.id as id1_1_, orderitem0_.goods_name as goods_na2_1_, orderitem0_.num as num3_1_, orderitem0_.order_id as order_id4_1_, orderitem0_.price as price5_1_ from tb_order_item orderitem0_ where orderitem0_.order_id=?

20:53:20 526 INFO [main]:Actual SQL: ds1 ::: select orderitem0_.id as id1_1_, orderitem0_.goods_name as goods_na2_1_, orderitem0_.num as num3_1_, orderitem0_.order_id as order_id4_1_, orderitem0_.price as price5_1_ from tb_order_item_2 orderitem0_ where orderitem0_.order_id=? ::: [847575584761856000]

20:53:20 566 INFO [main]:Logic SQL: select order0_.order_id as order_id1_0_0_, order0_.order_status as order_st2_0_0_, order0_.order_time as order_ti3_0_0_, order0_.price as price4_0_0_, order0_.title as title5_0_0_, order0_.user_id as user_id6_0_0_ from tb_order order0_ where order0_.order_id=?

20:53:20 566 INFO [main]:Actual SQL: ds1 ::: select order0_.order_id as order_id1_0_0_, order0_.order_status as order_st2_0_0_, order0_.order_time as order_ti3_0_0_, order0_.price as price4_0_0_, order0_.title as title5_0_0_, order0_.user_id as user_id6_0_0_ from tb_order_2 order0_ where order0_.order_id=? ::: [847575584761856000]

20:53:20 580 INFO [main]:查询的结果:[OrderItem(id=847575584870912000, orderId=847575584761856000, order=Order(orderId=847575584761856000, userId=1000, price=45130, orderStatus=2, title=, orderTime=2023-03-28T20:42:47), goodsName=商品-9026, price=9026, num=5)]

  从上面的结果我们可以看到当我们查询order_id为 847575584761856000 的记录时,因为我们之前是按 order_id 进行的分表,偶数直接查询 tb_order_item_2 ,查询到订单详情记录后,关联查询订单记录,就直接查询 tb_order_2 ,都是主键或索引查询,没有出现笛卡尔积式的查询,提高了效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/532806.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

拓扑排序在处理树形关系结构中的应用

Preface 偶然在QQ上的一个交流群中看到了一位群友的棘手需求。互联网开发中&#xff0c;数据的落盘存储通常在MySQL中。MySQL是一种关系型数据库&#xff0c;以“行”为基本的存储单元&#xff0c;然后通过外键等建立数据实体模型之间的联系。 但有些数据的存储&#xff0c;在…

波奇学C++:友元函数,友元类,内部类,匿名对象,优化构造

友元函数/类 &#xff1a;突破访问限定符&#xff0c;允许非同一个类的函数或者类访私有成员变量。 class A { public:A():_a(0),_b(1){cout << "A()" << endl;} private:int _a 0;int _b 1; }; void fun(const A& a) {cout << a._a <&l…

canal学习-运行canal-adapter源码并记录解决报错问题(一)

运行canal-adapter 1. 下载canal源码1.1 下载源码并安装好环境1.2 查看目录结构 2.项目运行2.1 项目打包2.2 项目打包可能遇到的问题&#xff1a;1.Failure to find com.alibaba.otter:connector.tcp:jar:jar-with-dependencies:1.1.52.com.alibaba.druid.pool.DruidDataSource…

HTTP协议与TCP协议

HTTP协议 1. HTTP有哪些⽅法&#xff1f; HTTP 1.0 标准中&#xff0c;定义了3种请求⽅法&#xff1a;GET、POST、HEAD HTTP 1.1 标准中&#xff0c;新增了请求⽅法&#xff1a;PUT、PATCH、DELETE、OPTIONS、TRACE、CONNECT 2. 各个HTTP方法的具体作用是什么&#xff1f; 方…

量子计算:揭开未来计算世界的面纱

随着科技的飞速发展&#xff0c;计算能力的提升成为人们关注的焦点之一。而在这个领域中&#xff0c;量子计算正逐渐成为备受瞩目的新星。量子计算利用了量子力学的原理&#xff0c;与传统计算方式有着根本的不同。在传统计算中&#xff0c;信息以比特的形式表示&#xff0c;而…

COMSOL光电专题第三十三期(线上),COMSOL声学(北京线下)专题线上通知

背景&#xff1a; COMSOL多物理场仿真软件以高效的计算性能和杰出的多场耦合分析能力实现了精确的数值仿真&#xff0c;已被广泛应用于各个领域的科学研究以及工程计算&#xff0c;为工程界和科学界解决了复杂的多物理场建模问题。COMSOL内嵌的声学模块可以方便地进行多孔声学…

AI技术如何助力合同智能管理?

近年来&#xff0c;合同管理领域开始大规模应用AI技术&#xff0c;今天我们来关注下AI技术如何助力合同智能管理&#xff1f; 传统的合同管理系统&#xff0c;一般都是流程管理&#xff0c;随着AI技术的快速发展&#xff0c;AI技术已经成功应用到了合同全生命周期管理的各阶段…

计算机网络 三 (数据链路层)上

数据链路层 数据链路层的概述 基本概念 数据链路层是OSI参考模型中的第二层&#xff0c;它主要负责在物理层上提供可靠的数据传输服务&#xff0c;使得相邻节点间的数据传输能够实现。 数据链路层的基本概念如下&#xff1a; 帧&#xff1a;数据链路层数据传输的基本单位是…

Redis持久化:RDB和AOF(版本redis 7.0)

什么是持久化&#xff1f; 学过计算机基础的都知道以一种磁盘&#xff0c;只要关机&#xff0c;那么磁盘的内容都会被清空&#xff0c;这种磁盘称为内存&#xff0c;而Redis则是一种内存数据库&#xff0c;redis中的数据也都存储在磁盘中&#xff0c;如果服务器中进程被关掉&am…

麻了,真的不想做测试了...

前言 有不少技术友在测试群里讨论&#xff0c;近期的面试越来越难了&#xff0c;要背的八股文越来越多了,考察得越来越细&#xff0c;越来越底层&#xff0c;明摆着就是想让我们徒手造航母嘛&#xff01;实在是太为难我们这些测试工程师了。 这不&#xff0c;为了帮大家节约时…

Mathtype修改硕士论文公式格式

Mathtype修改硕士论文格式 1将word格式的公式变为mathtype格式1选中公式2点击mathtype中的转换公式 2修改mathtype格式的公式文字版式 1将word格式的公式变为mathtype格式 1选中公式 如果不选公式默认全文所有公式或者指定的公式。 2点击mathtype中的转换公式 选择要转换的…

汽车功能安全

前言 近些年来&#xff0c;功能安全在汽车传统底盘域和动力域的应用已较为成熟&#xff0c;各大汽车企业功能安全意识也逐渐增强。在辅助驾驶和自动驾驶爆发式增长的大趋势下&#xff0c;现代汽车的功能安全在目前尤为复杂的电子电气系统中就显得更为重要&#xff0c;功能安全…

MySQL---存储过程流程控制(判断(if、case)、循环(while、repeat、loop))

1. if判断 IF语句包含多个条件判断&#xff0c;根据结果为TRUE、FALSE执行语句&#xff0c;与编程语言中的if、else if、else 语法类似&#xff0c;其语法格式如下&#xff1a; -- 语法 if search_condition_1 then statement_list_1[elseif search_condition_2 then statem…

十八、Stream 流

目录 1、为什么要引入SpringCloud Stream 2、SpringCloud Stream简介 2.1、标准MQ架构图 2.2、SpringCloud Stream架构图 2.3、SpringCloud Stream处理流程 3、如何使用SpringCloud Stream 3.1、创建springcloud-stream-sender项目&#xff08;消息生产者&#xff09; …

SpringCloud_服务调用_Ribbon负载算法简介与如何替换(二)

SpringCloud_服务调用_Ribbon负载算法简介与如何替换(二) Ribbon核心组件IRule IRule:根据特定算法中从服务列表中选取一个要访问的服务 IRule接口有多种实现&#xff1a; Ribbon自带的7种负载规则 com.netflix.loadbalancer.RoundRobinRule 轮询 com.netflix.loadbalancer.Ra…

8年测试老鸟总结,软件测试工程师关键成长晋升要素,这些不能不知道...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、技术-依然是最…

MySQL深入浅出:自增长序列(@i:=@i+1)的用处及用法

目录 1&#xff1a;问题分析 2&#xff1a;模拟自增长序列 2.1 单表查询 2.2 多表关联查询 3&#xff1a;结束语 社区 1&#xff1a;问题分析 Oracle中的伪列 ROWNUM 是一组递增的序列&#xff0c;在查询数据时生成&#xff0c;为结果集中每一行标识一个行号, 每条记录…

医院运维场景下的风险感知

随着医疗信息化建设发展&#xff0c;医院的系统、设备不断叠加&#xff0c;在提升用户体验&#xff0c;享受高效医疗服务的同时&#xff0c;也为支撑系统稳定运行的信息部门带来巨大挑战。诸如科室复杂、应用场景多、终端运维工作量大、软件系统兼容需求强等痛点&#xff0c;并…

WPF MaterialDesign 初学项目实战(0):github 项目Demo运行

前言&#xff1a; 最近在学B站的WPF项目实战合集(2022终结版)&#xff0c;但是到22P时候发现UI框架 MaterialDesignThemes的Github上面的程序没办法正常运行&#xff0c;最后折腾了好久终于解决。 github地址 gitcode镜像地址 下载成功后 下载成功后是如下效果 打开这个文…

259元,诺基亚返祖式新机玩了把大的

智能手机经过这么多年发展&#xff0c;市场逐渐趋向成熟。 在这个过程中&#xff0c;优胜劣汰这一自然法则同样适用&#xff0c;无数没能经受住市场考验的企业也只能含泪离场。 其中最典型的例子还得是曾经手机中的王者诺基亚了。 当初在 Symbian&#xff08;塞班系统&#x…