C++ は MySQL データベース接続プールを実装します

C++ は MySQL データベース接続プールを実装します

関連するテクノロジー

MySQL データベース プログラミング、シングルトン モード、STL コンテナ、C++11 マルチスレッド (スレッド相互排他、スレッド相互排他、スレッド同期通信および unique_lock)、スマート ポインターshared_ptr、ラムダ式、プロデューサー/コンシューマー スレッド モデル。

プロジェクトの背景

MySQL データベースのアクセス ボトルネック (C/S 設計 (クライアント - サーバー) に基づく) を改善するには、サーバー側でよく使用されるデータのバッファー サーバー キャッシュを増やすことに加えて (radis など、実際には高速インデックス作成のために頻繁にアクセスされるキーと値のペアを確立するためです)、接続プールを増やすこともできます。MySQL Server のアクセス効率を向上させるために、高同時実行環境では、大量の TCP 3 方向ハンドシェイク、MySQl サーバー接続検証、MySQL サーバーによるリソースをリサイクルするための接続の終了、および TCP 4 方向ウェーブによってパフォーマンス時間が消費されることも明らかです。接続プールを増やす目的は、この部分のパフォーマンス損失を軽減することです (接続を再確立せずに、使用可能な接続をデータ プールから直接取得します)(クライアントとデータベース サーバー間の通信は、一般に、TCP 接続の確立、MySQL 接続とコマンド通信の検証、TCP 4 方向ハンドシェイク、TCP 接続と切断の詳細については、TCP 3 方向ハンドシェイクと 4 方向ハンドシェイクのプロセスと原理を完全に理解するために、この記事で説明されています) に分類されます

現在、市場で主流の接続プールには、druid、c3p0、および apache dbcp 接続プールがあり、短期間で大量のデータベースの追加、削除、変更、クエリのパフォーマンスを向上させることができることは明らかですが、これらはすべて Java ベースで実装されています。

コネクションプールの機能

接続プールには通常、データベース接続で使用される IP アドレス、ポート ポート、ユーザー名とパスワード、および初期接続ボリューム、最大接続ボリューム、最大アイドル時間、接続タイムアウト時間などのその他のパフォーマンス パラメーターが含まれます。このプロジェクトは主に C++ によって実装された接続プールに基づいており、主に上記のすべての接続プールでサポートされる一般的な機能を実装します。

初期接続サイズ (initSize) : 接続プールが MySQL Server との initSize 数の接続を事前に作成することを意味します。アプリケーションが MySQL アクセスを開始するとき、MySQL Server との新しい接続を作成する必要はなく、接続プールから利用可能な接続を直接取得できます。使用が完了すると、現在の接続は解放されませんが、現在の接続は接続プールに返されます。

最大接続サイズ (maxSize) : MySQL Server への同時アクセス数が増加すると、初期接続サイズでは十分ではなくなります。このとき、新しいリクエストの数に応じてアプリケーションが使用する接続がさらに作成されます。ただし、新しく作成される接続数の上限は maxSize であり、各接続はソケット リソースを占有するため、無制限に接続を作成することはできません。通常、接続プールとサーバー プログラムは 1 つのホストに配置されます。接続プールがソケット リソースを占有しすぎると、サーバーはあまりにも多くのクライアントを受信できなくなりますリクエスト。これらの接続が使用されると、メンテナンスのために接続プールに戻されます。

最大アイドル時間 (maxIdleTime) : MySQL にアクセスする同時リクエストが増えると、接続プール内の接続数が動的に増加します。上限は maxSize です。これらの接続が使い果たされると、接続プールに戻されます。これらの新しく追加された接続が指定された maxIdleTime 内に再度使用されなかった場合、これらの新しく追加された接続リソースはリサイクルされ、初期接続量の initSize 接続を維持するだけで済みます。

接続タイムアウト (connectionTimeOut) : 同時 MySQL リクエストの量が多すぎ、接続プール内の接続数が maxSize に達し、現時点で使用可能なアイドル接続がない場合、アプリケーションは現時点では接続プールから接続を取得できません。ブロックによる接続の取得にかかる時間が connectionTimeout 時間を超えると、接続の取得に失敗し、データベースにアクセスできなくなります。

MySQL サーバーパラメータの概要

機能実現設計

ConnectionPool.cpp和ConnectionPool.h:连接池代码实现
Connection.cpp和Connection.h:数据库操作代码、增删改查代码实现
连接池主要包含了以下功能点:
1.连接池只需要一个实例,所以ConnectionPool以单例模式进行设计
2.从ConnectionPool中可以获取和MySQL的连接Connection
3.空闲连接Connection全部维护在一个线程安全的Connection队列中,使用线程互斥锁保证队列的线程安全
4.如果Connection队列为空,还需要再获取连接,此时需要动态创建连接,上限数量是maxSize
5.队列中空闲连接时间超过maxIdleTime的就要被释放掉,只保留初始的initSize个连接就可以了,这个功能点肯定需要放在独立的线程中去做
6.如果Connection队列为空,而此时连接的数量已达上限maxSize,那么等待connectionTimeout时间如果还获取不到空闲的连接,那么获取连接失败,此处从Connection队列获取空闲连接,可以使用带超时时间的mutex互斥锁来实现连接超时时间
7.用户获取的连接用shared_ptr智能指针来管理,用lambda表达式定制连接释放的功能(不真正释放连接,而是把连接归还到连接池中)
8.连接的生产和连接的消费采用生产者-消费者线程模型来设计,使用了线程间的同步通信机制条件变量和互斥锁

実装コードリファレンス

接続.h

#pragma once
#include <mysql.h>
#include <string>
#include<ctime>
using namespace std;

// 数据库操作类
class Connection
{
    
    
public:
	// 初始化数据库连接
	Connection();
	// 释放数据库连接资源
	~Connection();
	// 连接数据库
	bool connect(string ip, unsigned short port, string user, string password,string dbname);
	// 更新操作 insert、delete、update
	bool update(string sql);
	// 查询操作 select
	MYSQL_RES* query(string sql);

	//刷新一下连接的起始的空闲时间
	void refreshAliveTime();

	//返回连接的存活时间
	clock_t getAliveTime();
private:
	MYSQL* _conn; // 表示和MySQL Server的一条连接
	clock_t _alivetime;//记录进入空闲状态后的起始时间
};

接続.cpp

#include"connection.h"
#include"public.h"

// 初始化数据库连接
Connection::Connection()
{
    
    
	_conn = mysql_init(nullptr);
}
// 释放数据库连接资源
Connection::~Connection()
{
    
    
	if (_conn != nullptr)
		mysql_close(_conn);
}
// 连接数据库
bool Connection::connect(string ip, unsigned short port, string user, string password,
	string dbname)
{
    
    
	MYSQL* p = mysql_real_connect(_conn, ip.c_str(), user.c_str(),
		password.c_str(), dbname.c_str(), port, nullptr, 0);
	return p != nullptr;
}
// 更新操作 insert、delete、update
bool Connection::update(string sql)
{
    
    
	if (mysql_query(_conn, sql.c_str()))
	{
    
    
		LOG("更新失败:" + sql);
		return false;
	}
	return true;
}
// 查询操作 select
MYSQL_RES* Connection::query(string sql)
{
    
    
	if (mysql_query(_conn, sql.c_str()))
	{
    
    
		LOG("查询失败:" + sql);
		return nullptr;
	}
	return mysql_use_result(_conn);
}
//刷新一下连接的起始的空闲时间
void  Connection::refreshAliveTime()
{
    
    
	_alivetime = clock_t();
}

//返回连接的存活时间
clock_t Connection::getAliveTime()
{
    
    
	return clock() - _alivetime;
}

commConnectionPool.h

#pragma once
#include<string>
#include<queue>
#include<mutex>
#include<atomic>
#include<thread> 
#include<memory>
#include<functional>
#include<condition_variable>
#include"connection.h"


using namespace std;

class ConnectionPool {
    
    
public:
	//获取连接池对象实例,静态成员方法,不依赖于对象调用
	static ConnectionPool* getConnectionPool();
	//从线程池中获取线程
	shared_ptr<Connection> getConnection();
private:
	// 单例,构造函数私有化
	ConnectionPool();

	//加载配置文件
	bool loadConfigFile();

	//用来线程来产生连接
	void produceConnectionTask();
	//用来扫描连接的进程函数,防止很线程池中线程数量大于initSize而不归还资源
	void scannerConnectionTask();

	string _ip; //mysql的ip地址
	unsigned short _port; //mysql的端口号
	string _username; //mysql的连接用户名
	string _password; //mysql连接用户的密码
	string _dbname;
	int _initSize; //初始化连接池的数量
	int _maxSize; //最大化连接池的数量
	int _maxIdleTime; //连接池最大空闲时间
	int _connectionTimeout;//连接池最大获取时间

	queue<Connection*> _connectionQue; //连接池存储数据库连接队列,必须是多线程安全的
	mutex _queueMutex;//维护连接池队列线程安全的互斥锁
	atomic_int _connectionCnt;//记录所创建的connection数量

	condition_variable cv;//设置条件变量,用于连接生产线程和连接消费线程的实现
};

commConnectionPool.cpp

#include"commConnectionPool.h"
#include"public.h"

//线程安全的懒汉单例模式接口
ConnectionPool* ConnectionPool::getConnectionPool() {
    
    
	//静态局部变量由编译器自动lock和unlock
	static ConnectionPool pool;
	return &pool;
}

//从线程池中获取线程
shared_ptr<Connection> ConnectionPool::getConnection() {
    
    
	unique_lock<mutex> lock(_queueMutex);
	while (_connectionQue.empty()) {
    
    
		if (cv_status::timeout == cv.wait_for(lock, chrono::milliseconds(_connectionTimeout)))
		{
    
    
			if (_connectionQue.empty()) {
    
    
				LOG("获取空闲连接超时,获取失败!");
				return nullptr;
			}
		}
	}
	/*
	shared_ptr智能指针析构时,会把connection资源直接给delete掉,
	相当于调用了Connection的析构函数,connect就会被关闭掉了,
	这里需要自定义shared_ptr的释放资源方式,把connection归还到队列中
	*/
	shared_ptr<Connection> sp(_connectionQue.front(),
		[&](Connection* pcon) {
    
    
			//这里是在服务器应用线程中调用的,所以一定要考虑线程安全
			unique_lock<mutex> lock(_queueMutex);
			//智能指针析构的时候会将指针重新输入到队列中
			_connectionQue.push(pcon);
			pcon->refreshAliveTime();
		});
	_connectionQue.pop();
	cv.notify_all();//消费完连接之后,通知生产者线程检查一下,如果生产队列为空后,就通知线程赶紧生产
	return sp;
}

ConnectionPool::ConnectionPool() {
    
    
	if (!loadConfigFile()) {
    
    
		return;
	}
	for (int i = 0; i < _initSize; i++) {
    
    
		Connection* p = new Connection();
		p->connect(_ip, _port, _username, _password, _dbname);
		p->refreshAliveTime();
		_connectionQue.push(p);
		_connectionCnt++;
	}
	//启动一个新的线程,作为一个连接的生产者
	thread produce(std::bind(& ConnectionPool::produceConnectionTask, this));
	//分离线程(分离线程),主线程结束后该线程自动结束
	produce.detach();
	//启动一个定时线程,扫描超过maxIdleTime时间的空闲线程
	thread scanner(std::bind(&ConnectionPool::scannerConnectionTask, this));
	scanner.detach();
}

//用来扫描连接的进程函数,防止很线程池中线程数量大于initSize而不归还资源
void ConnectionPool::scannerConnectionTask()
{
    
    
	while (true) 
	{
    
    
		//通过sleep模拟定时效果
		this_thread::sleep_for(chrono::seconds(_maxIdleTime));

		//扫秒整个队列,释放多余的连接
		//队列要用互斥锁,防止多线程访问
		unique_lock<mutex> lock(_queueMutex);
		while (_connectionCnt > _initSize)
		{
    
    
			Connection* p = _connectionQue.front();
			//如果队列头都没有超时的话,那么后面的connection肯定不会超时
			//每次回收返回队列都是插入在队尾的
			if (p->getAliveTime() >= _maxIdleTime)
			{
    
    
				_connectionQue.pop();
				_connectionCnt--;
				delete p;
			}
			else {
    
    
				break;
			}
		}
	}
}

//用来线程来产生连接
void ConnectionPool::produceConnectionTask() {
    
    
	while (true) {
    
    
		//所有的线程在创建时都被_queueMutex锁住了,共用一把锁,函数作用域结束后默认解锁
		//unique_lock无默认参数时会自动加锁
		unique_lock<mutex> lock(_queueMutex);
		while (!_connectionQue.empty()) {
    
    
			//condition_variable cv 必须和unique_lock一起使用
			cv.wait(lock);//队列不为空,此处生产者线程进入等待状态
		}
		if (_connectionCnt < _maxSize) {
    
    
			Connection* p = new Connection();
			p->connect(_ip, _port, _username, _password, _dbname);
			p->refreshAliveTime();
			_connectionQue.push(p);
			_connectionCnt++;
		}
		cv.notify_all();//通知消费者线程可以进行连接了
	}
}


bool ConnectionPool::loadConfigFile() {
    
    
	//读取配置文件
	FILE* pf = fopen("./mysql.ini", "r");
	if (pf == nullptr) {
    
    
		LOG("mysql.ini file is not exist!");
		return false;
	}
	//feof()函数判断文件字节流是否到了末尾
	while (!feof(pf)) {
    
    
		char line[1024] = {
    
     0 };
		//fgets获取文件一行,并指定行的最大值(包含最后的空字符)
		//如果成功,该函数返回相同的 str 参数。
		//如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。
		//如果发生错误,返回一个空指针。
		fgets(line, 1024, pf);
		string str = line;
		int idx=str.find('=', 0);
		if (idx == -1) {
    
    
			//无效的配置
			continue;
		}
		int endx = str.find('\n', idx);
		string key = str.substr(0, idx);
		string value = str.substr(idx + 1, endx - idx - 1);

		if (key == "ip") {
    
    
			_ip = value;
		}
		else if (key == "port") {
    
    
			_port = atoi(value.c_str());
		}
		else if (key == "username") {
    
    
			_username = value;
		}
		else if (key == "password") {
    
    
			_password = value;
		}
		else if (key == "dbname") {
    
    
			_dbname = value;
		}
		else if (key == "initSize") {
    
    
			_initSize = atoi(value.c_str());
		}
		else if (key == "maxSize") {
    
    
			_maxSize = atoi(value.c_str());
		}
		else if (key == "maxIdleTime") {
    
    
			_maxIdleTime = atoi(value.c_str());
		}
		else if (key == "connectionTimeout") {
    
    
			_connectionTimeout = atoi(value.c_str());
		}
	}
	return true;
}

public.h

#pragma once
#include<iostream>

#define LOG(str) std::cout<<__FILE__<<" : "<<__LINE__<<" : "<<__TIMESTAMP__<<" : "<<str<<endl;

main.cpp

#include<iostream>
#include<string>
#include<ctime>
#include<thread>
#include"connection.h"
#include"commConnectionPool.h"

using namespace std;

int main(int argc, char argv[]) {
    
    

	clock_t begin = clock();

	int number = 5000;
	bool is_use_connection_pool = true;

	/*
	if (!is_use_connection_pool)
	{
		for (int i = 0; i < number; i++)
		{
			Connection conn;
			conn.connect("127.0.0.1", 3306, "root", "xiehou", "chat");
			char sql[1024] = { 0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			conn.update(sql);
		}
	}
	else 
	{
		//获取静态唯一的连接池,也是静态变量和静态方法的好处
		ConnectionPool* pool = ConnectionPool::getConnectionPool();

		for (int i = 0; i < number; i++)
		{
			shared_ptr<Connection> sp = pool->getConnection();
			char sql[1024] = { 0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			sp->update(sql);
		}
	}
	*/

	Connection conn;
	conn.connect("127.0.0.1", 3306, "root", "xiehou", "chat");
	//多线程-未使用连接池
	thread t1([]() {
    
    
		for (int i = 0; i < 250; i++)
		{
    
    
			Connection conn;
			conn.connect("127.0.0.1", 3306, "root", "xiehou", "chat");
			char sql[1024] = {
    
     0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			conn.update(sql);
		}
		});
	thread t2([]() {
    
    
		for (int i = 0; i < 250; i++)
		{
    
    
			Connection conn;
			conn.connect("127.0.0.1", 3306, "root", "xiehou", "chat");
			char sql[1024] = {
    
     0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			conn.update(sql);
		}
		});
	thread t3([]() {
    
    
		for (int i = 0; i < 250; i++)
		{
    
    
			Connection conn;
			conn.connect("127.0.0.1", 3306, "root", "xiehou", "chat");
			char sql[1024] = {
    
     0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			conn.update(sql);
		}
		});
	thread t4([]() {
    
    
		for (int i = 0; i < 250; i++)
		{
    
    
			Connection conn;
			conn.connect("127.0.0.1", 3306, "root", "xiehou", "chat");
			char sql[1024] = {
    
     0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			conn.update(sql);
		}
		});

	//多线程-线程池
	/*
	thread t1([]() {
		ConnectionPool* pool = ConnectionPool::getConnectionPool();
		for (int i = 0; i < 1250; i++)
		{
			shared_ptr<Connection> sp = pool->getConnection();
			char sql[1024] = { 0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			sp->update(sql);
		}
	});
	thread t2([]() {
		ConnectionPool* pool = ConnectionPool::getConnectionPool();
		for (int i = 0; i < 1250; i++)
		{
			shared_ptr<Connection> sp = pool->getConnection();
			char sql[1024] = { 0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			sp->update(sql);
		}
	});
	thread t3([]() {
		ConnectionPool* pool = ConnectionPool::getConnectionPool();
		for (int i = 0; i < 1250; i++)
		{
			shared_ptr<Connection> sp = pool->getConnection();
			char sql[1024] = { 0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			sp->update(sql);
		}
	});
	thread t4([]() {
		ConnectionPool* pool = ConnectionPool::getConnectionPool();
		for (int i = 0; i < 1250; i++)
		{
			shared_ptr<Connection> sp = pool->getConnection();
			char sql[1024] = { 0 };
			// 项目属性 -> C/C++ -> 预处理器 -> 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE,使用分号隔开
			sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')", "zhangsan", 20, "male");
			sp->update(sql);
		}
	});
	*/
	//join表示要等子线程结束后,后面的主线程才能继续执行,也就是end计时要等t1~t4结束后才能执行,detach则不用等待
	t1.join();
	t2.join();
	t3.join();
	t4.join();

	clock_t end = clock();
	std::cout << (end - begin) << "ms" << endl;

	return 0;
}

mysql.ini

# 用于存储mysql的基本连接信息
ip=127.0.0.1
port=3306
username=root
password=xiehou
dbname=chat
initSize=10
maxSize=1024
# 单位是秒
maxIdleTime=60
# 单位是毫秒
connectionTimeout=100

圧力試験

データ量 未使用の接続プールの消費時間 (ミリ秒) 接続プールの使用にかかった時間 (ミリ秒)
1000 シングルスレッド: 10548 3 スレッド: 3472 1 スレッド: 4577 3 スレッド: 2858
5000 単糸: 53145 三糸: 17485 シングルスレッド: 22877 スリースレッド: 14865

C++ マルチプロセス/マルチスレッド

詳細については、「C++ マルチスレッドの詳細な説明 (ネットワーク全体で最も完全な説明)」を参照してください。

ヘッダー ファイルthread、、、、、が関係しますmutexatomiccondition_variablefuture

MySQLデータベースの共通コマンド

MySQL データベース プログラムは、;C/C++ プログラムと同様に、 で終わる必要があります。また、MySQL プログラムは大文字と小文字を区別しません。つまり、大文字と小文字は区別されません。

データベース関連

データベース作成コマンド

create database name; //管理员用户
mysqladmin -u root -p create name  //普通用户,需要使用管理员权限

データベースが存在する場合は作成に失敗し、以下のような情報が取得されますERROR 1007 (HY000): Can't create database 'name'; database exists
推奨される作成コマンドは次のとおりです。CREATE DATABASE IF NOT EXISTS name DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

データベース削除コマンド

drop database name

データベースを削除する場合、削除するかどうかを決定するプロンプト メッセージが表示されます。

データベースを選択

use name

データベース内のすべてのテーブルを表示します

show tables;

データベーステーブル関連

データの種類

MySQL はさまざまな型をサポートしていますが、それらは数値型、日付/時刻型、および文字列 (文字) 型の 3 つのカテゴリに大別できます。

値の型

MySQL は、すべての標準 SQL 数値データ型をサポートします。

これらの型には、厳密な数値データ型 ( INTEGERSMALLINTDECIMALおよびNUMERIC) と近似数値データ型 ( FLOAT、 、REALおよびDOUBLE PRECISION) が含まれます。

キーワードはINTINTEGER同義語で、キーワードはの同義語DECです。DECIMAL

BITデータ型はビット フィールド値を保持し、MyISAMMEMORYInnoDBおよびBDBテーブルをサポートします。

SQL 標準の拡張として、MySQL は整数型 および もサポートTINYINTMEDIUMINTますBIGINT

日付と時刻のタイプ

時間の値を表す日付と時刻の型DATETIME、、、、、およびですDATETIMESTAMPTIMEYEAR

各 time タイプには、有効な値の範囲と、MySQL が表現できない無効な値を指定するときに使用される「ゼロ」値があります。

文字列型

文字列CHAR、、、、、、、および指しVARCHARますBINARYVARBINARYBLOBTEXTENUMSET

データテーブルの共通コマンド

データテーブルを作成する

CREATE TABLE table_name (column_name column_type);

次の例では、データベースにデータ テーブル runoob_tbl を作成します。テーブル名も列名も引用符で囲む必要がないことに注意してください。

CREATE TABLE IF NOT EXISTS `runoob_tbl`(
   `runoob_id` INT UNSIGNED AUTO_INCREMENT,
   `runoob_title` VARCHAR(100) NOT NULL,
   `runoob_author` VARCHAR(40) NOT NULL,
   `submission_date` DATE,
   `sex` ENUM('男','女')   DEFAULT NULL,
   PRIMARY KEY ( `runoob_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

分析例:

フィールドを NULL にしたくない場合は、フィールドの属性を NOT NULL に設定できます。データベースの操作時にフィールドに入力されたデータが NULL の場合、エラーが報告されます。
AUTO_INCREMENT は、列を自動インクリメント属性として定義します。これは通常主キーに使用され、値は自動的に 1 ずつ増加します。
PRIMARY KEY キーワードは、列を主キーとして定義するために使用されます。カンマで区切られた複数の列を使用して主キーを定義できます。
ENGINE はストレージ エンジンを設定し、CHARSET はエンコーディングを設定します。

mysql> create table user(
    -> id INT UNSIGNED AUTO_INCREMENT,
    -> name VARCHAR(50) NOT NULL,
    -> age INT NOT NULL,
    -> sex ENUM('male','female') NOT NULL,
    -> PRIMARY KEY (id)
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;

データテーブルの削除

DROP TABLE table_name ;

データを挿入する

INSERT INTO table_name ( field1, field2,...fieldN )
                       VALUES
                       ( value1, value2,...valueN );

データが文字型の場合は、 「value」のように一重引用符または二重引用符を使用する必要があります。

クエリデータ

SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M]
  • クエリ文には1つ以上のテーブルを使用でき、各テーブルをカンマ(,)で区切ってWHERE文でクエリ条件を設定します。
  • SELECT コマンドは 1 つ以上のレコードを読み取ることができます。
  • アスタリスク (*) を使用して他のフィールドを置き換えることができ、SELECT ステートメントはテーブル内のすべてのフィールド データを返します。
  • WHERE ステートメントを使用すると、任意の条件を含めることができます。
  • LIMIT 属性を使用して、返されるレコードの数を設定できます。
  • OFFSET を使用すると、SELECT ステートメントでクエリを開始するデータ オフセットを指定できます。デフォルトでは、オフセットは 0 です。

where ステートメント

以下は、WHERE 句を使用してデータ テーブルからデータを読み取る SQL SELECT ステートメントの一般的な構文です。

SELECT field1, field2,...fieldN FROM table_name1, table_name2...
[WHERE condition1 [AND [OR]] condition2.....
  • クエリ ステートメントでは、1 つ以上のテーブルを使用し、コンマを使用してテーブルを区切ったり、WHERE ステートメントを使用してクエリ条件を設定したりできます。
  • WHERE句には任意の条件を指定できます。
  • AND または OR を使用して 1 つ以上の条件を指定できます。
  • WHERE 句は、SQL DELETE または UPDATE コマンドでも使用できます。
  • WHERE 句はプログラミング言語の if 条件に似ており、MySQL テーブルのフィールド値に従って指定されたデータを読み取ります。

フォームのステータスを確認する

desc table_name;

サンプルは次のとおりです。

mysql> desc user;
+-------+-----------------------+------+-----+---------+----------------+
| Field | Type                  | Null | Key | Default | Extra          |
+-------+-----------------------+------+-----+---------+----------------+
| id    | int unsigned          | NO   | PRI | NULL    | auto_increment |
| name  | varchar(50)           | NO   |     | NULL    |                |
| age   | int                   | NO   |     | NULL    |                |
| sex   | enum('male','female') | NO   |     | NULL    |                |
+-------+-----------------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)

よくある問題

error C4996: ‘sprintf’: This function or variable may be unsafe. Consider using sprintf_s instead. 、VS で設定、プロジェクト プロパティ -> C/C++ -> プリプロセッサ -> プリプロセッサ定義に加えて、_CRT_SECURE_NO_DEPRECATE および _SCL_SECURE_NO_DEPRECATE をセミコロンで区切ります。

おすすめ

転載: blog.csdn.net/qq_45041871/article/details/131837950