下载mysql

sudo apt-get install mysql-server
sudo mysql -u root -p

过程中没有让我设置初始密码,这里直接回车进入。

修改密码:

your_new_password应该替换为您想要设置的新密码。

ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_new_password';

可以通过以下命令验证密码是否已更改:

 SELECT User, Host, authentication_string FROM mysql.user WHERE User='root';

远程连接mysql

10061报错

在Hostname输入本机的公网ip地址(ifconfig获得)

设置数据库密码

点击Test Connection,报错10061。

说明数据库服务器返回给workbench了10061的错误,那么服务器肯定工作了。

打开数据库的配置文件

sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

127.0.0.1是回环地址 机器内部使用的地址 外界访问不到

改成0.0.0.0,表示任意地址

重启mysql服务

sudo /etc/init.d/mysql restart

not allowed报错

重新尝试Test Connection,报错:

说明数据库服务器限制root的远程登录

查看当前用户的 Host 授权范围,输出显示仅允许本地登录:

不建议修改root,最高权限,企业运营过程中root非常重要。

创建一个新用户

create user 'admin'@'%' identified by 'your_password';

查看用户

select User, Host From user;

%表示任意地址,即任何地址都可以用admin用户登录

ssl报错

MySQL命令查看SSl

SHOW VARIABLES LIKE "%SSL%"

说明SSL已经启用。

修改配置文件跳过SSL:在尾行添加`skip_ssl`,重启mysql服务

查看ssl,已经关闭了:

外部组件异常报错

这是因为用了5. 版本的workbench,而我通过`sudo apt-get install mysql-server`下载的版本为8.0,加密方式为caching_sha2_password,5. 版本的客户端还不支持。因此需要修改 mysql 用户密码的加密方式。

查看加密方式

sudo mysql -u root -p
USE mysql;
select user, host, plugin, authentication_string from user;

ALTER USER 'admin'@'%' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER;   #设置密码永不过期
ALTER USER 'admin'@'%' IDENTIFIED WITH mysql_native_password BY 'password';   #修改密码加密方式
FLUSH PRIVILEGES; #更新

Connection Warining

终于发现是版本问题。去下了一个新版本的workbench,成功连接了。

使用workbench远程操作数据库

选择sql语句,点击小闪电执行语句

报错:

admin没有权限操作数据库mysql,使用root用户的权限赋予admin用户select权限

grant select on mysql.* to 'admin'@'%';

然后就可以执行use mysql和select相关操作,但还不能create。

赋予其所有权限,相当与root的权限:

grant all privileges on *.* to 'admin'@'%';

创建数据库YU_DB,并在其中创建表TBL_USER

CREATE DATABASE YU_DB;

SHOW DATABASES;



USE YU_DB;



CREATE TABLE TBL_USER(

U_ID INT PRIMARY KEY AUTO_INCREMENT,

U_NAME VARCHAR(32),

U_GENGDER VARCHAR(8)

);



SHOW TABLES;

使用C代码远程操作数据库

插入数据

c代码如下


#include <mysql.h>
#include <stdio.h>
#include <string.h>
#define DB_SERVER_PORT          3306
#define DB_SERVER_IP            "192.168.189.128"

#define DB_USERNAME             "admin"
#define DB_PASSWORD             "197523@cyr"

#define DB_NAME                 "YU_DB"
#define SQL_INSERT_TBL_USER     "INSERT TBL_USER(U_NAME, U_GENGDER) VALUES('yu', 'woman');"

int main(){
    MYSQL mysql;
    // 初始化数据库
    if(NULL == mysql_init(&mysql)){
        printf("mysql_init : %s\n",mysql_error(&mysql));
        return -1;
    }

    //连接数据库,非0为成功
   if(!mysql_real_connect(&mysql,DB_SERVER_IP,DB_USERNAME,DB_PASSWORD,DB_NAME,DB_SERVER_PORT, NULL,0)){
        printf("mysql_real_connect : %s\n",mysql_error(&mysql));
    }

    //传递SQL语句,0为成功
    if(mysql_real_query(&mysql,SQL_INSERT_TBL_USER,strlen(SQL_INSERT_TBL_USER))){
        printf("mysql_real_query : %s\n",mysql_error(&mysql));
    }
    //关闭数据库
    mysql_close(&mysql);
    return 0;

}

在ns服务器上(node server)上安装mysql的客户端操作库

sudo apt-get install libmysqlclient-dev

指定mysql的系统头文件、mysql的库,进行编译运行

gcc -o mysql mysql.c -I /usr/include/mysql/ -l mysqlclient
./mysql

回到workbench,运行

SELECT * FROM TBL_USER;

成功插入数据

查询数据

int yu_mysql_select(MYSQL *handle){

    //传递SQL语句

    if(mysql_real_query(handle,SQL_SELECT_TBL_USER,strlen(SQL_SELECT_TBL_USER))){
        printf("mysql_real_query : %s\n",mysql_error(handle));
        return -1;
    }

    //存储结果
    MYSQL_RES *res = mysql_store_result(handle);
    if(res == NULL){
        printf("mysql_real_query: %s\n",mysql_error(handle));
        return -2;
    }
    //确定结果的行列数
    int rows = mysql_num_rows(res);
    printf("row: %d\n", rows);
    int fields = mysql_num_fields(res);
    printf("fields: %d\n",fields);

    //抓取数据
    MYSQL_ROW row;
    while((row = mysql_fetch_row(res))){
        int i = 0;
        for(i = 0;i < fields;i++){
            printf("%s\t", row[i]);
        }
        printf("\n");
    }

}

删除数据

workbench实现

DELETE FROM TBL_USER WHERE U_NAME='yu';

U_NAME非主键,这样删除不安全。在安全模式下命令会被拒绝

关闭安全模式,执行完命令后再开启

SET SQL_SAFE_UPDATES=0;
DELETE FROM TBL_USER WHERE U_NAME='yu';
SET SQL_SAFE_UPDATES=1;

容易出错.

存储过程

CREATE PROCEDURE PROC_DELETE_USER(IN UNAME VARCHAR(32))
BEGIN
SET SQL_SAFE_UPDATES=0;
DELETE FROM TBL_USER WHERE U_NAME=UNANE;
SET SQL_SAFE_UPDATES=1;
END

这里报错,需要结束标识符。正确写法:

DELIMITER %%
CREATE PROCEDURE PROC_DELETE_USER(IN UNAME VARCHAR(32))
BEGIN
SET SQL_SAFE_UPDATES=0;
DELETE FROM TBL_USER WHERE U_NAME=UNANE;
SET SQL_SAFE_UPDATES=1;
END %%

%%可以替换为其他符号

调用存储过程

CALL PROC_DELETE_USER('qiuxiang');

删除存储过程

DROP PROCEDURE PROC_DELETE_USER;

代码实现

#define SQL_DELETE_TBL_USER     "CALL PROC_DELETE_USER('darren')"
……
    if(mysql_real_query(&mysql,SQL_DELETE_TBL_USER,strlen(SQL_DELETE_TBL_USER))){
        printf("mysql_real_query : %s\n",mysql_error(&mysql));
    }
……

图片插入数据库

  1. 准备好一张图片,读入内存
  2. 把图片数据存入数据库
  3. 如何把图片从数据库中读出来
  4. 写入磁盘

#include <mysql.h>
#include <stdio.h>
#include <string.h>
#define DB_SERVER_PORT          3306
#define DB_SERVER_IP            "192.168.189.128"

#define DB_USERNAME             "admin"
#define DB_PASSWORD             "197523@cyr" 

#define DB_NAME                 "YU_DB"
#define SQL_INSERT_TBL_USER     "INSERT TBL_USER(U_NAME, U_GENDER) VALUES('darren', 'man');"
#define SQL_SELECT_TBL_USER     "SELECT * FROM TBL_USER;"
#define SQL_DELETE_TBL_USER     "CALL PROC_DELETE_USER('darren')"
#define SQL_INSERT_IMG_USER     "INSERT TBL_USER(U_NAME, U_GENDER, U_IMG) VALUES('King', 'man', ?)"
#define SQL_SELECT_IMG_USER     "SELECT U_IMG FROM TBL_USER WHERE U_NAME='King';"     


#define FILE_IMAGE_LENGTH       (500*1024)
int yu_mysql_select(MYSQL *handle){
    //传递SQL语句
    if(mysql_real_query(handle,SQL_SELECT_TBL_USER,strlen(SQL_SELECT_TBL_USER))){
        printf("mysql_real_query : %s\n",mysql_error(handle));
        return -1;
    }
    //存储结果
    MYSQL_RES *res = mysql_store_result(handle);
    if(res == NULL){
        printf("mysql_real_query: %s\n",mysql_error(handle));
        return -2;
    }
    //确定结果的行列数
    int rows = mysql_num_rows(res);
    printf("row: %d\n", rows);
    int fields = mysql_num_fields(res);
    printf("fields: %d\n",fields);

    //抓取数据
    MYSQL_ROW row;
    while((row = mysql_fetch_row(res))){
        int i = 0;
        for(i = 0;i < fields;i++){
            printf("%s\t", row[i]);
        }
        printf("\n");
    }
}

//从内存读取图片的二进制数据
int read_image(char* filename, char* buffer){
    if(filename == NULL || buffer == NULL)return -1;

    //以二进制读的方式打开
    FILE* fp = fopen(filename, "rb"); 
    if(fp == NULL){
        printf("fopen failed\n");
        return -2;
    }
    
    //检测文件大小
    fseek(fp, 0, SEEK_END);//文件指针置末尾 偏移量0表示在末尾
    int length = ftell(fp);
    fseek(fp, 0, SEEK_SET);//文件指针置开头 偏移量0表示在开头

    //读取length个数据块,每个数据块大小1,返回读到的数据块个数
    int size = fread(buffer, 1, length, fp);
    if(size!=length){
        printf("fread failed: %d %d\n", size, length);
        return -2;
    }
    fclose(fp);
    return size;
    
}

int write_image(char* filename,char* buffer, int length){
    if(filename == NULL || buffer == NULL || length <= 0)return -1;

    FILE* fp = fopen(filename, "wb+");//+表示有则使用,无则创建
    if(fp == NULL){
        printf("fopen failed\n");
    }

    int size = fwrite(buffer, 1, length, fp);
    if(size != length){
        printf("fwrite failed: %d\n", size);
        return -3;
    }
    fclose(fp);
    return size;
}

int mysql_write(MYSQL* handle, char* buffer, int length){
    if(handle == NULL || buffer == NULL || length <= 0) return -1;

    //准备好stmt
    MYSQL_STMT* stmt = mysql_stmt_init(handle);
    int ret = mysql_stmt_prepare(stmt, SQL_INSERT_IMG_USER, strlen(SQL_INSERT_IMG_USER));
    if(ret){
        printf("mysql_stmt_prepare: %s\n", mysql_error(handle));
        return -2;
    }

    //准备好stmt的绑定参数
    MYSQL_BIND param = {0}; 
    param.buffer_type = MYSQL_TYPE_LONG_BLOB;
    param.buffer = NULL;
    param.is_null = 0;
    param.length = NULL;

    //绑定stmt与param
    ret = mysql_stmt_bind_param(stmt, &param);
    if(ret){
        printf("mysql_stmt_bind_param : %s\n", mysql_error(handle));
        return -3;
    }

    //分片发送数据给数据库
    ret = mysql_stmt_send_long_data(stmt, 0, buffer, length);
    if(ret){
        printf("mysql_stmt_send_long_data : %s\n", mysql_error(handle));
        return -4;
    }

    //把数据存入数据库
    ret = mysql_stmt_execute(stmt);
    if(ret){
        printf("mysql_stmt_execute : %s\n", mysql_error(handle));
        return -5;
    }

    ret = mysql_stmt_close(stmt);
    if(ret){
        printf("mysql_stmt_execute : %s\n", mysql_error(handle));
        return -6;
    }
    return ret;
}

int mysql_read(MYSQL* handle, char* buffer, int length){
    if(handle == NULL || buffer == NULL || length <= 0) return -1;
    
    MYSQL_STMT* stmt = mysql_stmt_init(handle);
    int ret = mysql_stmt_prepare(stmt, SQL_SELECT_IMG_USER, strlen(SQL_SELECT_IMG_USER));
    if(ret){
        printf("mysql_stmt_prepare: %s\n", mysql_error(handle));
        return -2;
    } 

    MYSQL_BIND result = {0};

    result.buffer_type = MYSQL_TYPE_LONG_BLOB;
    unsigned long total_length = 0;
    result.length = &total_length;

    ret = mysql_stmt_bind_result(stmt, &result);
    if(ret){
        printf("mysql_stmt_bind_result: %s\n",mysql_error(handle));
        return -3;
    }

    ret = mysql_stmt_execute(stmt);
    if(ret){
        printf("mysql_stmt_execute: %s\n",mysql_error(handle));
        return -4;
    }

    ret = mysql_stmt_store_result(stmt);
    if(ret){
        printf("mysql_stmt_store_result: %s\n",mysql_error(handle));
        return -5;
    }
    while(1){
        ret = mysql_stmt_fetch(stmt);
        if(ret != 0 && ret != MYSQL_DATA_TRUNCATED)break;

        int start = 0;
        while(start < (int)total_length){
            result.buffer = buffer + start; 
            result.buffer_length = 1;
            mysql_stmt_fetch_column(stmt,&result, 0, start);
            start += result.buffer_length;
        }
    }

    ret = mysql_stmt_close(stmt);
    if(ret){
        printf("mysql_stmt_execute : %s\n", mysql_error(handle));
        return -6;
    }
    return total_length;
}
int main(){
    MYSQL mysql;
    // 初始化数据库
    if(NULL == mysql_init(&mysql)){
        printf("mysql_init : %s\n",mysql_error(&mysql));
        return -1;
    }
    //连接数据库,非0为成功
    if(!mysql_real_connect(&mysql,DB_SERVER_IP,DB_USERNAME,DB_PASSWORD,DB_NAME,DB_SERVER_PORT, NULL,0)){
        printf("mysql_real_connect : %s\n",mysql_error(&mysql));
        return -1;
    }
    //传递SQL语句,0为成功
#if 1

    printf("case: mysql --> insert\n");
    //插入
    if(mysql_real_query(&mysql,SQL_INSERT_TBL_USER,strlen(SQL_INSERT_TBL_USER))){
        printf("mysql_real_query : %s\n",mysql_error(&mysql));
    }
#endif
    //查询
    yu_mysql_select(&mysql);
    printf("case: mysql --> delete\n");
#if 1
    //删除
    if(mysql_real_query(&mysql,SQL_DELETE_TBL_USER,strlen(SQL_DELETE_TBL_USER))){
        printf("mysql_real_query : %s\n",mysql_error(&mysql));
    }
    yu_mysql_select(&mysql);
#endif


    printf("case: mysql --> read image and write mysql\n");
    char buffer[FILE_IMAGE_LENGTH];
    int length = read_image("image.png", buffer);
    if(length<0) goto Exit;

    mysql_write(&mysql, buffer, length);//插入数据库
    

    printf("case: mysql --> read mysql and write image\n");
    memset(buffer, 0, FILE_IMAGE_LENGTH);
    length = mysql_read(&mysql, buffer, FILE_IMAGE_LENGTH);
    
    write_image("a.jpg", buffer, length);
    //关闭数据库
Exit:
    mysql_close(&mysql);
    
    return 0;
}

思考题:实现数据库的连接池

文章参考

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐