MySQL-进阶

news2024/9/23 7:29:51

存储引擎

MySQL体系结构

  • 连接层:
    • 最上层是一些客户端和连接服务,主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
  • 服务层:
    • 第二层架构主要完成大多数的核心服务功能,如SQL接口,经完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现。如 过程、函数等。
  • 引擎层:
    • 存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以感觉自己的需要,来选去合适的存储引擎。
  • 存储层:
    • 主要是将数据存储在文件系统之上,并完成与存储引擎的交互。

存储引擎简介

存储引擎就是存储数据、建立索引、更新、查询数据等技术的实现方式。存储引擎是基于表的,而不是基于库的,所有存储引擎又称为表类型。

-- -------------------------------------------------进阶
-- 查询创建表语句
show create table dept;
-- 查询支持的存储引擎
show engines ;
-- 创建一个my_MyISAMy表,用MyISAM引擎
create table my_MyISAM(
    id   int,
    name varchar(10)
)engine=MyISAM;

存储引擎特点

  • InnoDB
    • 介绍
      • InnoDB是一种兼顾可靠性和高性能的通用存储引擎,在MySQL5.5之后,InnoDB是默认的MySQL存储引擎。
    • 特点
      • DML操作遵循ACID模型,支持事务;
      • 行级锁,提高并发访问性能
      • 支持外键约束,保证数据的完整性和正确性
    • 文件
      • xxx.ibd:xxx代表的是表名,innoDB引擎的每张表都会对应这样一个表空间文还能,存储该表的表结构、数据和索引
      • 参数是:innodb_file_per_table
  • MyISAM
    • 介绍
      • MyISAM是MySQL早期的默认存储引擎。
    • 特点
      • 不支持事务,不支持外键
      • 支持表锁,不支持行锁
      • 访问速度快
    • 文件
      • xxx.sdi:存储表结构信息
      • xxx.MYD:存储数据
      • xxx.MYI:存储索引
  • Memory
    • 介绍:
      • Memory引擎的表数据是存储在内存中,由于受到硬件的问题或断电问题的影响,只能做为临时表或缓存使用
    • 特点:
      • 内存存放
      • hash索引(默认)
    • 文件:
      • xxx.sdi:存储表结构信息

存储引擎选择

在选择存储引擎时,应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组 合。

  • lnnoDB:是Mysql的默认存储引擎,支持事务、外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致 性,数据操作除了插入和查询之外,还包含很多的更新、删除操作,那么InnoDB存储引擎是比较合适的选择。
  • MylISAM:如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那 么选择这个存储引擎是非常合适的。
  • MEMORY:将所有数据保存在内存中,访问速度快,通常用于临时表及缓存。MEMORY的缺陷就是对表的大小有限制,太大的表 无法缓存在内存中,而且无法保障数据的安全性。

小结

索引

介绍

索引(index)是帮助MySQL高效获取数据数据结构有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些 数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

优缺点

优势

  • 提高数据检索的效率,降低数据库的I0成本
  • 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消 耗。

劣势

  • 索引列也是要占用空间的。
  • 索引大大提高了查询效率,同时却也降低更新表的速度,如对表进 行INSERT、UPDATE、DELETE时,效率降低。
索引结构

MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的结构,主要包含以下几种:

索引结构描述
B+Tree索引最常见的索引类型,大部分引擎都支持B+树索引
Hash索引底层数据结构是用哈希表实现的,只有精确匹配索引列的查询才有效,不支持范围查询
R-tree(空间索引)空间索引是MylSAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少
Full-text(全文索引)是一种通过建立倒排索引,快速匹配文档的方式。类似于Lucene,Solr,ES

我们平常所说的索引,如果没有特别指明,都是指B+树结构组织的索引。

索引InnoDBMyISAMMemory
B+tree索引支持支持支持
Hash索引不支持不支持支持
R-tree索引不支持支持不支持
Full-text5.6版本之后支持支持不支持
B-Tree(多路平衡查找树)

以一颗最大度数(max-degree)为5(5阶)的b-tree为例(每个节点最多存储4个key,5个指针):

具体动态变化的过程可以参考网站:https://www.cs.usfca.edu/~galles/visualization/BTree.html

B+Tree

相对于B-Tree区别:

  • ①.所有的数据都会出现在叶子节点
  • ②.叶子节点形成一个单向链表

MySQL索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能。

Hash

哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash表中。 如果两个(或多个)键值,映射到一个相同的槽位上,他们就产生了hash冲突(也称为hash碰撞),可以通过链表来解决。

 Hash索引特点

  •  Hash索引只能用于对等比较(=,in),不支持范围查询(between,>,<,.)
  • 无法利用索引完成排序操作
  • 查询效率高,通常只需要一次检索就可以了,效率通常要高于B+tree索引

存储引擎支持

在MySQL中,支持hash索引的是Memory引擎,而InnoDB中具有自适应hash功能,hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的。

为什么InnoDB存储引擎选择使用B+tree索引结构?
  • 相对于二叉树,层级更少,搜索效率高;
  • 对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一 页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的 高度,导致性能降低;
  • 相对Hash索引,B+tree支持范围匹配及排序操作;
索引分类

在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:

聚集索引选取规则:

  • 如果存在主键,主键索引就是聚集索引。
  • 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
  • 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。

回表查询:先在二级索引中找到对应的主键值,再到聚集索引中拿到这一行的行数据。

索引语法 

创建索引

create [unique|fulltext] index index_name on table_name(index_col_name); 

查看索引

show index from table_name;

删除索引

drop index index_name on table_name
SQL性能分析工具
 SQL执行频率

MySQL客户端连接成功后,通过show[sessionlglobal] status命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的 INSERT、UPDATE、DELETE、SELECT的访问频次:

 show global status like 'Com_______';
慢查询日志

 慢查询日志记录了所有执行时间超过指定参数(long_query_time, 单位:秒,默认10秒)的所有SQL语句的日志。

查询慢查询日志状态:

show variables like 'slow_query_log';

MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:

#开启MySQL慢日志查询开关
slow_query_log=1
#设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time=2
 profile详情

执行一系列的业务SQL的操作,然后通过如下指令查看指令的执行耗时:

#查看每一条SQL的耗时基本情况
show profiles;
#查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
#查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;

 explain执行计划

EXPLAIN 或者 DESC命令获取 MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。 

语法:
 #直接在select语句之前加上关键字explain/ desc 
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件

 EXPLAIN 执行计划各字段含义:

  • ld select查询的序列号,表示查询中执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)。
  • select_type 表示SELECT的类型,常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、 UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等
  • type 表示连接类型,性能由好到差的连接类型为NULL、system、const、eq_ref、ref、range、index、all。
  • possible_key 显示可能应用在这张表上的索引,一个或多个。
  • Key 实际使用的索引,如果为NULL,则没有使用索引。
  • Key_len 表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好。
  • rows MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的。
  • filtered 表示返回结果的行数占需读取行数的百分比,filtered的值越大越好。

SQL优化

视图/存储过程/触发器

视图

介绍

视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。

通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。

语法
创建
CREATE [OR REPLACE] VIEW 视图名称[(列名列表)]AS SELECT语句[WITH[CASCADED|LOCAL]CHECK OPTION]
查询
查看创建视图语句:SHOW CREATE VIEW 视图名称;
查看视图数据:SELECT*FROM 视图名称.…;
修改
方式一:CREATE OR REPLACE VIEW 视图名称[(列名列表)]AS SELECT语句[WITH[CASCADED|LOCAL]CHECK OPTION]
方式二:ALTER VIEW 视图名称[(列名列表)]AS SELECT语句[WITH[CASCADED|LOCAL]CHECK OPTION]
删除
DROP VIEW [IF EXISTS] 视图名称[视图名称]…

视图的检查选项

当使用WITH CHECK OPTION子句创建视图时,MySQL会通过视图检查正在更改的每个行,例如插入,更新,删除,以使其符合视图的定 义。

MySQL允许基于另一个视图创建视图,它还会检查依赖视图中的规则以保持一致性。为了确定检查的范围,mysql提供了两个选项: CASCADED和LOCAL,默认值为CASCADED。 CASCADED :

create or replace view stu_v1 as select sid, sname from student where sid<20;
select * from stu_v1;
insert into stu_v1 values (21,'hi');-- 插入成功
insert into stu_v1 values (19,'ho');-- 插入成功,不会检查增删改操作

create or replace view stu_v3 as select sid, sname from stu_v1 where sid>5 with cascaded check option ;
select * from stu_v3;
insert into stu_v3 values (21,'hii');-- 插入失败
insert into stu_v3 values (3,'hoo');-- 插入失败
insert into stu_v3 values (11,'hio');-- 插入成功

create or replace view stu_v5 as select sid, sname from stu_v3 where sid<=15;
insert into stu_v5 values (17,'hii');-- 插入成功
insert into stu_v5 values (21,'hoo');-- 插入失败
insert into stu_v5 values (5,'hio');-- 插入失败

 创建视图时加with cascaded(级联的) check option的话,会检查当前视图还会检查当前视图所以依赖的所有视图它的条件是否满足;

local

create or replace view stu_v2 as select sid, sname from student where sid<20;
select * from stu_v2;
insert into stu_v2 values (21,'hi');-- 插入成功,不满足v2
insert into stu_v2 values (19,'ho');-- 插入成功,不会检查增删改操作

create or replace view stu_v4 as select sid, sname from stu_v2 where sid>5 with local check option ;
select * from stu_v4;
insert into stu_v4 values (21,'hii');-- 插入成功,不满足v2
insert into stu_v4 values (3,'hoo');-- 插入失败,不满足v4
insert into stu_v4 values (11,'hio');-- 插入成功

create or replace view stu_v6 as select sid, sname from stu_v4 where sid<=15;
insert into stu_v6 values (17,'hii');-- 插入成功,不满足v6
insert into stu_v6 values (21,'hoo');-- 插入成功,不满足v2
insert into stu_v6 values (5,'hio');-- 插入失败,不满足v4

 定义视图时,有检查条件,就进行检查,没有就不进行检查;递归的检查依赖

视图的更新

要使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系。

如果视图包含以下任何一项,则该视图不可更新:

1.聚合函数或窗口函数(SUM()、MIN()、MAX()、COUNT()等)

2. DISTINCT Aae

3. GROUP BY

4. HAVING

5.UNION或者UNION ALL

作用

  • 简单
    • 视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作 每次指定全部的条件。
  • 安全
    • 数据库可以授权,但不能授权到数据库特定行和特定的列上。通过视图用户只能查询和修改他们所能见到的数据
  • 数据独立
    • 视图可帮助用户屏蔽真实表结构变化带来的影响。

触发器

介绍

    触发器是与表有关的数据库对象,指在insert/update/delete之前或之后,触发并执行触发器中定义的SQL语句集合。触发器的这种特 性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作。

    使用别名OLD和NEW来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发,不支持语句级触发。

 语法
创建
CREATE TRIGGER trigger_name
BEFORE/AFTER INSERT/UPDATE/DELETE
ON tbl name FOR EACH ROW --行级触发器
BEGIN
trigger_stmt ;
END;
查看
SHOW TRIGGERS ;
删除
DROP TRIGGER [schema_name.]trigger_name;-如果没有指定schema_name,默认为当前数据库。

-- 准备工作:日志表
create table emoloyee_logs(
    id int(11) not null auto_increment primary key ,
    operate varchar(20) not null ,
    operate_time datetime not null,
    operate_id int(11) not null ,
    operate_params varchar(500)
);
-- 插入数据触发器
create trigger tb_employee_insert_trigger
    after insert on employee for each row
begin
    insert into emoloyee_logs(id,operate,operate_time,operate_id,operate_params) values
    (null,'insert',now(),new.eno,concat('插入的数为:id',new.eno));
end
-- 查看触发器
show triggers ;

-- 插入数据
insert into employee values (7,'小2','男','项目部',1500);

-- 修改数据的触发器
create trigger tb_employee_update_trigger
    after update on employee for each row
begin
    insert into emoloyee_logs(id,operate,operate_time,operate_id,operate_params) values
    (null,'update',now(),new.eno,
    concat('更新之前的数为:name:',old.ename,'| 更新之后的数:name:',new.ename));
end

-- 更新数据
update employee set ename='张1' where employee.eno<3;


-- 删除数据的触发器
create trigger tb_employee_delete_trigger
    after delete on employee for each row
begin
    insert into emoloyee_logs(id,operate,operate_time,operate_id,operate_params) values
    (null,'delete',now(),old.eno,
    concat('删除之前的数为:name:',old.ename));
end

-- 删除数据
delete from employee where eno=6;
案例1:
create trigger sc_update_trigger
    before update on sc for each row
begin
    if old.grade-new.grade>=10 then
        insert into sc_G values(new.sno,new.cno,old.grade,now());
    end if;
end;
-- ----
show triggers ;
-- 更新
update sc set grade=grade-30 where sno='10060101'&&cno='07294001';
update sc set grade=grade-5 where sno='10060102'&&cno='07294002';
update sc set grade=grade-10 where sno='10060103'&&cno='07294002';
-- ----------------------------------------2
create table avg_sno(
    sno varchar(20) not null ,
    avg_sno double comment '平均成绩'
);
-- 触发器
create trigger avg_sno_trigger
    after update on sc for each row
begin
    insert into avg_sno values(NEW.sno,(select avg(new.grade) from sc));
end;

-- ------
update sc set grade=grade-20 where sno='10060101'&&cno='07294001';
update sc set grade=grade-5 where sno='10060102'&&cno='07294002';
update sc set grade=grade-10 where sno='10060103'&&cno='07294002';

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

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

相关文章

新的centos7.9安装jenkins(二)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 接上一节文章。 这个版本默认git也安装好了&#xff0c;所以全局配置这个不需要了。 maven安装3.9.3版本…

C++基础(4)——类与对象(默认成员函数)

目录 1.拷贝构造函数&#xff1a; 1.1 为什么要引入拷贝构造&#xff1a; 1.2 拷贝构造函数的定义及特性&#xff1a; 1.3 什么类可以不用编写拷贝构造&#xff1a; 2. 赋值运算符重载&#xff1a; 2.1 为社么要引入运算符重载&#xff1a; 2.2运算符重载的定义以及特性…

EasyExcel 注解fillForegroundColor

EasyExcel 注解fillForegroundColor 对应的颜色值 /** * 样式的数据类 * * author leiyiDong **/ Data // 头背景设置成红色 IndexedColors.RED.getIndex() HeadStyle(fillPatternType FillPatternType.SOLID_FOREGROUND, fillForegroundColor 10) // 头字体设置成20 Hea…

qml ParticleSystem3D使用介绍

在 Qt Quick 3D 中,ParticleSystem3D 是用来创建和控制3D粒子系统的元素。粒子系统是图形编程中用于模拟液体、烟雾、火、星空等现象的技术,它通过生成大量小粒子来模拟这些效果。ParticleSystem3D 提供了一个框架,允许开发者定义粒子的各种属性,如生命周期、速度、颜色、大…

Vue3+vite 处理静态资源,解决服务器不显示动态循环img问题

注意&#xff1a; vue2webpack中&#xff0c;通常使用require来动态渲染静态资源。但在vue3vite中&#xff0c;不支持require语法&#xff0c;因此使用require会报undefined&#xff0c;所以官方推荐使用import来动态渲染静态资源。 实现方式动态渲染静态资源 vue2webpack 使…

GitHub桌面版

GitHub桌面版 一、GitHub 桌面版二、clone 仓库三、更新仓库 一、GitHub 桌面版 二、clone 仓库 三、更新仓库

Netty Review - 探索ByteBuf的内部机制

文章目录 概念ByteBuf VS Java NIO BufferByteBuf实现类HeapByteBuf vs DirectByteBufPooledByteBuf vs UnpooledByteBuf其他 ByteBuf的实现机制 概念 ByteBuf是Netty中用于处理二进制数据的缓冲区 Netty的ByteBuf是一个可用于高效存储和操作字节数据的数据结构。与传统的Byt…

OpenStack云计算平台-计算服务

目录 一、计算服务概览 二、安装并配置控制节点 1、先决条件 2、安全并配置组件 3、完成安装 三、安装和配置计算节点 1、安全并配置组件 2、完成安装 四、验证操作 一、计算服务概览 使用OpenStack计算服务来托管和管理云计算系统。OpenStack计算服务是基础设施即服务…

新的预测模型的局部评价指标-pAUROCc

新的预测模型的局部评价指标-pAUROCc Background 局部评价主要是用在不平衡数据上&#xff0c;其合理性&#xff1a;1.局部评价比全局评价敏感&#xff0c;更容易区分模型的优劣&#xff1b;2.临床决策曲线&#xff08;DCA&#xff09;可知&#xff0c;模型使用过程中&#x…

【SpringCloud】从单体架构到微服务架构

今天来看看架构的演变过程 一、单体架构 从图中可以看到&#xff0c;所有服务耦合在一起&#xff0c;数据库存在单点&#xff0c;一旦其中一个服务出现问题时&#xff0c;整个工程都需要重新发布&#xff0c;从而导致整个业务不能提供响应 这种架构对于小项目而言是没有什么…

bclinux aarch64 ceph 14.2.10 云主机 性能对比FastCFS vdbench

部署参考 ceph-deploy bclinux aarch64 ceph 14.2.10-CSDN博客 ceph-deploy bclinux aarch64 ceph 14.2.10【3】vdbench fsd 文件系统测试-CSDN博客 ceph 14.2.10 aarch64 非集群内 客户端 挂载块设备-CSDN博客 FastCFS vdbench数据参考 bclinux aarch64 openeuler 20.03 …

C++初阶 | [五] 内存管理

摘要&#xff1a;new and delete&#xff0c;定位new&#xff0c;&#xff08;C内存管理的方式&#xff09;&#xff0c;malloc/free和new/delete的区别&#xff0c;内存泄漏 关于内存&#xff1a; 栈又叫堆栈——非静态局部变量/函数参数/返回值等等&#xff0c;栈是向下增长…

Modbus RTU协议及modbus库函数使用

一、与Modbus TCP的区别 在一般工业场景使用modbus RTU的场景还是更多一些&#xff0c;modbus RTU基于串行协议进行收发数据&#xff0c;包括RS232/485等工业总线协议。 与modbus TCP不同的是RTU没有报文头MBAP字段&#xff0c;但是在尾部增加了两个CRC检验字节&#xff08;CRC…

红队攻防实战之内网穿透隐秘隧道搭建

别低头&#xff0c;皇冠会掉&#xff1b;别流泪&#xff0c;贱人会笑。 本文首发于先知社区&#xff0c;原创作者即是本人 0x00 前言 构建内网隐蔽通道&#xff0c;从而突破各种安全策略限制&#xff0c;实现对目标服务器的完美控制。 当我们从外网成功获得攻击点的时候&…

【性能优化】JVM调优与写出JVM友好高效的代码

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

git clone -mirror 和 git clone 的区别

目录 前言两则区别git clone --mirrorgit clone 获取到的文件有什么不同瘦身仓库如何选择结语开源项目 前言 Git是一款强大的版本控制系统&#xff0c;通过Git可以方便地管理代码的版本和协作开发。在使用Git时&#xff0c;常见的操作之一就是通过git clone命令将远程仓库克隆…

ky10 server sp3 解决/boot/grub2/grub.cfg 找不到

现象 /boot/grub2 目录下不存在grub.cfg 配置文件 解决 执行下面脚本即可 yum install -y grub2 grub2-mkconfig -o /boot/grub2/grub.cfg 执行完成第一条命令 执行完成第二条命令 查看效果 已经生成这个文件了

Visual Studio 2019 C# System.BadImageFormatException 解决方法

文章目录 1.DLL文件缺失或不匹配原因解决方法 2.系统环境变量Path下内容过多原因解决方法 3.位数错误原因解决方法 分析几种可能因素 1.DLL文件缺失或不匹配 原因 检查对应Debug路径下的DLL文件是否有缺失 解决方法 将对应的DLL文件放到Debug文件夹里面&#xff0c;检查冗余…

成为AI产品经理——模型构建过程(上)

目录 一、背景 1.对内 2.对外 二、模型构建过程 1.模型设计 2.特征工程 ① 数据清洗 ② 特征提取 数值型数据 标签/描述类数据特征 非结构化数据&#xff08;处理文本特征&#xff09; 网络关系型数据 ③ 特征选择 ④ 训练集/测试集 一、背景 虽然产品经理不…

飞翔的鸟游戏

一.准备工作 首先创建一个新的Java项目命名为“飞翔的鸟”&#xff0c;并在src中创建一个包命名为“com.qiku.bird"&#xff0c;在这个包内分别创建4个类命名为“Bird”、“BirdGame”、“Column”、“Ground”&#xff0c;并向需要的图片素材导入到包内。 二.代码呈现 pa…