前言
传统的将数据集中存储至单一数据节点的解决方案,在性能、可用性和运维成本这三方面已经难于满足互联网的海量数据场景。
数据分片
数据分片指按照某个维度将存放在单一数据库中的数据分散地存放至多个数据库或表中以达到提升性能瓶颈以及可用性的效果。 数据分片的有效手段是对关系型数据库进行分库和分表。分库和分表均可以有效的避免由数据量超过可承受阈值而产生的查询瓶颈。 除此之外,分库还能够用于有效的分散对数据库单点的访问量;分表虽然无法缓解数据库压力,但却能够提供尽量将分布式事务转化为本地事务的可能,一旦涉及到跨库的更新操作,分布式事务往往会使问题变得复杂。 使用多主多从的分片方式,可以有效的避免数据单点,从而提升数据架构的可用性。
通过分库和分表进行数据的拆分来使得各个表的数据量保持在阈值以下,以及对流量进行疏导应对高访问量,是应对高并发和海量数据系统的有效手段。 数据分片的拆分方式又分为垂直分片和水平分片。
1)垂直分片
按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用。 在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。 下图展示了根据业务需要,将用户表和订单表垂直分片到不同的数据库的方案。
垂直分片往往需要对架构和设计进行调整。通常来讲,是来不及应对互联网业务需求快速变化的;而且,它也并无法真正的解决单点瓶颈。 垂直拆分可以缓解数据量和访问量带来的问题,但无法根治。如果垂直拆分之后,表中的数据量依然超过单节点所能承载的阈值,则需要水平分片来进一步处理。
2)水平分片
水平分片又称为横向拆分。 相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。 例如:根据主键分片,偶数主键的记录放入0库(或表),奇数主键的记录放入1库(或表),如下图所示。
水平分片从理论上突破了单机数据量处理的瓶颈,并且扩展相对自由,是分库分表的标准解决方案。
小结:
为什么分片:因为数据随着系统的应用越来越大,可能达到数据库可存储的阀值;所以可以根据分片策略将数据按照规则放置到不同的数据库表中。
- 垂直分片:按照业务划分存放数据,一般专库专用
- 水平分片:按照数据的字段特征根据一定的算法将这些一条一条的记录保存到不同的数据库表中
Sharding Sphere分库分表
1)Sharding Sphere简介
Apache ShardingSphere(Incubator) 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(规划中)这3款相互独立,却又能够混合部署配合使用的产品组成。它们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、云原生等各种多样化的应用场景。
ShardingSphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。它通过关注不变,进而抓住事物本质。关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。
官网地址:http://shardingsphere.apache.org/index_zh.html
2)数据库准备
找到 课前资料包下 分库分表目录下的sql脚本 去执行,创建用于测试分库分表的数据库语句。
create database if not exists sharding0 default character set = 'utf8';
use sharding0;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `tb_order_1`;
CREATE TABLE `tb_order_1` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`total_fee` bigint(20) NOT NULL COMMENT '总金额,单位为分',
`actual_fee` bigint(20) NOT NULL COMMENT '实付金额。单位:分。如:20007,表示:200元7分',
`promotion_ids` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '优惠活动id,多个以,隔开',
`payment_type` tinyint(1) unsigned zerofill NOT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` bigint(20) NOT NULL COMMENT '邮费。单位:分。如:20007,表示:200元7分',
`user_id` bigint(20) NOT NULL COMMENT '用户id',
`invoice_type` int(1) DEFAULT '0' COMMENT '发票类型(0无发票1普通发票,2电子发票,3增值税发票)',
`source_type` int(1) DEFAULT '2' COMMENT '订单来源:1:app端,2:pc端,3:微信端',
`status` tinyint(1) DEFAULT NULL COMMENT '订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`pay_time` timestamp NULL DEFAULT NULL COMMENT '支付时间',
`consign_time` timestamp NULL DEFAULT NULL COMMENT '发货时间',
`end_time` timestamp NULL DEFAULT NULL COMMENT '交易完成时间',
`close_time` timestamp NULL DEFAULT NULL COMMENT '交易关闭时间',
`comment_time` timestamp NULL DEFAULT NULL COMMENT '评价时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`order_id`),
KEY `multi_key_status_time` (`status`,`create_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT = '订单表' ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `tb_order_2`;
CREATE TABLE `tb_order_2` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`total_fee` bigint(20) NOT NULL COMMENT '总金额,单位为分',
`actual_fee` bigint(20) NOT NULL COMMENT '实付金额。单位:分。如:20007,表示:200元7分',
`promotion_ids` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '优惠活动id,多个以,隔开',
`payment_type` tinyint(1) unsigned zerofill NOT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` bigint(20) NOT NULL COMMENT '邮费。单位:分。如:20007,表示:200元7分',
`user_id` bigint(20) NOT NULL COMMENT '用户id',
`invoice_type` int(1) DEFAULT '0' COMMENT '发票类型(0无发票1普通发票,2电子发票,3增值税发票)',
`source_type` int(1) DEFAULT '2' COMMENT '订单来源:1:app端,2:pc端,3:微信端',
`status` tinyint(1) DEFAULT NULL COMMENT '订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`pay_time` timestamp NULL DEFAULT NULL COMMENT '支付时间',
`consign_time` timestamp NULL DEFAULT NULL COMMENT '发货时间',
`end_time` timestamp NULL DEFAULT NULL COMMENT '交易完成时间',
`close_time` timestamp NULL DEFAULT NULL COMMENT '交易关闭时间',
`comment_time` timestamp NULL DEFAULT NULL COMMENT '评价时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`order_id`),
KEY `multi_key_status_time` (`status`,`create_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT = '订单表' ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `tb_order_3`;
CREATE TABLE `tb_order_3` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`total_fee` bigint(20) NOT NULL COMMENT '总金额,单位为分',
`actual_fee` bigint(20) NOT NULL COMMENT '实付金额。单位:分。如:20007,表示:200元7分',
`promotion_ids` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '优惠活动id,多个以,隔开',
`payment_type` tinyint(1) unsigned zerofill NOT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` bigint(20) NOT NULL COMMENT '邮费。单位:分。如:20007,表示:200元7分',
`user_id` bigint(20) NOT NULL COMMENT '用户id',
`invoice_type` int(1) DEFAULT '0' COMMENT '发票类型(0无发票1普通发票,2电子发票,3增值税发票)',
`source_type` int(1) DEFAULT '2' COMMENT '订单来源:1:app端,2:pc端,3:微信端',
`status` tinyint(1) DEFAULT NULL COMMENT '订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`pay_time` timestamp NULL DEFAULT NULL COMMENT '支付时间',
`consign_time` timestamp NULL DEFAULT NULL COMMENT '发货时间',
`end_time` timestamp NULL DEFAULT NULL COMMENT '交易完成时间',
`close_time` timestamp NULL DEFAULT NULL COMMENT '交易关闭时间',
`comment_time` timestamp NULL DEFAULT NULL COMMENT '评价时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`order_id`),
KEY `multi_key_status_time` (`status`,`create_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT = '订单表' ROW_FORMAT = Dynamic;
create database if not exists sharding1 default character set = 'utf8';
use sharding1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `tb_order_1`;
CREATE TABLE `tb_order_1` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`total_fee` bigint(20) NOT NULL COMMENT '总金额,单位为分',
`actual_fee` bigint(20) NOT NULL COMMENT '实付金额。单位:分。如:20007,表示:200元7分',
`promotion_ids` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '优惠活动id,多个以,隔开',
`payment_type` tinyint(1) unsigned zerofill NOT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` bigint(20) NOT NULL COMMENT '邮费。单位:分。如:20007,表示:200元7分',
`user_id` bigint(20) NOT NULL COMMENT '用户id',
`invoice_type` int(1) DEFAULT '0' COMMENT '发票类型(0无发票1普通发票,2电子发票,3增值税发票)',
`source_type` int(1) DEFAULT '2' COMMENT '订单来源:1:app端,2:pc端,3:微信端',
`status` tinyint(1) DEFAULT NULL COMMENT '订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`pay_time` timestamp NULL DEFAULT NULL COMMENT '支付时间',
`consign_time` timestamp NULL DEFAULT NULL COMMENT '发货时间',
`end_time` timestamp NULL DEFAULT NULL COMMENT '交易完成时间',
`close_time` timestamp NULL DEFAULT NULL COMMENT '交易关闭时间',
`comment_time` timestamp NULL DEFAULT NULL COMMENT '评价时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`order_id`),
KEY `multi_key_status_time` (`status`,`create_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT = '订单表' ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `tb_order_2`;
CREATE TABLE `tb_order_2` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`total_fee` bigint(20) NOT NULL COMMENT '总金额,单位为分',
`actual_fee` bigint(20) NOT NULL COMMENT '实付金额。单位:分。如:20007,表示:200元7分',
`promotion_ids` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '优惠活动id,多个以,隔开',
`payment_type` tinyint(1) unsigned zerofill NOT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` bigint(20) NOT NULL COMMENT '邮费。单位:分。如:20007,表示:200元7分',
`user_id` bigint(20) NOT NULL COMMENT '用户id',
`invoice_type` int(1) DEFAULT '0' COMMENT '发票类型(0无发票1普通发票,2电子发票,3增值税发票)',
`source_type` int(1) DEFAULT '2' COMMENT '订单来源:1:app端,2:pc端,3:微信端',
`status` tinyint(1) DEFAULT NULL COMMENT '订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`pay_time` timestamp NULL DEFAULT NULL COMMENT '支付时间',
`consign_time` timestamp NULL DEFAULT NULL COMMENT '发货时间',
`end_time` timestamp NULL DEFAULT NULL COMMENT '交易完成时间',
`close_time` timestamp NULL DEFAULT NULL COMMENT '交易关闭时间',
`comment_time` timestamp NULL DEFAULT NULL COMMENT '评价时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`order_id`),
KEY `multi_key_status_time` (`status`,`create_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT = '订单表' ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `tb_order_3`;
CREATE TABLE `tb_order_3` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`total_fee` bigint(20) NOT NULL COMMENT '总金额,单位为分',
`actual_fee` bigint(20) NOT NULL COMMENT '实付金额。单位:分。如:20007,表示:200元7分',
`promotion_ids` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '优惠活动id,多个以,隔开',
`payment_type` tinyint(1) unsigned zerofill NOT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` bigint(20) NOT NULL COMMENT '邮费。单位:分。如:20007,表示:200元7分',
`user_id` bigint(20) NOT NULL COMMENT '用户id',
`invoice_type` int(1) DEFAULT '0' COMMENT '发票类型(0无发票1普通发票,2电子发票,3增值税发票)',
`source_type` int(1) DEFAULT '2' COMMENT '订单来源:1:app端,2:pc端,3:微信端',
`status` tinyint(1) DEFAULT NULL COMMENT '订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`pay_time` timestamp NULL DEFAULT NULL COMMENT '支付时间',
`consign_time` timestamp NULL DEFAULT NULL COMMENT '发货时间',
`end_time` timestamp NULL DEFAULT NULL COMMENT '交易完成时间',
`close_time` timestamp NULL DEFAULT NULL COMMENT '交易关闭时间',
`comment_time` timestamp NULL DEFAULT NULL COMMENT '评价时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`order_id`),
KEY `multi_key_status_time` (`status`,`create_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT = '订单表' ROW_FORMAT = Dynamic;
执行完上面sql,会出现两个数据库,每个数据库都会有三张表:
3)执行逻辑图
解释:
当插入一条数据时,sharding Sphere根据order_id%2=0 || order_id%=1 选择插入对应的数据库,然后再根据order_id%3+1插入该库中的哪张表
举例:
order_id=100
1.order_id%2=0 那么就会选择插入sharding0这个库中,那三张表该插入到哪张表中呢?
2.先在这里说下为什么order_id%3要加1,因为我们在数据库中的表是tb_order_[1-3]的,而order_id%3的结果只可能是0-2,所以加1就可以对应表的后面那个数字,方便选择插入到哪张表
3.order_id%3+1=2,所以最终选择插入到sharding0数据库中的tb_order_2表中
4)分库分表技术对比
- MyCat 也可以进行数据库分库分表;但是mycat是在数据库层面进行的;如果使用了mycat则代码连接数据库的时候;连接的是mycat。所以必须要启动mycat服务器。
- 而Shading sphere 则是在代码层级进行分库分表的,不需要启动任何额外的服务器组件。
搭建分库分表示例工程并测试
创建工程导入以下依赖
<dependencies>
<!--通用mapper起步依赖-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.1.5</version>
</dependency>
<!--MySQL数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<!--mybatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
</dependencies>
启动类
@SpringBootApplication
@MapperScan("com.xxx.sharding.mapper")
public class ShardingSphereApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingSphereApplication.class,args);
}
}
编写实体类
@Data
@Table(name = "tb_order") //这里的表名和数据库中表名的不一样,到时候会拼接
public class Order implements Serializable {
@Id
private Long orderId; // 订单编号
private Long totalFee; // 商品金额
private Long postFee; // 邮费
private Long actualFee; // 实付金额
private Integer paymentType; // 付款方式:1:在线支付, 2:货到付款
private String promotionIds; // 优惠促销的活动id
private Long userId; // 用户id
private Integer status; // 订单状态
private Date createTime; // 创建时间
private Date payTime; // 付款时间
private Date consignTime; // 发货时间
private Date endTime; // 确认收货时间
private Date closeTime; // 交易关闭时间
private Date commentTime; // 评价时间
private Date updateTime; // 更新时间
private Integer invoiceType; // 发票类型,0无发票,1普通发票,2电子发票,3增值税发票
private Integer sourceType; // 订单来源 1:app端,2:pc端,3:微信端
}
编写mapper
public interface OrderMapper extends Mapper<Order> {
}
添加配置文件
这个需要大家仔细看下,是根据什么策略就是插入数据的
#配置数据源
sharding:
jdbc:
datasource:
#数据库名,名称不能包含下划线
names: sharding0,sharding1
sharding0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/sharding0?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
sharding1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/sharding1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
config:
props:
sql:
show: true #在控制台显示最终sql语句
sharding:
#分库策略;行表达式分片策略
default-database-strategy:
inline:
#根据哪个字段进行分库;
sharding-column: order_id
# 策略;确定数据进入哪个库【这里是order_id 除以2 取余为0的,即偶数】
#当order_id除以2取余为0的就拼接前面数据库的名字 sharding0 反之就余1就是插入到sharding1数据库中,因为对2取模,不是0,就是1
algorithm-expression: sharding$->{order_id%2}
#知道分到哪个库了,还用设置插入到哪个表中
tables:
# 分表策略
tb_order:
#数据库表节点
actual-data-nodes: sharding$->{0..1}.tb_order_$->{1..3}
# 分表策略
table-strategy:
inline:
# 根据哪个字段进行分表
sharding-column: order_id
# 策略;确定数据进入哪张表
#由于表是tb_order_1-3,而对3取模的结果只会是【0-2】所以取模后加1才能对应插入哪个表
algorithm-expression: tb_order_$->{order_id%3 + 1}
# 主键
key-generator-column-name: order_id
key-generator-column-class: SNOWFLAKE
spring:
main:
allow-bean-definition-overriding: true
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingTest extends TestCase {
@Autowired
private OrderMapper orderMapper;
// 插入测试
@Test
public void test(){
Order order;
int count;
Random random = new Random();
for (int i = 0; i < 100; i++) {
order = new Order();
order.setUserId(1L);// 使用工具类获取拦截器传递过来的用户id
order.setStatus(1); // 订单状态
order.setSourceType(2); // 订单来源 1:app端,2:pc端,3:微信端
order.setPostFee(0L);// 邮费:全场包邮
order.setPaymentType(1);// 支付类型:在线支付
order.setInvoiceType(0);// 发票类型,0无发票,1普通发票,2电子发票,3增值税发票
order.setActualFee(1L);//实际支付 = 总金额 - 活动金额 ; 这里为了测试我们写个1分
order.setTotalFee(Long.valueOf(random.nextInt(1000)+i)); // 总金额
count = orderMapper.insertSelective(order);
System.out.println("插入条数:"+count);
}
}
// 查询所有
@Test
public void test2(){
List<Order> items = orderMapper.selectAll();
System.out.println("总记录数======>"+items.size());
System.out.println(items.get(0));
}
// 根据id查询
@Test
public void test3(){
Order item = orderMapper.selectByPrimaryKey(1225310911506550784L);
System.out.println(item);
}
// 更新
@Test
public void test4(){
Order order = new Order();
order.setOrderId(1225310911506550784L);
order.setUserId(2222L);
order.setStatus(0);
int count = orderMapper.updateByPrimaryKeySelective(order);
System.out.println(count);
order = orderMapper.selectByPrimaryKey(1225310911506550784L);
System.out.println(order);
}
// 删除
@Test
public void test5(){
int count = orderMapper.deleteByPrimaryKey(1225310911506550784L);
System.out.println(count);
}
}
数据库已经插入数据