整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

在 Node.js 中使用 MySQL &a

在 Node.js 中使用 MySQL & MySQL JavaScript 客户端

oSQL 数据库最近一段时间都是很受追捧的,也许已经是 Node.js 应用程序的首选后端了。不过,你不应该只是根据潮流来选择拿什么技术构建下一个项目,使用什么数据库类型要取决于项目的特定需求。如果你的项目涉及到动态表的创建,实时的插入等等,那么 NoSQL 就是不错的技术路线,而另一方面,如果项目中要处理复杂的查询和事务,那么 SQL 数据库就更加合适了。

在本教程中,我们会向你介绍如何使用 MySQL 模块 - 这是一个用 JavaScript 编写的运行在 Node.js 之上的 MySQL 驱动程序。我会向你解释如何使用该模块连接到 MySQL 数据库,执行常规的 CRUD 操作,之后就是对存储的过程进行检查,以及对用户的输入进行转义这些技术。

这个颇受欢迎的教程在 2017 年 11 月 07 日进行了更新。其中的修改包括将语法更新到了 ES6,解决了node-mysql 模块被重新命名的问题,增加了更多对初学者友好的文字说明,并在 ORM 上新增加了一个部分。

快速入门:如何在Node 中使用MySQL

也许你来这是就是为了找到一个快速的法门。如果你是想用尽可能少的时间在 Node 中启动并运行 MySQL,我们能满足你的需求!

以下5个简单步骤告诉你如何在 Node 中使用 MySQL:

  1. 创建一个新项目:mkdir mysql-test && cd mysql-test

  2. 创建一个 package.json 文件:npm init -y

  3. 安装mysql模块: npm install mysql –save

  4. 创建一个app.js文件并将下面的代码段复制进去。

  5. 运行该文件: node app.js。会看到一条 “Connected!”(已连接上了)消息。

安装 mysql 模块

现在让我们细化到第一步。首先,我们使用命令行创建一个新目录进进入这个目录。然后我们使用 npm init -y 命令创建 package.json 文件。-y 参数表示 npm 会使用默认值而不会问你各种问题。

这一步假设你已经在系统上安装了 Node 和 npm。如果还没安装,请阅读 SitePoint 上的这篇文章,它会指导你:使用 nvm 安装 Node.js 的多个版本。

然后,我们从 npm 安装 mysql 模块并将其保存为项目的依赖项。项目的 dependencies (相对于 dev-dependencies) 是运行程序所需要的包。你可以阅读了解两者的区别。

如果你深入学习使用 npm,可以阅读这个指南,或者在我们的论坛上提问。

入门

在我们连接到数据库之前,有一件重要的事情就是要在你的机器上安装和配置 MySQL。如果这件事情还没做完,那就看看软件主页上的安装说明自己去装一个吧。

接下来我们需要做的就是创建一个数据库和一个数据库表。你可以使用一个图形用户界面来做到这一点,比如说 phpMyAdmin,或者就使用命令行。 对于我们这篇文章,使用的是一个名为 sitepoint 的数据库和一个名为 employees 的表。如果你希望跟着一起操作的话,这里有一个数据库的转储文件,方便你可以快速地启动并运行起来:

连接到数据库

现在,我们在 mysql-test 目录下创建一个名为 app.js 的文件,来看看如何从 Node.js 连接到 MySQL。

现在打开一个终端并输入 node app.js。在连接成功建立之后,你应该能够在控制台中看到“Connection established”(连接已经建立好了)这条消息了。 如果出现了什么问题(例如输入了错误的密码),程序就会触发一个回调,该事件会传递出一个 JavaScript Error 对象(err)的实例。 你可以尝试将其打印到控制台以查看其中包含的有用信息以调试程序。

使用 Grunt 来监视文件的更改

每当我们对代码进行更改时,手动运行 node app.js 命令会变得有点乏味,所以让我们来把这个操作自动化吧。 这一节并不需要跟本教程的其余部分并没有依赖关系,不过如果照着做的话肯定会为你节省一些麻烦事儿。

我们首先得安装几个包:

Grunt 是有名的 JavaScript 任务执行程序,每当监听到有文件发生修改时,grunt-contrib-watch 都会运行已经预定义好的任务,并且会使用 grunt-execute 来运行 node app.js 命令。

安装完成之后,在项目根中创建一个名为Gruntfile.js的文件,然后在里面添加上如下代码。

现在运行 grunt watch 然后修改一下 app.js 文件。Grunt 就应该会检测到我们修改了文件并重新运行 node app.js 命令。

执行查询

读取

现在你知道如何在 Node.js 中建立 MySQL 连接了,再来看看如何执行 SQL 查询。我们从这里开始:建立使用 createConnection 命令连接到名为 sitepoint 的数据库。

连接建立后我们要使用连接变量来对数据库中的 employees 表进行查询。

现在运行 app.js (通过 grunt-watch 或者在终端输入 node app.js),你可以看到终端输出从数据库返回的数据。

从 MySQL 数据库返回的数据可以通过遍历 rows 对象来进行解析。

创建

你可以在数据库中执行 insert 查询,像这样:

请注意到我们是如何通过回调参数来获得刚插入那条记录的 ID 的。

更新

类似地,在执行 update 查询的时候,通过 result.affectedRows 可得到受影响的行数:

删除

delete 查询的操作也差不多:

高级用法

我希望有办法通过 mysql 模块来处理存储过程,以及转义用户输入。

存储过程

简单的说,存储过程是存储在数据库中,可以由数据库引擎和连接上数据的程序语言调用的程序(例如,SQL 程序)。如果你需要复习,请看看这篇不错的文章。

先来为我们的 sitepoint 数据库创建一个存储过程,它用于获取所有员工的详情。我们把它命名为 sp_getall。为了做这件事,你需要某种数据库接操作界面。我使用 phpMyAdmin。在 sitepoint 数据库中运行下面的查询:

它会将程序保存在 information_schema 数据库的 ROUTINGS 表中。

下一步,建立连接并使用连接对象调用存储过程,像这样:

保存修改并运行。运行的时候你可以看到从数据库返回的数据。

这些数据包括一些附加信息,比如影响的行数,insertId 等。你需要对返回数据的第 0 个元素进行遍历以获取员工详情信息。

现在考虑一个需要输入参数的存储过程。

我们可以在调用存储过程的时候传入参数:

多数时候,如果我们想在数据库中插入一条记录,需要将插入记录的 ID 作为输出参数返回出来。考虑接下来用于插入数据的存储过程,它有一个输出参数:

为了调用含有输出参数的存储过程,我们需要在创建连接时调用多个程序。因此,修改连接,设置执行多个语句为 true。

然后在调用存储过程的时候,设置并传入一个输出参数。

在上面的代码中,我们设置了输出参数 @employee_id 并在调用存储过程的时候将其传入。一旦调用完成,我们需要使用 select 查询输出参数来获取返回的 ID。

运行 app.js。如果执行成功你可以看到 select 查询的输出参数和各种其它信息。通过 rows[2] 可获得输出参数的值。

转义用户输入

为了避免 SQL 注入攻击,你应该总是转义来自用户的任何数据,然后再把它用于 SQL 查询。来演示一下为什么:

这看起来并没有什么问题,它会返回正确的结果:

不过,如果我们将 userLandVariable 改为:

居然访问了整个数据集。如果我们再改为这样:

这下麻烦大了!

好消息是有办法处理这类问题。你只需要使用 mysql.escape 方法:

或者使用问号占位符,就像我们在文章一开始提到的那个示例一样:

为什么不简单地使用 ORM?

你可能注意到了,评论中有人建议使用 ORM。在详述这个方法的优缺点之前,我先看看 ORM 是什么。下面是来自 Stack Overflow 的回答。

对象关系映射(Object-Relational Mapping, ORM) 是一种允许人们使用面向对象范型来查询和操作数据库数据的技术。在谈到 ORM 的时候,多数人是指实现了 ORM 技术的某个库,所以会使用 “an ORM” 这样的短语。

因此,这种方法基本上意味着你会使用 ORM 领域相关的语言来编写数据库逻辑,而不是我们一直在讨论的普通方法。下面以 Sequelize 为例:

对比:

使用 ORM 对你是否有意义,取决于很多与你工作相关的因素,比如你在做什么以及为谁做。一方面,ORM 的形式使开发更为高效,从某种程序上来说,它抽象了大部分的 SQL 因而不需要团队中的每个人都去了解如何编写高效的数据库查询。它也很容易迁移到不同的数据库软件,因为你是在抽象层次上进行开发。

然而,从另一方面来说,由于不理解 ORM 是如何做的,所以可能会编写出一些混乱和低效的 SQL。性能也会是一个大问题,毕竟优化不通过 ORM 的查询要容易得多。

到底采用哪一种方法,决定权在你,但是如果正在做这个决定,请看看这个 Stack Overflow 的帖子:为什么应该使用 ORM?,以及 SitePoint 上的:你可能不知道的 3 个 JavaScript ORM。

小结

本教程中只涉及到了 MySQL 客户端的皮毛。我推荐你去阅读官方文档以了解更详细的信息。当然也有别的选择,比如 node-mysql2 和 node-mysql-libmysqlclient。

你是否已经在 Node.js 中用过这些库来连接到 MySQL?我很想听人说说这些库。请在下面的评论中告诉我们你的想法、建议以及更正意见!


文章来源:开源中国

【灯塔大数据】微信公众号介绍:中国电信北京研究院通过整合电信自有数据、互联网数据和线下数据,创建了业内领先的“灯塔”大数据行业应用平台,致力于与行业合作伙伴共同打造大数据行业应用生态圈。目前我们面向市场研究、广告、汽车、金融、人力资源等诸多行业领域,提供零售研究、消费者研究、店铺选址、精准营销、泛义征信等服务,助力企业在大数据时代杨帆远航。

微信公众号【灯塔大数据】关键字信息:

【人工智能】获取人工智能时代的发展思考 ppt

【半月刊】下载大数据瞭望半月刊

【网络安全】获取国民网络安全报告全文

【23个理由】下载《大数据让你兴奋的23个理由》电子书

【思维导图】下载12种工具的获取方式

【 灯塔 】 查看更多关键字回复

唠嗑一下。都在说去O或者开源,但是对于数据库选型来说,很多人却存在着误区。例如,去O,狭义上讲,是去Oracle数据库。但是从广义上来说,是去Oracle公司产品或者具有漂亮国垄断地位和需要商业授权的数据库产品。

去O,目前国内有一个现象,就是很多公司或个人听到去O,第一反应是改用Mysql,实际上Mysql也是Oracle公司的。而且Mysql虽然是开源的,但是需要遵循GPL开源协议,这个协议里面(大概意思)含有这么两点就可以窥见一斑:

1、如果用Mysql源码进行二次修改,修改后的产品也必须开源,例如目前国产分布式数据库TiDB就遵循该协议进行开源;

2、如果要对Mysql二次封装或者修改后进行实现商业版本,就必须取得甲骨文公司授权。以上这两条,就足以让Mysql这款开源数据库并不具备“开源优势”,将来该被制裁还是会被制裁。

目前去O,还有一款备选开源数据库是PostgreSQL,它是基于BSD开源协议的,该开源协议是四大开源协议里面最“开放”和自由的,不会受到商业版权化影响,并且组织或个人也可以通过它的源码进行二次封装或者进行发行商业版,例如华为的OpenGuass是基于该开源版本进行二次开发的,并且基于PostgreSQL或者基于OpenGuass进行二次封装成商业版本的数据库(国产、非国产等)也比比皆是。


以上只是吐个槽,本篇文章主要是想通过.NET6+EF CORE + 三大数据库,进行一个在同等环境下的简单的读写性能测试。


【备注】由于各种原因,接下来的测试结果可能会不准确,以下仅供学习或参考使用。


数据库运行环境:Cent OS 7.5


PostgreSQL版本:14

MySQL数据库版本:8.0

Oracle数据库:12C 64位


客户端环境:WIN 10 专业版

运行时环境:.NET 6

ORM:EF CORE

开发语言:C#



CentOS环境安装PostgreSQL

远程服务器上已有授权的Oracle环境和Mysql环境,所以具体安装细节不再进行描述,如果感兴趣的小伙伴也可以自行百度一下Oracle和Mysql的安装教程,应该非常多。由于服务器上暂时还没有PostgreSQL环境,我暂且也把安装PostgreSQL的安装步骤也顺手记录下。


PostgreSQL安装:

下载地址:

https://www.postgresql.org/download/linux/redhat/

选择版本以后,会有对应提示的安装方式命令,就不发出来了,可自行参考。


以下是安装以后的一些配置。

安装完毕,并且启动pgsql服务以后,此处我先创建一个测试用的数据库:testdb


使用命令:su - postgres 可以进行默认的登录,默认无密码。

登陆以后使用命令:psql 可以进入到可执行SQL的命令的页面,以postgres=# 开头。其他命令和有关创建用户的SQL语句如图所示。


修改配置文件: /var/lib/pgsql/14/data/postgresql.conf

将注释的listen_addresses打开,设置值为 ‘*’

路径上的14代表版本,如果是13版本就是13,以此类推,下同。

修改/var/lib/pgsql/14/data/pg_hba.conf配置文件,对IPV4访问新增一行配置如下:

然后要重启pgsql服务,以用于生效。


由于pgsql默认的端口是5432,为了可以跨远程访问,此处把远程服务器上的端口开放出来。命令:firewall-cmd --zone=public --add-port=5432/tcp --permanent

然后重载防火墙,命令:firewall-cmd --reload

测试数据库有关表结构。以下表均没有设置索引,仅单表测试,结果仅供参考。

Mysql表结构:

PostgreSQL表结构:


Oracle表结构:



.NET 6开发测试代码

先创建一个minimal api项目,以及一个服务类库项目。类库引用需要操作Oracle数据库、MySQL数据库以及Postgresql数据库有关的组件。



对服务类设置为启动项,然后新增三个文件夹(MyModel,OraModel和PgModel),用于分别存放三个数据库的实体类。然后在程序包管理控制台上,通过命令:

Scaffold-DbContext “mysql连接字符串" Pomelo.EntityFrameworkCore.MySql -OutputDir MyModel -Force

自动生成指定的mysql数据库实体类。其中,MyModel是需要生成的目标目录文件夹。


通过命令:

Scaffold-DbContext "Oracle连接字符串" Oracle.EntityFrameworkCore -OutputDir OraModel -Force

自动生成Oracle数据库实体类。


通过命令:

Scaffold-DbContext "pgsql连接字符串" Npgsql.EntityFrameworkCore.PostgreSQL -OutputDir PgModel -Force

自动生成PostgreSQL数据库实体类。



新建一个测试服务类DatabaseTestService,提供简单插入和更新功能:


在minimai api项目里,新增两个简单的测试API用于测试。为了简单,就直接实例化一下进行访问,然后返回执行结果。


以上方法可能执行适合会导致耗时而失败,为了直观一点,改成控制台里面输出。


实现里面也做点调整。


测试插入和更新

运行程序以后,对三个数据库分别插入数据并计时。

先看Oracle物理表情况。

插入总共数据条数:

部分数据结果集:


然后是mysql物理表数据。

插入数据总数:

部分数据结果集:


最后是PostgreSQL。插入总条数:

部分数据结果集:


以下是通过EF CORE进行插入的结果:


接下来进行一轮更新操作,为了防止数据量太大,所以只进行批量更新10000条数据。结果如下:


看下数据更新结果是不是正常。

Oracle数据:


MySQL数据:


PGSQL数据:


数据库数据清空,屏蔽掉C#代码一些实体赋值时间,重新执行两次仅统计批量插入数据库部分的执行的时间进行重新测试,仅测试批量插入耗时结果。

第一回测试结果:

接下来不删除数据,重新执行一轮。


Oracle估计哪儿有问题,数据让人很尴尬啊。接下来只比较MySQL和PgSQL

来一波批量插入:


再来一波三次的批量更新:


有关代码(最后测试使用)

 public class DatabaseTestService
    {
        public String TestInsert()
        {
            StringBuilder sb=new StringBuilder();
           Console.WriteLine("*************************开始插入测试************************");
            for(int i=1; i < 5; i++)
            {
          //      Console.WriteLine(TestOracleInsert(i));
                Console.WriteLine(TestMysqlInsert(i));
                Console.WriteLine(TestPostgreSQLInsert(i));
            }
            return sb.ToString();
        }
        public String TestUpdate()
        {
            StringBuilder sb=new StringBuilder();
            Console.WriteLine("*************************开始更新测试************************");
            //       Console.WriteLine(TestOracleUpdate());
            for (int i=0;i<3;i++) {
                Console.WriteLine(TestMysqlUpdate(i));
                Console.WriteLine(TestPostgreSQLUpdate(i));
            }
            return sb.ToString();
        }
        private String TestOracleInsert(int loop)
        {
            StringBuilder sb=new();
            Stopwatch stopwatch=new();
            List<OraModel.TestTable> tables=new();

            for (int i=1; i <=50000; i++)
            {
                OraModel.TestTable table=new();
                table.Id=Guid.NewGuid().ToString("N");
                table.Message=$"第{loop}轮测试数据{i}";
                table.CurrentTime=DateTime.Now;
                table.Code=(loop * 5000) + i;
                tables.Add(table);
            }
            using (var context=new OraModel.ModelContext())
            {
                try {

                    stopwatch.Start();
                    context.Database.BeginTransaction();
                    context.TestTables.AddRange(tables);
                    context.SaveChanges();
                    context.Database.CommitTransaction();
                    stopwatch.Stop();
                    sb.Append($"第{loop}轮插入50000条到【Oracle】数据库【成功】:耗时{stopwatch.ElapsedMilliseconds} ms...");

                }
                catch(Exception ex)
                {
                    context.Database.RollbackTransaction();
                    stopwatch.Stop();
                    sb.Append($"第{loop}轮插入50000条到【Oracle】数据库【失败】:耗时{stopwatch.ElapsedMilliseconds} ms...");
                }
                finally
                {
                }
            }

            return sb.ToString();
        }
        private String TestMysqlInsert(int loop)
        {
            StringBuilder sb=new();
            Stopwatch stopwatch=new();
            List<MyModel.TestTable> tables=new();
            for (int i=1; i <=100000; i++)
            {
                MyModel.TestTable table=new();
                table.Id=Guid.NewGuid().ToString("N");
                table.Message=$"第{loop}轮测试数据{i}";
                table.CurrentTime=DateTime.Now;
                table.Code=i;
                tables.Add(table);
            }
            using (var context=new MyModel.testdbContext())
            {
                try
                {
                    stopwatch.Start();
                    context.Database.BeginTransaction();
                    context.TestTables.AddRange(tables);
                    context.SaveChanges();
                    context.Database.CommitTransaction();
                    stopwatch.Stop();
                    sb.Append($"第{loop}轮插入100000条到【MySQL】数据库【成功】:耗时{stopwatch.ElapsedMilliseconds} ms...");

                }
                catch (Exception ex)
                {
                    context.Database.RollbackTransaction();
                    stopwatch.Stop();
                    sb.Append($"第{loop}轮插入100000条到【MySQL】数据库【失败】:耗时{stopwatch.ElapsedMilliseconds} ms...");
                }
                finally
                {
                }
            }

            return sb.ToString();
        }
        private String TestPostgreSQLInsert(int loop)
        {
            StringBuilder sb=new();
            Stopwatch stopwatch=new();
            List<PgModel.TestTable> tables=new();

            for (int i=1; i <=100000; i++)
            {
                PgModel.TestTable table=new();
                table.Id=Guid.NewGuid().ToString("N");
                table.Message=$"第{loop}轮测试数据{i}";
                table.CurrentTime=DateTime.Now;
                table.Code=i;
                tables.Add(table);
            }
            using (var context=new PgModel.testdbContext())
            {
                try
                {

                    stopwatch.Start();
                    context.Database.BeginTransaction();
                    context.TestTables.AddRange(tables);
                    context.SaveChanges();
                    context.Database.CommitTransaction();
                    stopwatch.Stop();
                    sb.Append($"第{loop}轮插入100000条到【PostgreSQL】数据库【成功】:耗时{stopwatch.ElapsedMilliseconds} ms...");

                }
                catch (Exception ex)
                {
                    context.Database.RollbackTransaction();
                    stopwatch.Stop();
                    sb.Append($"第{loop}轮插入100000条到【PostgreSQL】数据库【失败】:耗时{stopwatch.ElapsedMilliseconds} ms...");
                }
                finally
                {
                }
            }

            return sb.ToString();
        }
        private String TestOracleUpdate()
        {
            StringBuilder sb=new();
            Stopwatch stopwatch=new();
           
            using (var context=new OraModel.ModelContext())
            {
                
                var datas=context.TestTables.OrderBy(x=>x.Code).Take(10000);
                context.Database.BeginTransaction();
                foreach (var value in datas)
                {
                    value.Message=$"数据变更,code={value.Code}";
                }
                try
                {
                    stopwatch.Start();
                    context.TestTables.UpdateRange(datas);
                    context.SaveChanges();
                    context.Database.CommitTransaction();
                    stopwatch.Stop();
                    sb.Append($"批量更新【Oracle】数据库10000条【成功】:耗时{stopwatch.ElapsedMilliseconds} ms...");
                    
                }
                catch (Exception ex)
                {
                    context.Database.RollbackTransaction();
                    stopwatch.Stop();
                    sb.Append($"批量更新【Oracle】数据库10000条【失败】:耗时{stopwatch.ElapsedMilliseconds} ms...");
                }
                finally
                {
                }
            }

            return sb.ToString();
        }
        private String TestMysqlUpdate(int loop)
        {
            StringBuilder sb=new();
            Stopwatch stopwatch=new();
            using (var context=new MyModel.testdbContext())
            {

                var datas=context.TestTables.OrderBy(x=> x.Code).Skip(loop*50000).Take(50000);
                context.Database.BeginTransaction();
                foreach (var value in datas)
                {
                    value.Message=$"数据变更,code={value.Code}";
                }
                try
                {
                    stopwatch.Start();
                    context.TestTables.UpdateRange(datas);
                    context.SaveChanges();
                    context.Database.CommitTransaction();
                    stopwatch.Stop();
                    sb.Append($"批量更新【MySQL】数据库50000条【成功】:耗时{stopwatch.ElapsedMilliseconds} ms...");

                }
                catch (Exception ex)
                {
                    context.Database.RollbackTransaction();
                    stopwatch.Stop();
                    sb.Append($"批量更新【MySQL】数据库50000条【失败】:耗时{stopwatch.ElapsedMilliseconds} ms...");
                }
                finally
                {
                }
            }

            return sb.ToString();
        }
        private String TestPostgreSQLUpdate(int loop)
        {
            StringBuilder sb=new();
            Stopwatch stopwatch=new();
            using (var context=new PgModel.testdbContext())
            {

                var datas=context.TestTables.OrderBy(x=> x.Code).Skip(loop * 50000).Take(50000);
                context.Database.BeginTransaction();
                foreach (var value in datas)
                {
                    value.Message=$"数据变更,code={value.Code}";
                }
                try
                {
                    stopwatch.Start();
                    context.TestTables.UpdateRange(datas);
                    context.SaveChanges();
                    context.Database.CommitTransaction();
                    stopwatch.Stop();
                    sb.Append($"第{loop}轮 批量更新【PostgreSQL】数据库50000条【成功】:耗时{stopwatch.ElapsedMilliseconds} ms...");

                }
                catch (Exception ex)
                {
                    context.Database.RollbackTransaction();
                    stopwatch.Stop();
                    sb.Append($"第{loop}轮 批量更新【PostgreSQL】数据库50000条【失败】:耗时{stopwatch.ElapsedMilliseconds} ms...");
                }
                finally
                {
                }
            }

            return sb.ToString();
        }



    }

以上测试至此就结束了。结论可能有点尴尬,也许跟环境配置有关,也可能跟ef core操作数据库的支持与实现有关。并且当前仅在单表环境下测试,并没有通过多表测试、存过测试、压力测试等,结果仅供娱乐和参考。同时欢迎各位大佬们提供更多测试内容,也欢迎各位大佬转发或评论或点赞等一键三连。

本文原链接:https://www.cnblogs.com/weskynet/p/16097151.html


果你不了解python,可以先了解python的简单用法。不过人邮君相信,在座的各位都是大佬,我们直接介绍操作。

第一部分,我们先来介绍python与mysql如何完成数据交互:

python 与 mysql 实现交互的过程,通常分为:建立连接、把sql语句定义为字符串,提交指令、关闭连接

核心的技能在于 sql语句;除了定义sql语句,其余3个处理都是固定的写法。接下来,人邮君结合《MySQL是怎样运行的》这本书,Linux环境为主,为大家进行说明。

MySQL是怎样运行的 从根儿上理解MySQL

MySQL是怎样运行的 从根儿上理解MySQL
¥49.5
购买
<script src="//mp.toutiao.com/mp/agw/mass_profit/pc_product_promotions_js?item_id=6909291449641075203"></script>

首先来看第一步,安装 MySQL 数据库:

如果你想要使用python操作MySQL数据库,就必须先要安装pymysql库,这个库的安装很简单;

第二步,pymysql 模块安装与使用:

MySQL-python驱动,是python 操作mysql必不可少的模块。

下载MySQL-python-1.2.5.zip 文件之后直接解压。进入MySQL-python-1.2.5目录:

>>python setup.py install

下载地址:https://pypi.python.org/pypi/MySQL-python/

第三步,python与mysql的交互实现:

1)连接

pymysql .connect () 函数:连接数据库

使用 pymysql 的 connect() 方法连接数据库,涉及到几个参数,具体代表意义如下:

host:MySQL服务的地址,若数据库在本地上,使用 localhost 或者127.0.0.1。如果在其它服务器上,则写对应的 IP地址

port:服务的端口号,默认为3306,不写则为默认值。

user:登录数据库的用户名

passwd:登录 MySQL 的密码

db:数据库名

charset:设置为 utf8 编码,解决存汉字乱码问题

eg:

# 导入模块
import pymysql
# 打开数据库连接
conn=pymysql.connect(
    host="127.0.0.1",
    user="root",
    password="123456",
    database="test_db",
    charset="utf8")
print(conn)
print(type(conn))

输出结果显示如下:表面数据库连接成功

详细可以参考

https://www.cnblogs.com/qjj19931230/p/12550384.html?utm_source=tuicool

这里要强调的是,除了上面的连接方式,还有其他的连接。在《MySQL是怎样运行的》这本书中,介绍到,mysql连接分为内连接和外连接。内外连接的根本区别是在驱动表中记录不符合ON子句中的连接条件时,内连接不会把该记录加入到最后的结果集中,而外连接会。外连接分为左(外)连接和右(外)连接。


三种链接方式如下图所示:

2)获取游标

conn.cursor():获取游标

对数据库进行操作,只连接数据库是不够的,还需要获取操作数据库的游标,才能进行后续的操作。游标的主要作用是用来接收数据库操作后的返回结果,比如数据查询、插入和删除等。通过获取到的数据库连接实例 conn 下的 cursor() 方法来创建游标,如下:

# 导入模块
import pymysql
# 打开数据库连接
conn=pymysql.connect(
    host="127.0.0.1",
    user="root",
    password="123456",
    database="test_db",
    charset="utf8")
# print(conn)
# print(type(conn))
# 获取连接下的游标
cursor_test=conn.cursor()
print(cursor_test)

3)数据库操作

  • 创建表
import pymysql
# 打开数据库连接
conn=pymysql.connect(
    host="127.0.0.1",
    user="root",
    password="123456",
    database="test_db",
    charset="utf8")
# 获取连接下的游标
cursor_test=conn.cursor()
# 使用 execute() 方法执行 SQL,如果表存在则删除
cursor_test.execute("DROP TABLE IF EXISTS EMPLOYEE")
# 使用预处理语句创建表
sql="""CREATE TABLE user1 (
         FIRST_NAME  CHAR(20) NOT NULL,
         LAST_NAME  CHAR(20),
         AGE INT,  
         SEX CHAR(1),
         INCOME FLOAT )"""
cursor_test.execute(sql)
# 关闭数据库连接
conn.close()

如下所示数据库表创建成功:

mysql> desc user1;
+------------+----------+------+-----+---------+-------+
| Field      | Type     | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+-------+
| FIRST_NAME | char(20) | NO   |     | NULL    |       |
| LAST_NAME  | char(20) | YES  |     | NULL    |       |
| AGE        | int(11)  | YES  |     | NULL    |       |
| SEX        | char(1)  | YES  |     | NULL    |       |
| INCOME     | float    | YES  |     | NULL    |       |
+------------+----------+------+-----+---------+-------+
5 rows in set (0.00 sec)
  • 插入数据
import pymysql
# 打开数据库连接
conn=pymysql.connect(
    host="127.0.0.1",
    user="root",
    password="123456",
    database="test_db",
    charset="utf8")
# 获取连接下的游标
cursor_test=conn.cursor()
# 使用预处理语句创建表
sql="""INSERT INTO user1(FIRST_NAME,
         LAST_NAME, AGE, SEX, INCOME)
         VALUES ('Fei', 'Fei', 20, 'M', 1000)"""
try:
   # 执行sql语句
   cursor_test.execute(sql)
   # 提交到数据库执行
   conn.commit()
except:
   # 如果发生错误则回滚
   conn.rollback()
# 关闭数据库连接
conn.close()
  • 查询数据
import pymysql
# 打开数据库连接
conn=pymysql.connect(
    host="127.0.0.1",
    user="root",
    password="123456",
    database="test_db",
    charset="utf8")
# 获取连接下的游标
cursor_test=conn.cursor()
sql="""
    select * from user1"""
try:
    # 执行 sql 语句
    cursor_test.execute(sql)
    # 显示出所有数据
    data_result=cursor_test.fetchall()
    for row in data_result:
        fname=row[0]
        lname=row[1]
        age=row[2]
        sex=row[3]
        income=row[4]
        # 打印结果
        print("fname=%s,lname=%s,age=%s,sex=%s,income=%s" % \
              (fname, lname, age, sex, income))
except:
    print("Error: unable to fetch data")
# 关闭数据库连接
conn.close()
  • 删除操作
# 导入模块
import pymysql
# 打开数据库连接
conn=pymysql.connect(
    host="127.0.0.1",
    user="root",
    password="123456",
    database="test_db",
    charset="utf8")
# print(conn)
# print(type(conn))
# 获取连接下的游标
cursor_test=conn.cursor()
sql="DELETE * FROM user1"
try:
    # 执行SQL语句
    cursor_test.execute(sql)
    # 提交到数据库执行
    conn.commit()
except:
    # 发生错误时回滚
    conn.rollback()
# 关闭数据库连接
conn.close()

第二部分,我们来介绍如何实现「大量」数据的交互?

《MySQL是怎样运行的》,作者小孩子4919强调,嵌套循环连接算法是指驱动表只访问一次,但被驱动表却可能会访问多次,访问次数取决于驱动表执行单表查询后的结果集中有多少条记录,大致过程如下:


步骤1,选取驱动表,使用与驱动表相关的过滤条件,选取代价最低的单表访问方法来执行对驱动表的单表查询;

步骤2,对步骤1中查询驱动表得到的结果集中的每一条记录,都分别到被驱动表中查找匹配的记录。

由于被驱动表可能会访问多次,因此可以为被驱动表建立合适的索引以加快查询速度。

所以,如果被驱动表非常大,即需要完成大量的数据交换,多次访问被驱动表可能导致很多次的磁盘I/O读取操作,此时可以使用基于块的嵌套循环连接算法来缓解由此造成的性能损耗。Mysql的设计者,提出了名为Join Buffer(连接缓冲区)的概念:

有兴趣的同学,建议根据书中详细描述走一遍。

此外,人邮君特别建议大家看看《MySQL是怎样运行的》,它解决了“为什么这个SQL语句执行得这么慢?为什么我明明建立了索引,但是查询计划显示没用?为什么IN查询中的参数一多就不使用索引了?为什么我的数据显示成了乱码?”等等每一位DBA和后端开发人员在与MySQL打交道时,所遇到的很多常见问题。除此之外,索引结构、MVCC、隔离级别的实现、锁的使用等知识,也是求职人员在MySQL面试中躲不过去的高频问题,作者都在书中给出了很详细的介绍。

MySQL是怎样运行的 从根儿上理解MySQL


这本书的初稿最初是以小册的形式发布在掘金平台上的,一经发布便得到大家的青睐,十分火爆!历经两年,现在终于成书,有兴趣的小伙伴也可以去掘金围观~(小孩子4919 的个人主页)

从底层到应用,从基础到进阶,关于MySQL的一切,作者都在书中讲解得非常清楚,帮助你从根儿上理解MySQL。