【iOS】数据持久化(三)之SQLite3数据库

目录

    • 数据库简介
    • 什么是`SQLite`?
      • 在Xcode引入SQLite API
      • SQL语句的种类
      • 存储字段类型
    • SQLite的使用
      • 创建数据库
      • 创建表和删表
      • 数据表操作
        • 增(插入数据INSERT)
        • 删(删除数据DELETE)
        • 改(更新数据UPDATE)
        • 查(查询数据SELECT)
      • 补充
        • 条件语句
        • 起别名
        • 计算数据的数量
        • 排序
        • LIMIT
    • 结束语

数据库简介

本文介绍SQLite的使用,首先简单了解一下什么是数据库

  • 数据库(Database)是根据数据结构来组织、存储和管理数据的仓库
  • 数据库大致分为两种:关系型数据库(主流)、对象型数据库

什么是SQLite

SQLite是一款轻型的嵌入式数据库(用C语言写的开源库),实现了一个自包含的SQL关系型数据库引擎,可存储并操作大量数据,作为关系型数据库我们可以在一个数据库中建立多张相关联的表来解决大量数据重复的问题,而且SQLite库也针对移动设备上的使用进行了优化。

SQLite的接口使用C语言写的,而且 Objective-C是C的超集,所以可以直接在工程中使用SQLite

SQLite占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了,而且处理速度比Mysql、PostgreSQL这两款著名的数据库都还快

在Xcode引入SQLite API

  1. 项目配置界面,选择Build Phrases
    在这里插入图片描述
  2. 点开Link Binary With Libraries后,点击+号,子弹窗输入sqlite
    请添加图片描述
  3. 添加任意一个,两个都是一样的
    请添加图片描述
  4. 在需要使用SQLite的地方导入sqlite库即可
#import <sqlite3.h>

@interface ViewController () {
    sqlite3* _sqlite;
}
@end

SQL语句的种类

数据定义语句(DDL:Data Definition Language)

  • 定义和管理SQL数据库中所有对象(一般是表TABLE,主要用在定义和改变的结构、数据结构、之间的链接和约束等初始化工作上
  • 包括在数据库中创建新表、删除表或改变表(CREATE TABLEDROP TABLEALTER TABLE)等操作

数据操作语句(DML:Data Manipulation Language)

  • 对表(TABLE)中的数据进行操作
  • 包括INSERTDELETEUPDATESELECT等操作

数据查询语句(DQL:Data Query Language)

  • 查询获得表中的数据
  • 基本结构是由SELECT子句、FROM子句、WHERE子句组成的查询块
  • 还包括order bygroup byhaving

数据控制语句(DCL:Data Control Language)

  • 定义数据库、表、字段、用户的访问权限和安全级别,并控制不同数据的直接许可和访问级别,对数据库进行实时监控
  • 包括COMMIT提交、ROLLBACK回滚、GRANTREVOKE

存储字段类型

存储类描述
NULL空值
INTEGER带符号的整型值
REAL浮点值
TEXT文本字符串,使用数据库编码(UTF-8、UTF-16BE或UTF-16LE)存储
BLOB二进制数据(比如文件、模型),完全根据它的输入存储

实际上SQLite字段是无类型的,就算声明为INTEGER类型,仍能存储字符串文本(主键除外),建表时声明任何类型或不声明类型都可以(比如CREATE TABLE TB_One(name, age)

为了保持良好的编程规范,方便程序员之间的交流,编写建表语句的时候最好加上每个字段的具体类型,也是约定俗成的规则

SQLite的使用

创建数据库

实际上是打开指定数据库,有数据库文件就去打开它,没有就自动创建数据库

1. 获取数据库文件路径

    //SQLite文件名称
    static NSString* const dataBaseName = @"MyFirstDB.sqlite";
    
    //将数据库存到沙盒中的Documents路径
    //获取Documents路径
    NSString* sandBoxPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    
    //拼接得到数据库文件地址
    NSString* filePath = [sandBoxPath stringByAppendingPathComponent: dataBaseName];

SQLite文件名称自己随便起,后缀最好是.db.sqilte,用来表示这是一个数据库

2. 打开指定数据库

NSInteger status = sqlite3_open(filePath.UTF8String, &_sqlite);
if (status == SQLITE_OK) {
    NSLog(@"打开数据库成功");
} else {
    NSLog(@"打开数据库失败");
}
  • sqlite3_open(const char *filename, sqlite3 **ppDb);方法用于打开数据库连接
  • 第一个参数是数据库文件的路径,第二个参数是一个数据库的实例,即一个sqlite3*类型的引用(声明),如果要进行增删改查,就得操作_sqlite这个实例。
  • 这个方法有一个枚举返回值表示是否打开了数据库,这里先用整型变量status接收这个返回值
  • filePath是OC类型的字符串,但sqlite3_open要求传递的是C类型的字符串,使用UTF8String将OC风格的字符串转成C风格的字符串

枚举值 SQLITE_OK 代表成功的状态:

在这里插入图片描述
查看沙盒内的数据库文件:

请添加图片描述

创建表和删表

当我们第一次打开数据库后,数据库里面什么都没有,我们需要创建一张数据库表来存放数据

1. 创建表基本格式

  • CREATE TABLE 表名 (字段名1 字段类型 约束, 字段名2 字段类型2 约束, …);
  • CREATE TABLE IF NOT EXISTS表明 (字段名1 字段类型 约束, 字段名2 字段类型2 约束, …); 判断表是否已存在,不存在则创建,防止创建重复的表

示例:CREATE TABLE t_Student(ID INTEGER, NAME TEXT NOT NULL, AGE INTEGER NOT NULL, SCORE REAL);NAME和AGE后面的NOT NULL约束表示在表中创建记录时这个字段不能为NULL,常见的约束还有DEFAULTUNIQUEPRIMARY KEY约束,更多SQLite约束的总结详见这篇文章:SQLite约束总结

NSInteger state = sqlite3_open(filePath.UTF8String, &_sqlite);
    if (state == SQLITE_OK) {
        NSLog(@"打开数据库成功");
        
        //创建表SQL语句
        NSString* SQLString = @"CREATE TABLE IF NOT EXISTS t_Student(ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER NOT NULL, SCORE REAL)";
        
        //保存错误信息
        char* errorMsg = NULL;
        NSInteger result = sqlite3_exec(_sqlite, SQLString.UTF8String, NULL, NULL, &errorMsg);
        if (result == SQLITE_OK) {
            NSLog(@"创表成功");
        } else {
            NSLog(@"创表失败 -> errorMessage: %s", errorMsg);
        }
        
    } else {
        NSLog(@"打开数据库失败");
    }
  • sqlite3_exec(sqlite3 *, const char *sql, int (*callback)(void *, int, char **, char **), void *, char **errmsg);方法用于执行除了查询语句以外的其他语句
  • 此方法需要传递5个参数,第一个参数是数据库的引用即sqlite3*类型的引用_sqlite,第二个参数是要执行的SQL语句,第三个参数为回调参数,是一个指向函数的指针,此函数将在SQL语句执行完成后执行,如果把callback前的*改成^就是一个代码块,第四个参数为传递给回调函数的指针参数(可写为NULL),第五个参数为报错信息,用以代码调试
  • 这个方法有一个与sqlite3_open一致的枚举类型返回值,因为我们可以访问到报错信息errorMsg,所以可以不用变量result保存来获取创建表的成功与否,如下:
//直接用C语言风格字符串也可
const char* SQLString = "CREATE TABLE IF NOT EXISTS t_Student(ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER NOT NULL, SCORE REAL)";
        
char* errorMsg = NULL;
sqlite3_exec(_sqlite, SQLString, NULL, NULL, &errorMsg);
if (!errorMsg) {
    NSLog(@"创表成功");
} else {
    NSLog(@"创表失败 -> errorMessage: %s 当前文件路径:%s 当前行数:%d", errorMsg, __FILE__, __LINE__);
}

__FILE____LINE__为标准C语言中的预定义宏,前者用以指示本行语句所在源文件的文件,后者用以指示本行语句所在源文件中的位置信息

执行后,创建表成功,打开数据库文件查看:
先在终端输入sqlite3 数据库文件路径,输入.tables查看有哪些数据库表,.quit退出数据库文件在这里插入图片描述可以看到不仅有里面创建的t_Student表Table,还有我之后创建的t_Fellow


电脑一般不会预装相关查看sqlite数据库的软件,这里通过Mac终端查看Sqlite,参考Mac通过终端使用Sqlite3数据库


既然已经成功创建了表,现将SQL语句中的IF NOT EXISTS删去,执行创表失败相关语句:在这里插入图片描述错误信息也会提示该表已经创建!

2. 有关主键

良好的数据库编程规范应该要保证每条记录的唯一性,为此增加了主键约束,每张表必须有一个主键,用来表示记录的唯一性,创表时用PRIMARY KEY声明一个主键

示例:CREATE TABLE t_Student(ID INTEGER PRIMARY KEY, NAME TEXT NOT NULL, AGE INTEGER NOT NULL, SCORE REAL);
只要声明为PRIMARY KEY,就说明是一个主键字段,主键字段默认包含了NOT NULLUNIQUE两个约束

主键的设计原则:

  • 主键应当是对用户没有意义的
  • 永远也不要更新主键
  • 主键不应包含动态变化的数据
  • 主键应当由计算机自动生成

如果想要让主键自动增长(必须是INTEGER类型),应该增加AUTOINCREMENT,示例:CREATE TABLE t_Student (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER NOT NULL, SCORE REAL);

3. 删除表基本格式

  • DROP TABLE 表名;
  • DROP TABLE IF EXISTS 表名; 判断表是否存在,存在则删除

仍使用sqlite3_exec执行:

const char* SQLString = "DROP TABLE t_Fellow";
        
char* errorMsg = NULL;
sqlite3_exec(_sqlite, SQLString, NULL, NULL, &errorMsg);
if (!errorMsg) {
    NSLog(@"删表成功");
} else {
    NSLog(@"删表失败 -> errorMessage: %s 当前文件路径:%s 当前行数:%d", errorMsg, __FILE__, __LINE__);
}

t_Fellow表已删:
请添加图片描述

如果删除不存在的表,错误信息为:
请添加图片描述

数据表操作

增(插入数据INSERT)
  • INSERT INTO 表名 (字段1, 字段2, …) values (字段1的值, 字段2的值, …);

示例:INSERT INTO t_Student (NAME, AGE) VALUES ('Jacky', 20);数据库中的字符串内容应该用单引号``括起来

for (int i = 0; i < 7; ++i) {
    NSString* name = [NSString stringWithFormat: @"Jacky-%d号", i + 1];
    NSString* SQLString = [NSString stringWithFormat: @"INSERT INTO t_Student (NAME, AGE) VALUES ('%@', %d)", name, i + 19];

    char* errorMsg = NULL;
    sqlite3_exec(_sqlite, SQLString.UTF8String, NULL, NULL, &errorMsg);
    if (!errorMsg) {
        NSLog(@"插入数据成功");
    } else {
        NSLog(@"插入数据失败 -> errorMessage: %s", errorMsg);
    }
}

查看打印日志:

请添加图片描述

终端查看数据库表的内容:

请添加图片描述

删(删除数据DELETE)
  • DELETE FROM 表名; 删除表中所有数据
  • DELETE FROM 表名 WHERE 查询条件; 删除指定数据
const char* SQLString = "DELETE FROM t_Student WHERE NAME = 'Jacky-4号'";
        
char* errorMsg = NULL;
sqlite3_exec(_sqlite, SQLString, NULL, NULL, &errorMsg);
if (!errorMsg) {
    NSLog(@"删除数据成功");
} else {
    NSLog(@"删表数据失败 -> errorMessage: %s", errorMsg);
}

请添加图片描述

改(更新数据UPDATE)
  • UPDATE 表名 SET 字段1 = 更新值, 字段2 = 更新值, … ; 改变所有字段为字段1字段2的值
  • UPDATE 表名 SET 字段1 = 更新值, 字段2 = 更新值, … WHERE 查询条件; 改变指定字段数据
const char* SQLString = "UPDATE t_Student SET NAME = 'Jackson-2号' WHERE AGE = 20";

char* errorMsg = NULL;
sqlite3_exec(_sqlite, SQLString, NULL, NULL, &errorMsg);
if (!errorMsg) {
    NSLog(@"更新数据成功");
} else {
    NSLog(@"更新数据失败 -> errorMessage: %s", errorMsg);
}

请添加图片描述

查(查询数据SELECT)
  • SELECT * FROM 表名; 获取所有可用字段
  • SELECT 字段1, 字段2, … FROM 表名; 查询指定字段数据

SELECT查询操作也可以使用sqlite3_exec执行,但通常使用sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);函数,该函数将SQL语句编译成SQLite虚拟机指令,并将编译后的SQLite3语句对象存储在ppStmt指向的指针中,以备执行。如果pzTail不是NULL,则该指针将指向SQL语句中未编译部分的起始位置

  • sqlite3_prepare_v2函数是用来做SQL查询之前的准备工作的,其返回一个枚举值作为准备工作的结果
  • 该函数第一个参数是sqlite3*类型数据库的引用,第二个参数是要执行的SQL语句,第三个参数是SQL语句的长度(如果设置为-1,则代表系统会自动计算SQL语句的长度),第四个参数用于存储查询结果,第五个参数是指向无法使用的部分的指针,一般不会用到,写成NULL即可
//查询age不等于19的数据
const char* SQLString = "SELECT ID, NAME, AGE FROM t_Student WHERE AGE != 19";
        
//用stmt取出查询结果
sqlite3_stmt* stmt = NULL;
        
NSInteger state = sqlite3_prepare_v2(_sqlite, SQLString, -1, &stmt, NULL);
if (state == SQLITE_OK) {
    NSLog(@"查询语句没有问题 读取数据成功");
            
    //每调用一次sqlite3_step函数,stmt就会指向下一条数据
while (sqlite3_step(stmt) == SQLITE_ROW) {  //找到一条记录
        //读取数据
                
        //取出第0列字段的值(int类型)
        int ID = sqlite3_column_int(stmt, 0);
        //取出第1列字段的值(text类型)
        const unsigned char* name = sqlite3_column_text(stmt, 1);
        //取出第2列字段的值(int类型)
        int age = sqlite3_column_int(stmt, 2);
                
        printf("%d %s %d\n", ID, name, age);
    }
} else {
    NSLog(@"查询语句有问题 读取数据失败");
}
  • sqlite3_step(stmt)函数将会执行查询并且将查询到的当前记录存入到stmt
  • 此函数第一次执行会将表中的第一条数据存到stmt中,第二次执行会将表中的第二条数据存到stmt
  • 因此while (sqlite3_step(stmt) == SQLITE_ROW)将会遍历表中的数据,而SQLITE_ROW枚举值判断的是有读取到数据的行的情况

执行情况:

请添加图片描述

补充

条件语句

如果只想给内容更新或者删除某些指定的数据,就需在DML语句上加上条件语句

以下为条件语句常见格式:

  • WHERE 字段 = 某个值; 注意只有一个=
  • WHERE 字段 is 某个值; is相当于=
  • WHERE 字段 != 某个值;
  • *WHERE 字段 is not 某个值; *is not相当于!=
  • WHERE 字段 > 某个值;
  • WHERE 字段1 = 某个值 and 字段2 > 某个值; and相当于C语言中的&&
  • WHERE 字段1 = 某个值 or 字段2 = 某个值; or相当于C语言中的||

示例:将t_Student表中年龄小于等于25或者年龄大于21的数据,NAME都改为JackyUPDATE t_Student SET NAME = 'Jackson' WHERE AGE > 21 and AGE <= 25;

请添加图片描述
为方便演示,我们再改回去

起别名

字段名、表名起别名,基本格式如下:

  • SELECT 字段1 别名, 字段2 别名, … FROM 表名 别名;
  • SELECT 字段1 别名, 字段2 as 别名, … FROM 表名 as 别名;
  • SELECT 别名.字段1, 别名.字段2, … FROM 表名;

示例:
给字段起别名SELECT NAME USER, AGE AS OLD, SCORE POINT FROM t_Student;
请添加图片描述

给表t_Student起个别名s, 利用s来引用表中的字段SELECT s.NAME, s.AGE FROM t_Student s;
请添加图片描述

计算数据的数量

基本格式:

  • SELECT COUNT (字段) FROM 表名;
  • SELECT COUNT ( * ) FROM 表名;

示例:SELECT COUNT (*) FROM t_Student WHERE AGE > 21;

请添加图片描述

排序

根据某个字段的值进行排序搜索,基本格式如下:

  • SELECT * FROM 表名 ORDER BY 字段; 示例:SELECT * FROM t_Student ORDER BY AGE
  • 默认是按照升序排序(从小到大),也可以写为SELECT * FROM t_Student ORDER BY AGE ASC;也可以变为降序(从大到小)SELECT * FROM t_Student ORDER BY AGE DESC
    在这里插入图片描述
  • 用多个字段进行排序,先根据年龄排序(升序),年龄相等就根据ID排序(降序)SELECT * FROM t_Student ORDER BY AGE ASC, ID DESC;
    请添加图片描述
LIMIT

使用LIMIT可以精确地控制查询结果的数量,基本格式如下:

  • SELECT * FROM 表名 LIMIT 数值1, 数值2;

示例:比如现在有6条数据,SELECT * FROM t_Student LIMIT 2, 4;就表示跳过最前面2条数据,然后取4条数据

请添加图片描述

LIMIT经常用来做分页查询,比如每页固定显示7条数据,那么应该这样取数据:

第1页:LIMIT 0, 7 第2页:LIMIT 7, 7 第3页:LIMIT 14, 7 … 第n页:LIMIT (n - 1)*7, 7


结束语

本文总结了在iOS开发中用OC语言如何去使用SQLite数据库,介绍了SQLite相关函数,以及SQLite的基本语句

iOS中原生的SQLite API在进行数据存储的时候,需要使用C语言中的函数,操作比较麻烦,于是就出现了一系列将SQLite封装的库:CoreData(Apple官方)、FMDB(第三方),后续将会对这两个基于SQLite编写的库进行学习!🫡

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT打包部署程序时候程序无法启动

当在Qt打包部署程序后&#xff08;用windeployqt打包好qt依赖库后&#xff09;&#xff0c;在本机可以运行&#xff0c;在其他电脑上显示程序无法启动&#xff0c;如下图所示。可能是在复制dll时候将System32中的dll复制到了应用程序中&#xff0c;应该改用SysWOW64中的dll&…

通过kubeadm方式安装k8s

虚拟机最少是 2 core&#xff0c;master内存最小3G&#xff0c;node内存最小2G. 要求的Docker版本是18.03&#xff0c;如果不是安装的docker ce&#xff0c;版本是过旧的&#xff0c;可以选择删除后重新安装&#xff1b; 也可以重新创建一个虚拟机执行以下命令。 简单方法&am…

LeetCode Hot100 17.电话号码的字母组合

题目&#xff1a; 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 方法&#xff1a;灵神 子集型回溯 class Solution {p…

npm私有源构建项目下载依赖报错

Jenkins构建项目报错&#xff0c;依赖找不到 Error: Couldnt find any versions for "babel/helper-module-imports" that matches "^7.22.15"at MessageError.ExtendableBuiltin (/data1/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/…

屏幕分辨率修改工具SwitchResX mac功能特点

SwitchResX mac是可用于修改和管理显示器的分辨率和刷新率。 SwitchResX mac功能和特点 支持多种分辨率和刷新率&#xff1a;SwitchResX可以添加和管理多种分辨率和刷新率&#xff0c;包括自定义分辨率和刷新率。 自动切换分辨率&#xff1a;SwitchResX可以根据应用程序和窗口…

如何提高大模型在超长上下文的表现?Claude实验表明加一句prompt立即提升效果~

本文来自DataLearnerAI官方网站&#xff1a;如何提高大模型在超长上下文的表现&#xff1f;Claude实验表明加一句prompt立即提升效果~ | 数据学习者官方网站(Datalearner)https://www.datalearner.com/blog/1051701947131881 Claude 2.1版本的模型上下文长度最高拓展到200K&am…

时间序列预测 — VMD-LSTM实现单变量多步光伏预测(Tensorflow):单变量转为多变量

目录 1 数据处理 1.1 导入库文件 1.2 导入数据集 1.3 缺失值分析 2 VMD经验模态分解 3 构造训练数据 4 LSTM模型训练 5 预测 1 数据处理 1.1 导入库文件 import time import datetime import pandas as pd import numpy as np import matplotlib.pyplot as plt f…

windows系统和虚拟机上ubuntu系统通过虚拟串口进行通信

本文的目的是实现windows系统和虚拟机上安装的ubuntu通过串口进行通信。为了直观观测串口收发数据的内容&#xff0c;需要在windows系统和ubuntu系统使用串口助手来进行监听。windows系统端用的监听工具是串口助手SSCOM&#xff0c;ubuntu系统端使用的串口助手是CuteCom。 ubu…

电子眼+无人机构建平安城市视频防控监控方案

电子眼&#xff08;也称为监控摄像机&#xff09;可以通过安装在城市的不同角落&#xff0c;实时监控城市的各个地方。它们可以用于监测交通违法行为、监控公共场所的安全以及实时监测特定区域的活动情况。通过电子眼的应用&#xff0c;可以帮助警方及时发现并响应各类安全事件…

『Redis』在Docker中快速部署Redis并进行数据持久化挂载

&#x1f4e3;读完这篇文章里你能收获到 在Docke中快速部署Redis如何将Redis的数据进行持久化 文章目录 一、拉取镜像二、创建挂载目录1 宿主机与容器挂载映射2 挂载命令执行 三、创建容器—运行Redis四、查看运行情况 一、拉取镜像 版本号根据需要自己选择&#xff0c;这里以…

PPT插件-好用的插件-图形缩放-大珩助手

图形缩放 包括适合屏幕、适合宽度、适合高度、水平翻转、垂直翻转、指定角度&#xff0c;可同时对多个形状进行操作 适合屏幕 一键设置图像、文本、形状的长宽尺寸与当前幻灯片一致 适合宽度 一键设置图像、文本、形状的宽度尺寸与当前幻灯片一致 适合高度 一键设置图像…

鸿蒙方舟开发框架ArkUI简介

语雀知识库地址&#xff1a;语雀HarmonyOS知识库 飞书知识库地址&#xff1a;飞书HarmonyOS知识库 嗨&#xff0c;各位别来无恙呐&#xff0c;我是小白 众所周知&#xff0c;华为在今年推出了 HarmonyOS 4.0 版本&#xff0c;而在此之前的版本中&#xff0c;HarmonyOS 应用的 …

第17章:随堂复习与企业真题(反射机制)

第17章&#xff1a;随堂复习与企业真题&#xff08;反射机制&#xff09; 一、随堂复习 1. 反射的概述&#xff08;熟悉&#xff09; Java给我们提供了一套API&#xff0c;使用这套API我们可以在运行时动态的获取指定对象所属的类&#xff0c;创建运行时类的对象&#xff0c;…

web漏洞原理与防御策略,web漏洞怎么挖掘

目录 Web安全的重要性 ​编辑常见的Web漏洞类型及其原理&#xff1a; 1、跨站脚本攻击&#xff08;XSS&#xff09;: 2、SQL注入: 3、跨站请求伪造&#xff08;CSRF&#xff09;: 4、远程文件包含&#xff08;RFI&#xff09;和本地文件包含&#xff08;LFI&#xff09;:…

[笔记]ARMv7/ARMv8 交叉编译器下载

开发 Cortex-A7、Cortex-A72 或其他 ARM 架构 profile 芯片时&#xff0c;经常需要下载对应架构的交叉编译器&#xff0c;所以写这篇笔记&#xff0c;用于记录一下交叉编译器下载流程&#xff0c;免得搞忘。 编译环境&#xff1a;ubuntu 虚拟机 下载地址 我们可以从 ARM 官网…

使用MfgTool烧写前需准备的文件

一. 简介 本文我们就来学习&#xff0c;如何将我们编译的 uboot&#xff0c;zImage&#xff08;内核镜像&#xff09;&#xff0c;xxx.dtb设备树文件&#xff0c;还有制作的根文件系统&#xff0c;这四个文件烧写到开发板中&#xff0c;最后 开发板能正常启动。 本文这里使用…

数据可视化软件的兴起:背后的驱动力

在当今信息时代&#xff0c;数据变得比以往任何时候都更为重要。数据可视化软件的广泛应用成为了一种趋势。那么&#xff0c;为什么越来越多的人选择使用数据可视化软件呢&#xff1f;今天我就以自己的工作经验为基础&#xff0c;进行简单的分析。 数据可视化软件能将枯燥的数…

分布式系统CAP理论与BASE理论

CAP理论 Cap理论又被称作布鲁尔定理&#xff08;Brewers theorem&#xff09;&#xff0c;它指出对于一个分布式系统来说&#xff0c;不可能同时满足如下三点&#xff1a; 一致性&#xff08;Consistency&#xff09; 可用性&#xff08;Availability&#xff09; 分区容错性…

STM32单片机项目实例:基于TouchGFX的智能手表设计(3)嵌入式程序任务调度的设计

STM32单片机项目实例&#xff1a;基于TouchGFX的智能手表设计&#xff08;3&#xff09;嵌入式程序任务调度的设计 目录 一、嵌入式程序设计 1.1轮询 1.2 前后台&#xff08;中断轮询&#xff09; 1.3 事件驱动与消息 1.3.1 事件驱动的概念 1.4 定时器触发事件驱动型的任…

软件设计师——面向对象技术(一)

&#x1f4d1;前言 本文主要是【面向对象技术】——软件设计师—面向对象技术的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#…