C++ implémente le pool de connexion à la base de données MySQL

C++ implémente le pool de connexion à la base de données MySQL

Technologie impliquée

Programmation de base de données MySQL, mode singleton, conteneur STL, multithreading C++11 (exclusion mutuelle des threads, exclusion mutuelle des threads, communication de synchronisation des threads et unique_lock), pointeur intelligent shared_ptr, expression lambda, modèle de thread producteur-consommateur.

Contexte du projet

Afin d'améliorer le goulot d'étranglement d'accès de la base de données MySQL (basé sur la conception C/S (client-serveur)), en plus d'augmenter le cache du serveur tampon des données couramment utilisées côté serveur (comme radis, en fait, il s'agit d'établir une paire clé-valeur fréquemment consultée pour une indexation rapide), vous pouvez également augmenter le pool de connexion. Pour améliorer l'efficacité d'accès de MySQL Server, dans un environnement à forte concurrence, le temps de performance consommé par un grand nombre de poignées de main TCP à trois voies, la vérification de la connexion MySQl Server, la fermeture de connexions MySQL Server pour recycler les ressources et la vague TCP à quatre voies est également évident. Le but de l'augmentation du pool de connexions est de réduire cette partie de la perte de performances (obtenir les connexions disponibles directement à partir du pool de données sans rétablir les connexions) . (La communication entre le client et le serveur de base de données est généralement divisée en : établissement de la connexion TCP, vérification de la connexion MySQL et de la communication de commande, prise de contact TCP à quatre voies, plus de connexion et de déconnexion TCP peuvent être trouvées dans cet article pour bien comprendre le processus et le principe de la prise de contact TCP à trois voies et de la prise de contact à quatre voies ) .

À l'heure actuelle, les pools de connexion courants sur le marché incluent les pools de connexion druid, c3p0 et apache dbcp.Il est évident qu'ils peuvent améliorer les performances d'un grand nombre d'opérations d'ajout, de suppression, de modification et de requête de base de données en peu de temps, mais ils sont tous implémentés sur la base de Java.

La fonction du pool de connexion

Le pool de connexion inclut généralement l'adresse IP, le port, le nom d'utilisateur et le mot de passe utilisés par la connexion à la base de données, ainsi que d'autres paramètres de performances, tels que le volume de connexion initial, le volume de connexion maximal, le temps d'inactivité maximal et le délai d'expiration de la connexion. Ce projet est principalement basé sur le pool de connexion implémenté par C++ et implémente principalement les fonctions générales prises en charge par tous les pools de connexion ci-dessus.

Quantité de connexion initiale (initSize) : indique que le pool de connexions créera à l'avance des connexions de connexion initSize avec MySQL Server. Lorsque l'application initie l'accès à MySQL, elle n'a pas besoin de créer une nouvelle connexion avec MySQL Server et peut obtenir directement une connexion disponible à partir du pool de connexions. Une fois l'utilisation terminée, la connexion actuelle n'est pas libérée, mais la connexion actuelle est renvoyée au pool de connexions.

Taille de connexion maximale (maxSize) : lorsque le nombre d'accès simultanés au serveur MySQL augmente, la taille de connexion initiale n'est pas suffisante. À ce moment, davantage de connexions seront créées pour l'application à utiliser en fonction du nombre de nouvelles requêtes. Cependant, la limite supérieure du nombre de nouvelles connexions créées est maxSize, et les connexions ne peuvent pas être créées sans limite, car chaque connexion occupera une ressource de socket. Généralement, le pool de connexions et le programme serveur sont déployés sur un hôte. Si le pool de connexions occupe trop de ressources de socket, le serveur ne peut pas recevoir trop de demandes client. Lorsque ces connexions sont utilisées, elles sont renvoyées au pool de connexions pour maintenance.

Temps d'inactivité maximal (maxIdleTime) : lorsqu'il y a plus de demandes simultanées d'accès à MySQL, le nombre de connexions dans le pool de connexions augmente dynamiquement. La limite supérieure est maxSize. Lorsque ces connexions sont épuisées, elles sont renvoyées dans le pool de connexions. Si ces connexions nouvellement ajoutées n'ont pas été réutilisées dans le maxIdleTime spécifié, ces ressources de connexion nouvellement ajoutées seront recyclées et n'auront besoin que de conserver le nombre initial de connexions initSize.

Délai d'attente de connexion (connectionTimeOut) : lorsque le nombre de requêtes MySQL simultanées est trop important, que le nombre de connexions dans le pool de connexions a atteint maxSize et qu'il n'y a pas de connexions inactives disponibles à ce moment, l'application ne peut pas réussir à obtenir des connexions à partir du pool de connexions pour le moment. Si le temps nécessaire pour obtenir des connexions via le blocage dépasse le délai connectionTimeout, la connexion échoue et la base de données n'est pas accessible.

Introduction aux paramètres du serveur MySQL

conception de réalisation de fonction

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.连接的生产和连接的消费采用生产者-消费者线程模型来设计,使用了线程间的同步通信机制条件变量和互斥锁

Référence du code d'implémentation

connexion.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;//记录进入空闲状态后的起始时间
};

connexion.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

test de pression

La quantité de données Temps de consommation du pool de connexions inutilisées (ms) Le temps passé à utiliser le pool de connexion (ms)
1000 Filetage simple : 10548 Trois fils : 3472 Fil unique : 4577 Trois fils : 2858
5000 Filetage simple : 53145 Trois fils : 17485 Filetage simple : 22877 Trois fils : 14865

C++ multi-processus/multi-thread

Pour des informations plus détaillées, veuillez vous référer à l'explication détaillée du multithreading C++ (la plus complète sur l'ensemble du réseau) .

Implique principalement les fichiers d'en-tête thread, mutex, atomic, condition_variable, future.

Commandes courantes de la base de données MySQL

Les programmes de base de données MySQL doivent se ;terminer par , comme les programmes C/C++. Et le programme MySQL n'est pas sensible à la casse, c'est-à-dire qu'il n'est pas sensible à la casse.

lié à la base de données

Commande de création de base de données

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

Si la base de données existe, la création échouera et des informations similaires aux suivantes seront obtenues ERROR 1007 (HY000): Can't create database 'name'; database exists.
La commande de création recommandée estCREATE DATABASE IF NOT EXISTS name DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

commande de suppression de la base de données

drop database name

Lors de la suppression de la base de données, il y aura un message d'invite pour déterminer s'il faut la supprimer.

sélectionner la base de données

use name

Afficher toutes les tables de la base de données

show tables;

Table de base de données liée

type de données

MySQL prend en charge une variété de types, qui peuvent être grossièrement divisés en trois catégories : types numériques, date/heure et chaîne (caractère).

type de valeur

MySQL prend en charge tous les types de données numériques SQL standard.

Ces types incluent des types de données strictement numériques ( INTEGER, et ) et des types de données numériques approximatifs ( SMALLINT, et ) .DECIMALNUMERICFLOATREALDOUBLE PRECISION

Le mot-clé INTest INTEGERun synonyme de et le mot-clé DECest DECIMALun synonyme de .

BITLe type de données contient des valeurs de champ de bits et prend en charge les tables MyISAM, et .MEMORYInnoDBBDB

En tant qu'extension du standard SQL, MySQL prend également en charge les types entiers TINYINT, MEDIUMINTet BIGINT.

type de date et d'heure

Les types de date et d'heure représentant les valeurs de temps sont DATETIME, DATE, et .TIMESTAMPTIMEYEAR

Chaque type de temps a une plage de valeurs valides et une valeur "zéro", qui est utilisée lors de la spécification d'une valeur invalide que MySQL ne peut pas représenter.

type de chaîne

Le type de chaîne fait référence à CHAR, VARCHAR, BINARY, , , et .VARBINARYBLOBTEXTENUMSET

Commandes communes de la table de données

Créer un tableau de données

CREATE TABLE table_name (column_name column_type);

Dans l'exemple suivant, nous allons créer la table de données runoob_tbl dans la base de données. Notez que ni le nom de la table ni le nom de la colonne ne doivent être mis entre guillemets :

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;

Exemple d'analyse :

Si vous ne voulez pas que le champ soit NULL, vous pouvez définir l'attribut du champ sur NOT NULL. Si les données saisies dans le champ sont NULL lors de l'utilisation de la base de données, une erreur sera signalée.
AUTO_INCREMENT définit la colonne comme un attribut d'auto-incrémentation, qui est généralement utilisé pour la clé primaire, et la valeur augmentera automatiquement de 1.
Le mot-clé PRIMARY KEY est utilisé pour définir une colonne comme clé primaire. Vous pouvez définir une clé primaire en utilisant plusieurs colonnes, séparées par des virgules.
ENGINE définit le moteur de stockage, CHARSET définit l'encodage.

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;

supprimer la table de données

DROP TABLE table_name ;

insérer des données

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

Si les données sont de type caractère , vous devez utiliser des guillemets simples ou des guillemets doubles , tels que : "valeur".

Interroger les données

SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M]
  • Une ou plusieurs tables peuvent être utilisées dans l'instruction de requête, et les tables sont séparées par des virgules (,), et les conditions de requête sont définies à l'aide de l'instruction WHERE.
  • La commande SELECT peut lire un ou plusieurs enregistrements.
  • Vous pouvez utiliser un astérisque (*) pour remplacer d'autres champs, et l'instruction SELECT renverra toutes les données de champ dans la table
  • Toute condition peut être incluse à l'aide de l'instruction WHERE.
  • Vous pouvez utiliser l'attribut LIMIT pour définir le nombre d'enregistrements renvoyés.
  • Vous pouvez utiliser OFFSET pour spécifier le décalage de données pour démarrer l'interrogation dans l'instruction SELECT. Par défaut, le décalage est de 0.

où déclaration

Voici la syntaxe générale de l'instruction SQL SELECT pour lire les données de la table de données à l'aide de la clause WHERE :

SELECT field1, field2,...fieldN FROM table_name1, table_name2...
[WHERE condition1 [AND [OR]] condition2.....
  • Dans l'instruction de requête, vous pouvez utiliser une ou plusieurs tables, utiliser des virgules pour séparer les tables et utiliser l'instruction WHERE pour définir les conditions de la requête.
  • N'importe quelle condition peut être spécifiée dans la clause WHERE.
  • Une ou plusieurs conditions peuvent être spécifiées en utilisant AND ou OR.
  • La clause WHERE peut également être utilisée dans les commandes SQL DELETE ou UPDATE.
  • La clause WHERE est similaire à la condition if du langage de programmation et lit les données spécifiées en fonction de la valeur du champ dans la table MySQL.

Vérifier l'état du formulaire

desc table_name;

Un exemple est le suivant :

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)

Problème commun

error C4996: ‘sprintf’: This function or variable may be unsafe. Consider using sprintf_s instead. , défini dans VS, propriétés du projet -> C/C++ -> préprocesseur -> définition du préprocesseur plus _CRT_SECURE_NO_DEPRECATE et _SCL_SECURE_NO_DEPRECATE, séparés par des points-virgules.

Je suppose que tu aimes

Origine blog.csdn.net/qq_45041871/article/details/131837950
conseillé
Classement