Mac操作数据库Mysql知识点备忘录

目录

Mac安装Ubuntu启动Mysql

Mac安装Mysql

CenterOS

Mac

Mysql 8和5的密码插件区别

介绍

基础命令操作数据库

远程连接

数据库操作命令

表操作命令

数据操作命令

备份与恢复命令

查询分配

条件查询

聚合查询

分组查询

排序

分页查询

高级特性

表关系建立和外键

inner join 连接查询

完整的select语句

自关联

视图sql语句的封装

事务

索引

小例子

Python3.6数据库操作Demo

配置PYCharm

逻辑代码

面向对象封装

登录Demo


Mac安装Ubuntu启动Mysql

1.先安装VirtualBoxVM   安装搜狗

2.然后安装Ubuntu系统安装

3.打开Ubuntu左侧工具栏选择软件中心,搜索Mysql更新安装Mysql客户端和Mysql服务端源

4.执行命令安装

安装

sudo apt-get install mysql-server mysql-client
然后按照提示输入

一旦安装完成,MySQL 服务器应该自动启动。您可以在终端提示符后运行以下命令来检查 MySQL 服务器是否正在运行

sudo netstat -tap | grep mysql

出现如下代表已启动

deftmikejing@deftmikejing-VirtualBox:~$ sudo netstat -tap | grep mysql
[sudo] password for deftmikejing: 
tcp6       0      0 [::]:mysql              [::]:*                  LISTEN      1078/mysqld     
deftmikejing@deftmikejing-VirtualBox:~$ 


或者
deftmikejing@deftmikejing-VirtualBox:/lib/systemd/system$ ps ajx|grep mysql
    1   686   686   686 ?           -1 Ss     120   0:00 /bin/sh /usr/bin/mysqld_safe
  686  1141   686   686 ?           -1 Sl     120   0:01 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --log-error=/var/log/mysql/error.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/run/mysqld/mysqld.sock --port=3306
 2877  6341  6340  2877 pts/1     6340 S+    1000   0:00 grep --color=auto mysql
  • 启动
service mysql start
  • 停止
service mysql stop
  • 重启
service mysql restart

如果服务器不能正常运行,您可以通过下列命令启动它:

 sudo /etc/init.d/mysql restart

mysql 的默认密码是linux系统密码,如果需要修改

mysql -u root -p

输入密码

set password =password('需要替换的密码');

5.设置mysql远程访问

使用 sudo netstat -lntp 命令看看

tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN 
如果上面0 0.0.0.0后面不是3306的话就打开/etc/mysql/my.cnf   吧下面这一行给注释掉

bind-address = 127.0.0.1

修改配置以后记得要重启mysql

编辑mysql配置文件,把其中bind-address = 127.0.0.1注释了

vi /etc/mysql/mysql.conf.d/mysqld.cnf 

建立远程连接 

使用root进入mysql命令行
mysql -uroot -p

执行如下2个命令,示例中mysql的root账号密码:root(这root填写具体的密码)
grant all privileges on *.* to root@"%" identified by "password" with grant option;
flush privileges;

重启mysql

/etc/init.d/mysql restart

注意说明

本机登陆mysql:mysql -u root -p (-p一定要有);

从所有主机:grant all privileges on *.* to root@"%" identified by "password" with grant option;

从指定主机:grant all privileges on *.* to root@"192.168.11.205" identified by "password" with grant option;  

例如:

grant all privileges on *.* to test@'192.168.113.124' identified by '123456'

然后执行

flush privileges;

重启Mysql

查看下刚才的账号

select host,user,password from mysql.user

到这里就可以测试下宿主机器ping通宿主下的Ubuntu

默认情况下无法ping通,需要修改网络设置 参考链接

之后下载Navicat用Mac链接Ubuntu里面的Mysql就可以用图形化工具操作了

Mac安装Mysql

CenterOS

一般我们部署到Linux上去,这里就先介绍些CenterOS的安装方法

以 MySQL 5.6 的 Yum 源为例,如果需要更高版本可以另寻,安装命令如下:

wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
sudo rpm -ivh mysql-community-release-el7-5.noarch.rpm
yum install -y mysql mysql-server

运行如上命令即可完成安装,初始密码为空。接下来需要启动 MySQL 服务。

启动 MySQL 服务命令:

sudo systemctl start mysqld

停止、重启命令:

sudo systemctl stop mysqld
sudo systemctl restart mysqld

以上我们就完成了 Linux 下 MySQL 的安装,安装完成之后可以修改密码,可以执行如下命令:

mysql -uroot -p

输入密码后进入 MySQL 命令行模式。

use mysql;
UPDATE user SET Password = PASSWORD('newpass') WHERE user = 'root';
FLUSH PRIVILEGES;

命令中 newpass 即为修改的新的 MySQL 密码,请自行替换。

由于 Linux 一般会作为服务器使用,为了使得 MySQL 可以被远程访问,我们需要修改 MySQL 的配置文件,配置文件路径一般为 /etc/mysql/my.cnf。

如使用 vi 进行修改的命令如下:

vi /etc/mysql/my.cnf

取消此行的注释:

bind-address = 127.0.0.1

此行限制了 MySQL 只能本地访问而不能远程访问,取消注释即可解除此限制。

修改完成之后重启 MySQL 服务,这样 MySQL 就可以被远程访问了。

到此为止,Linux 下安装 MySQL 的过程结束。

Mac

推荐使用 Homebrew 安装,执行 brew 命令即可。

brew install mysql

启动、停止、重启 MySQL 服务的命令:

sudo mysql.server start
sudo mysql.server stop
sudo mysql.server restart

Mac 一般不会作为服务器使用,如果要想取消本地 host 绑定,同样修改 my.cnf 文件,然后重启服务即可。

 

这里如果找不到my.cnf文件,可以通过如下命令进行查找:

find 文件路径 参数

比如你可以通过以下命令在用户文件夹中搜索名字中包含screen的文件

find ~ -iname  "screen*"

你也可以在特定的文件夹中寻找特定的文件,比如

find ~/Library/ -iname "com.apple.syncedpreferences.plist"

这个命令可以在Library文件夹中寻找com.apple.syncedpreferences.plist文件

mdfind命令就是Spotlight功能的终端界面,这意味着如果Spotlight被禁用,mdfind命令也将无法工作。mdfind命令非常迅速、高效。最基本的使用方法是:

mdfind -name 文件名字

比如你可以通过下面的命令寻找Photo 1.PNG文件

mdfind -name "Photo 1.PNG"

因为mdfind就是Spotlight功能的终端界面,你还可以使用mdfind寻找文件和文件夹的内容,比如通过以下命令寻找所有包含Will Pearson文字的文件:

mdfind "Will Pearson"

mdfind命令还可以通过-onlyin参数搜索特定文件夹的内容,比如

mdfind -onlyin ~/Library plist

这条命令可以搜索Library文件夹中所有plist文件。

mikejing$ mdfind -name "my.cnf"
/usr/local/etc/my.cnf

修改该文件下127.0.0.1 是否注释来调整是否可以远程连接。

安装之后进行配置

1.启动

mysql.server start

2.mysql配置脚本

/usr/local/opt/mysql/bin/mysql_secure_installation //mysql 提供的配置向导

详细如下

sunyichaodeMacBook-Pro:~ sunyichao$ /usr/local/opt/mysql/bin/mysql_secure_installation   //mysql 提供的配置向导
Securing the MySQL server deployment.
Connecting to MySQL using a blank password.
VALIDATE PASSWORD PLUGIN can be used to test passwordsand improve security. It     checks the strength of password and allows the users to set only those passwords which are secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No: k //是否采用mysql密码安全检测插件(这里作为演示选择否,密码检查插件要求密码复杂程度高,大小写字母+数字+字符等)
Please set the password for root here. // 首次使用自带配置脚本,设置root密码

New password:

Re-enter new password:

By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment.    
Remove anonymous users? [Y/n] Y //是否删除匿名用户
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y //是否禁止远程登录
 ... Success!

By default, MySQL comes with a database named 'test' that anyone can
access.This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] Y //删除测试数据库,并登录
 Dropping test database...
 ... Success!
 Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y//重新载入权限表
 ... Success!

All done!  If you've completed all of the above steps, your MySQL
installation should now be secure.

Thanks for using MySQL!

Cleaning up...
sunyichaodeMacBook-Pro:~ sunyichao$

Mysql 8和5的密码插件区别

Navicat连接报错如下:

2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_sha2_password.so, 2): image not found

两个版本的区别 

mysql> select version()
    -> ;
+-----------+
| version() |
+-----------+
| 8.0.16    |
+-----------+
1 row in set (0.01 sec)

mysql> show variables like 'default_authentication_plugin'
    -> ;
+-------------------------------+-----------------------+
| Variable_name                 | Value                 |
+-------------------------------+-----------------------+
| default_authentication_plugin | caching_sha2_password |
+-------------------------------+-----------------------+
1 row in set (0.10 sec)

mysql> show tables;
+---------------------------+
| Tables_in_mysql           |
+---------------------------+
| columns_priv              |
| component                 |
| db                        |
| default_roles             |
| engine_cost               |
| func                      |
| general_log               |
| global_grants             |
| gtid_executed             |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| innodb_index_stats        |
| innodb_table_stats        |
| password_history          |
| plugin                    |
| procs_priv                |
| proxies_priv              |
| role_edges                |
| server_cost               |
| servers                   |
| slave_master_info         |
| slave_relay_log_info      |
| slave_worker_info         |
| slow_log                  |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
| user                      |
+---------------------------+
33 rows in set (0.01 sec)

mysql> select Host, User, Plugin from user;
+-----------+------------------+-----------------------+
| Host      | User             | Plugin                |
+-----------+------------------+-----------------------+
| localhost | mysql.infoschema | caching_sha2_password |
| localhost | mysql.session    | caching_sha2_password |
| localhost | mysql.sys        | caching_sha2_password |
| localhost | root             | caching_sha2_password |
+-----------+------------------+-----------------------+
4 rows in set (0.00 sec)
mysql> select version();
+------------+
| version()  |
+------------+
| 5.7.15-log |
+------------+
1 row in set (0.00 sec)
 
mysql> show variables like 'default_authentication_plugin';
+-------------------------------+-----------------------+
| Variable_name                 | Value                 |
+-------------------------------+-----------------------+
| default_authentication_plugin | mysql_native_password |
+-------------------------------+-----------------------+
1 row in set (0.01 sec)
 
mysql> select host,user,plugin from mysql.user;
+-----------+-----------+-----------------------+
| host      | user      | plugin                |
+-----------+-----------+-----------------------+
| localhost | root      | mysql_native_password |
| localhost | mysql.sys | mysql_native_password |
| %         | root      | mysql_native_password |

可以看到MySQL8.0.11版本默认的认证方式是caching_sha2_password ,而在MySQL5.7版本则为mysql_native_password。

若想在MySQL8.0版本中继续使用旧版本中的认证方式需要在my.cnf 文件中配置并重启,因为此参数不可动态修改。
 

mysql> set global default_authentication_plugin='mysql_native_password';
ERROR 1238 (HY000): Variable 'default_authentication_plugin' is a read only variable

写入my.cnf 文件后重启MySQL:

vim my.cnf
[mysqld]
default_authentication_plugin=mysql_native_password

上面的这种方案对已有的账户是无法修改的,只是后续新增的账户就会默认的Plugin变成mysql_native_password 


第二种解决方法:兼容新老版本的认证方式。

ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; #修改加密规则 
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; #更新一下用户的密码 
FLUSH PRIVILEGES; #刷新权限

创建新用户步骤,其中 with mysql_native_password不是必须的,默认根据配置文件走 

--创建新的用户:
    create user root@'%' identified WITH mysql_native_password BY 'password';
    grant all privileges on *.* to root@'%' with grant option;
    flush privileges;
    --在MySQL8.0创建用户并授权的语句则不被支持:
    mysql> grant all privileges on *.* to root@'%' identified by 'password' with grant option;
        ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'identified by 'root' with grant option' at line 1
        mysql>

 

介绍

  • 数据库系统解决的问题:持久化存储,优化读写,保证数据的有效性
  • 当前使用的数据库,主要分为两类
    • 文档型,如sqlite,就是一个文件,通过对文件的复制完成数据库的复制
    • 服务型,如mysql、postgre,数据存储在一个物理文件中,但是需要使用终端以tcp/ip协议连接,进行数据库的读写操作

E-R模型

  • 当前物理的数据库都是按照E-R模型进行设计的
  • E表示entry,实体
  • R表示relationship,关系
  • 一个实体转换为数据库中的一个表
  • 关系描述两个实体之间的对应规则,包括
    • 一对一
    • 一对多
    • 多对多
  • 关系转换为数据库表中的一个列 *在关系型数据库中一行就是一个对象

三范式

  • 经过研究和对使用中问题的总结,对于设计数据库提出了一些规范,这些规范被称为范式
  • 第一范式(1NF):列不可拆分
  • 第二范式(2NF):唯一标识
  • 第三范式(3NF):引用主键
  • 说明:后一个范式,都是在前一个范式的基础上建立的

 

字段类型

  • 在mysql中包含的数据类型很多,这里主要列出来常用的几种
  • 数字:int,decimal
  • 字符串:char(不可变,长度不够自动填充), varchar(可变的),text
  • 日期:datetime
  • 布尔:bit


    约束
  • 主键primary key
  • 非空not null
  • 惟一unique
  • 默认default
  • 外键foreign key

基础命令操作数据库

远程连接

  • 一般在公司开发中,可能会将数据库统一搭建在一台服务器上,所有开发人员共用一个数据库,而不是在自己的电脑中配置一个数据库
  • 运行命令
mysql -hip地址 -uroot -p
  • -h后面写要连接的主机ip地址
  • -u后面写连接的用户名
  • -p回车后写密码

数据库操作命令

  • 查看数据库
show databases;
  • 创建数据库
create database 数据库名 charset=utf8;
  • 删除数据库
drop database 数据库名;
  • 切换数据库
use 数据库名;
  • 查看当前选择的数据库
select database();

表操作命令

  • 查看当前数据库中所有表
show tables;
  • 创建表
  • auto_increment表示自动增长

    create table 表名(列及类型);
    如:
    create table students(
    id int auto_increment primary key,
    sname varchar(10) not null
    );
    
  • 修改表

alter table 表名 add|change|drop 列名 类型;
如:
alter table students add birthday datetime;


change举例

alter table 表名 change 原字段 修改后字段 类型
  • 删除表
drop table 表名;
  • 查看表结构
desc 表名;
  • 更改表名称
rename table 原表名 to 新表名;
  • 查看表的创建语句
show create table 表名;

数据操作命令

  • 查询
select * from 表名
  • 增加
全列插入:insert into 表名 values(...)
缺省插入:insert into 表名(列1,...) values(值1,...)
同时插入多条数据:insert into 表名 values(...),(...)...;
或insert into 表名(列1,...) values(值1,...),(值1,...)...;
  • 主键列是自动增长,但是在全列插入时需要占位,通常使用0,插入成功后以实际数据为准
  • 修改
update 表名 set 列1=值1,... where 条件
  • 删除
delete from 表名 where 条件
  • 逻辑删除,本质就是修改操作update
alter table students add isdelete bit default 0;
如果需要删除则
update students isdelete=1 where ...;

备份与恢复命令

数据备份

  • 进入超级管理员
sudo -s
  • 进入mysql库目录 
Homebrew 安装目录  /usr/local/var/mysql/
cd /usr/local/var/mysql/
  • 运行mysqldump命令
mysqldump –uroot –p 数据库名 > ~/Desktop/备份文件.sql;
按提示输入mysql的密码

数据恢复

  • 连接mysql,创建数据库

  • 退出连接,执行如下命令

mysql -uroot –p 数据库名 < ~/Desktop/备份文件.sql
根据提示输入mysql密码

查询分配

条件查询

  • 查询的基本语法
select * from 表名;
  • from关键字后面写表名,表示数据来源于是这张表
  • select后面写表中的列名,如果是*表示在结果中显示表中所有列
  • 在select后面的列名部分,可以使用as为列起别名,这个别名出现在结果集中
  • 如果要查询多个列,之间使用逗号分隔

消除重复行

  • 在select后面列前使用distinct可以消除重复的行
select distinct gender from students;
  • 使用where子句对表中的数据筛选,结果为true的行会出现在结果集中
  • 语法如下:
select * from 表名 where 条件;

比较运算符

  • 等于=
  • 大于>
  • 大于等于>=
  • 小于<
  • 小于等于<=
  • 不等于!=或<>
  • 查询编号大于3的学生
select * from students where id>3;
  • 查询编号不大于4的科目
select * from subjects where id<=4;
  • 查询姓名不是“黄蓉”的学生
select * from students where sname!='黄蓉';
  • 查询没被删除的学生
select * from students where isdelete=0;

逻辑运算符

  • and
  • or
  • not
  • 查询编号大于3的女同学
select * from students where id>3 and gender=0;
  • 查询编号小于4或没被删除的学生
select * from students where id<4 or isdelete=0;

模糊查询

  • like
  • %表示任意多个任意字符
  • _表示一个任意字符
  • 查询姓黄的学生
select * from students where sname like '黄%';
  • 查询姓黄并且名字是一个字的学生
select * from students where sname like '黄_';
  • 查询姓黄或叫靖的学生
select * from students where sname like '黄%' or sname like '%靖%';

范围查询

  • in表示在一个非连续的范围内
  • 查询编号是1或3或8的学生
select * from students where id in(1,3,8);
  • between ... and ...表示在一个连续的范围内
  • 查询学生是3至8的学生
select * from students where id between 3 and 8;
  • 查询学生是3至8的男生
select * from students where id between 3 and 8 and gender=1;

空判断

  • 注意:null与''是不同的
  • 判空is null
  • 查询没有填写地址的学生
select * from students where hometown is null;
  • 判非空is not null
  • 查询填写了地址的学生
select * from students where hometown is not null;
  • 查询填写了地址的女生
select * from students where hometown is not null and gender=0;

优先级

  • 小括号,not,比较运算符,逻辑运算符
  • and比or先运算,如果同时出现并希望先算or,需要结合()使用

聚合查询

  • 为了快速得到统计数据,提供了5个聚合函数
  • count(*)表示计算总行数,括号中写星与列名,结果是相同的
  • 查询学生总数
select count(*) from students;
  • max(列)表示求此列的最大值
  • 查询女生的编号最大值
select max(id) from students where gender=0;
  • min(列)表示求此列的最小值
  • 查询未删除的学生最小编号
select min(id) from students where isdelete=0;
  • sum(列)表示求此列的和
  • 查询男生的编号之后
select sum(id) from students where gender=1;
  • avg(列)表示求此列的平均值
  • 查询未删除女生的编号平均值
select avg(id) from students where isdelete=0 and gender=0;

分组查询

  • 按照字段分组,表示此字段相同的数据会被放到一个组中
  • 分组后,只能查询出相同的数据列,对于有差异的数据列无法出现在结果集中
  • 可以对分组后的数据进行统计,做聚合运算
  • 语法:
select 列1,列2,聚合... from 表名 group by 列1,列2,列3...
  • 查询男女生总数
select gender as 性别,count(*)
from students
group by gender;
  • 查询各城市人数
select hometown as 家乡,count(*)
from students
group by hometown;

分组后的数据筛选

  • 语法:
select 列1,列2,聚合... from 表名
group by 列1,列2,列3...
having 列1,...聚合...
  • having后面的条件运算符与where的相同
  • 查询男生总人数
方案一
select count(*)
from students
where gender=1;
-----------------------------------
方案二:
select gender as 性别,count(*)
from students
group by gender
having gender=1;

对比where与having

  • where是对from后面指定的表进行数据筛选,属于对原始数据的筛选
  • having是对group by的结果进行筛选

排序

  • 为了方便查看数据,可以对数据进行排序
  • 语法:
select * from 表名
order by 列1 asc|desc,列2 asc|desc,...
  • 将行数据按照列1进行排序,如果某些行列1的值相同时,则按照列2排序,以此类推
  • 默认按照列值从小到大排列
  • asc从小到大排列,即升序
  • desc从大到小排序,即降序
  • 查询未删除男生学生信息,按学号降序
select * from students
where gender=1 and isdelete=0
order by id desc;
  • 查询未删除科目信息,按名称升序
select * from subject
where isdelete=0
order by stitle;

分页查询

  • 当数据量过大时,在一页中查看数据是一件非常麻烦的事情
  • 语法
select * from 表名
limit start,count
  • 从start开始,获取count条数据
  • start索引从0开始

示例:分页

  • 已知:每页显示m条数据,当前显示第n页
  • 求总页数:此段逻辑后面会在python中实现
    • 查询总条数p1
    • 使用p1除以m得到p2
    • 如果整除则p2为总数页
    • 如果不整除则p2+1为总页数
  • 求第n页的数据
select * from students
where isdelete=0
limit (n-1)*m,m

高级特性

表关系建立和外键

案例一:

学生 1对多  成绩     学生表中一行能对应多行成绩出现

科目 1对多  成绩    科目中一行能对应多行成绩出现

成绩 1对1   学生和科目   一条成绩必定对应一个学生和一个科目

案例二:

班级    1对多  学生    班级表中一行,能对应多行学生出现

学生  1对1    班级      一个学生必定对应一个班级

1对多代表1的这一方会出现多个在另一方,因此主键关联都会写在学生表中或者成绩表中 

  • 创建成绩表scores,结构如下
    • id
    • 学生
    • 科目
    • 成绩
  •  
  • 思考:学生列应该存什么信息呢?
  • 答:学生列的数据不是在这里新建的,而应该从学生表引用过来,关系也是一条数据;根据范式要求应该存储学生的编号,而不是学生的姓名等其它信息
  • 同理,科目表也是关系列,引用科目表中的数据

这里学生,成绩,科目三个的分析和电商里面 用户,购物车,商品是一样的,首先

学生和科目是n:m的关系,无法维护,因此需要再开一张表成绩来维护好比用户和商品是n:m的关系,因此需要购物车来维护,用户和购物车是1:n,商品和购物车也是1:n

 

以下是科目和学生的标 以及创建一张成绩单的标,

+----+---------+
| id | title   |
+----+---------+
|  1 | Science |
|  2 | Math    |
|  3 | English |
|  4 | Pysical |
|  5 | Mamical |
+----+---------+
5 rows in set (0.00 sec)

mysql> select *from students;
+----+------------+--------+---------------------+----------+-------+----------+
| id | name       | gender | birthday            | isDelete | score | address  |
+----+------------+--------+---------------------+----------+-------+----------+
|  1 | Mekejing   |       | 2018-01-01 00:00:00 |          |    97 | NULL     |
|  2 | jiaojiao   |       | 2018-01-01 00:00:00 |          |    55 | NULL     |
|  3 | elf        |       | 2018-01-01 00:00:00 |          |   100 | shenzhen |
|  4 | 11111      |        | 2018-01-01 00:00:00 |          |    60 | shenzhen |
|  6 | 3333333    |       | 2018-01-01 00:00:00 |         |    77 | shenzhen |
|  7 | wuke       |       | 0000-00-00 00:00:00 |          |    80 | NULL     |
|  8 | Deft       |        | 2019-01-01 00:00:00 |          |    32 | NULL     |
|  9 | jiaoBo     |        | 2001-01-01 00:00:00 |          |    71 | NULL     |
| 10 | oojiaojiao |        | 2001-01-01 00:00:00 |          |    71 | NULL     |
+----+------------+--------+---------------------+----------+-------+----------+


mysql> create table score(
    -> id int auto_increment primary key not null,
    -> score decimal(4,1),
    -> stuid int,
    -> subid int,
    -> foreign key(stuid) references students(id),
    -> foreign key(subid) references subjects(id))
    -> ;
Query OK, 0 rows affected (0.02 sec)


mysql> desc score;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment |
| score | decimal(4,1) | YES  |     | NULL    |                |
| stuid | int(11)      | YES  | MUL | NULL    |                |
| subid | int(11)      | YES  | MUL | NULL    |                |
+-------+--------------+------+-----+---------+----------------+

查看原始的创建脚本

show create table score;


| score | CREATE TABLE `score` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `score` decimal(4,1) DEFAULT NULL,
  `stuid` int(11) DEFAULT NULL,
  `subid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `stuid` (`stuid`),
  KEY `subid` (`subid`),
  CONSTRAINT `score_ibfk_1` FOREIGN KEY (`stuid`) REFERENCES `students` (`id`),
  CONSTRAINT `score_ibfk_2` FOREIGN KEY (`subid`) REFERENCES `subjects` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 |

可以看到stuid和subid都是关联着各自表中的primary key

  • 思考:怎么保证关系列数据的有效性呢?任何整数都可以吗?
  • 答:必须是学生表中id列存在的数据,可以通过外键约束进行数据的有效性验证
  • 为stuid添加外键约束

可以和上面一样直接在创建表的时候创建外键约束,也可以alter添加

alter table scores add constraint stu_sco foreign key(stuid) references students(id);
  • 此时插入或者修改数据时,如果stuid的值在students表中不存在则会报错
  • 在创建表时可以直接创建约束

外键的级联操作)

例如删除students里面的一个学生,那么score里面已经有数据关联上,如何处理?

  • 在删除students表的数据时,如果这个id值在scores中已经存在,则会抛异常
  • 推荐使用逻辑删除,还可以解决这个问题
  • 可以创建表时指定级联操作,也可以在创建表后再修改外键的级联操作
  • 语法
alter table scores add constraint stu_sco foreign key(stuid) references students(id) on delete cascade;
  • 级联操作的类型包括:
    • restrict(限制):默认值,抛异常
    • cascade(级联):如果主表的记录删掉,则从表中相关联的记录都将被删除
    • set null:将外键设置为空
    • no action:什么都不做

删除约束


查看表建立语句

| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                   |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| score | CREATE TABLE `score` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `score` decimal(5,2) DEFAULT NULL,
  `stuid` int(11) DEFAULT NULL,
  `subid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `subid` (`subid`),
  KEY `stu_sco` (`stuid`),
  CONSTRAINT `stu_sco` FOREIGN KEY (`stuid`) REFERENCES `students` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 |


删除约束
alter table score drop foreign key stu_sco;

这时候就可以删除级联的表数据了,比如这个时候你删除了students表的数据,其他表有外键关联也没事,因为约束已经解除了,但是这个时候你要添加约束,就会报错,因为数据已经找不到了
alter table score add constraint stu_sco foreign key(stuid) references students(id);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`mikejing`.`#sql-15650_18`, CONSTRAINT `stu_sco` FOREIGN KEY (`stuid`) REFERENCES `students` (`id`))
mysql> delete from score where id = 4;
Query OK, 1 row affected (0.00 sec)

mysql> alter table score add constraint stu_sco foreign key(stuid) references students(id);
Query OK, 4 rows affected (0.05 sec)
Records: 4  Duplicates: 0  Warnings: 0

 

  • 问:查询每个学生每个科目的分数
  • 分析:学生姓名来源于students表,科目名称来源于subjects,分数来源于scores表,怎么将3个表放到一起查询,并将结果显示在同一个结果集中呢?
  • 答:当查询结果来源于多张表时,需要使用连接查询
  • 关键:找到表间的关系,当前的关系是
    • students表的id---scores表的stuid
    • subjects表的id---scores表的subid
  • 则上面问题的答案是:
select students.sname,subjects.stitle,scores.score
from scores
inner join students on scores.stuid=students.id
inner join subjects on scores.subid=subjects.id;
  • 结论:当需要对有关系的多张表进行查询时,需要使用连接join

inner join 连接查询

select *from score inner join students;

这是最基本的,如果score表10条和students表5条,因此在不加on条件下,组合起来是10*5=50条新的数据组合,然后根据on后面的组合筛选,比如下面的操作,id关联到的,因此自关联的表可以理解为 自身表条目的平方组合出来的数据进行筛选即可
 

实际上就是多个表链接成一个大表

  • 连接查询分类如下:
    • 表A inner join 表B:表A与表B匹配的行会出现在结果中
    • 表A left join 表B:表A与表B匹配的行会出现在结果中,外加表A中独有的数据,未对应的数据使用null填充
    • 表A right join 表B:表A与表B匹配的行会出现在结果中,外加表B中独有的数据,未对应的数据使用null填充
  • 在查询或条件中推荐使用“表名.列名”的语法
  • 如果多个表中列名不重复可以省略“表名.”部分
  • 如果表的名称太长,可以在表名后面使用' as 简写名'或' 简写名',为表起个临时的简写名称
  • 查询学生的姓名、平均分
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
group by students.sname;
  • 查询男生的姓名、总分
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
where students.gender=1
group by students.sname;
  • 查询科目的名称、平均分
select subjects.stitle,avg(scores.score)
from scores
inner join subjects on scores.subid=subjects.id
group by subjects.stitle;
  • 查询未删除科目的名称、最高分、平均分
select subjects.stitle,avg(scores.score),max(scores.score)
from scores
inner join subjects on scores.subid=subjects.id
where subjects.isdelete=0
group by subjects.stitle;
  • 嵌套查询
    第一个select from用的后面查询出来的表,需要给一个as别名,不然会报错
select sum(anum) from (select students.name,sum(score.score) as anum from score inner join students on score.stuid=students.id where gender=1 group by students.name) as MKJ;

完整的select语句

select distinct *
from 表名 inner |left|right|on join 表 on 关系
where ....
group by ... having ...
order by ...
limit star,count
  • 执行顺序为:
    • from 表名
    • where .... inner...
    • group by ...
    • select distinct *
    • having ...
    • order by ...
    • limit star,count
  • 实际使用中,只是语句中某些部分的组合,而不是全部

自关联

以省市县为例,这些数据不需要开多个表,可以通过自关联的方式完成,例如

id  title   pid
1   浙江     NULL
2   宁波      1(关联到自身表中另一行)
3   慈溪      2 (关联到自身表中另一行)
。。。。。

这种设计还有类似分类,一张表中可以无限数据,无限分类下去,充分利用空间 

 

  • 设计省信息的表结构provinces
    • id
    • ptitle
  • 设计市信息的表结构citys
    • id
    • ctitle
    • proid
  • citys表的proid表示城市所属的省,对应着provinces表的id值
  • 问题:能不能将两个表合成一张表呢?
  • 思考:观察两张表发现,citys表比provinces表多一个列proid,其它列的类型都是一样的
  • 意义:存储的都是地区信息,而且每种信息的数据量有限,没必要增加一个新表,或者将来还要存储区、乡镇信息,都增加新表的开销太大
  • 答案:定义表areas,结构如下
    • id
    • atitle
    • pid
  • 因为省没有所属的省份,所以可以填写为null
  • 城市所属的省份pid,填写省所对应的编号id
  • 这就是自关联,表中的某一列,关联了这个表中的另外一列,但是它们的业务逻辑含义是不一样的,城市信息的pid引用的是省信息的id
  • 在这个表中,结构不变,可以添加区县、乡镇街道、村社区等信息
  • 创建areas表的语句如下:
create table areas(
id int primary key,
atitle varchar(20),
pid int,
foreign key(pid) references areas(id)
);

视图sql语句的封装

  • 对于复杂的查询,在多次使用后,维护是一件非常麻烦的事情
  • 解决:定义视图
  • 视图本质就是对查询的一个封装
  • 定义视图
create view stuscore as 
select students.*,scores.score from scores
inner join students on scores.stuid=students.id;
  • 视图的用途就是查询
select * from stuscore;

事务

数据被更改时  insert  update delete 

  • 当一个业务逻辑需要多个sql完成时,如果其中某条sql语句出错,则希望整个操作都退回
  • 使用事务可以完成退回的功能,保证业务逻辑的正确性
  • 事务四大特性(简称ACID)
    • 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行
    • 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致
    • 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的
    • 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障
  • 要求:表的类型必须是innodb或bdb类型,才可以对此表使用事务
  • 查看表的创建语句
show create table students;
  • 修改表的类型
alter table '表名' engine=innodb;
  • 事务语句
开启begin;
提交commit;
回滚rollback;

事务可以理解为对同一个东西的修改操作,可以理解为OC里面的setter操作,多线程会抢资源,因此会有锁的存在,事务也是一样,通过锁来保证数据执行的一致性和隔离性,事务其实就通过锁在内存中开辟一个空间进行计算,通过commit或者rollback来确定是否需要采用之前的修改,如果其他线程也在操作数据库而且是操作同一条,就会出现锁等待,等commit或者rollback之后解锁继续执行

先做个浅显的理解,到时候深入了再来记录;

其实事务可以优化的点想到一个,比如你要插入很多条数据,直接执行insert语句不开启事务,其实每次都会对数据库的更改和提交操作,因此开启事务,再合理内存配置范围内,通过事务一次性提交更改物理数据库,减少损耗

事务引擎提交事务会开启行级锁

索引

Mysql 索引原理

Mysql索引使用方式介绍

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就可以得到索引的本质:索引是数据结构。

我们知道,数据库查询是数据库的最主要功能之一。我们都希望查询数据的速度能尽可能的快,因此数据库系统的设计者会从查询算法的角度进行优化。最基本的查询算法当然是顺序查找(linear search),这种复杂度为O(n)的算法在数据量很大时显然是糟糕的,好在计算机科学的发展提供了很多更优秀的查找算法,例如二分查找(binary search)、二叉树查找(binary tree search)等。如果稍微分析一下会发现,每种查找算法都只能应用于特定的数据结构之上,例如二分查找要求被检索数据有序,而二叉树查找只能应用于二叉查找树上,但是数据本身的组织结构不可能完全满足各种数据结构(例如,理论上不可能同时将两列都按顺序进行组织),所以,在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。

可以理解为数据本身的组织结构不可能满足各种数据结构,比如满足有序的二分查找或者二叉树查找,因此需要建立索引,把该字段或者多个字段下的所有数据都拉出来新建一个目录,满足数据结构查找,比如有序拉出来二分查找。

选择数据类型

  • 越小的数据类型和简单的数据类型越好,数据越小磁盘,内存,CPU中需要更少的空间,处理起来更快
  • 尽量避免NULL:应指定列为NOT NULL,除非你想存储NULL,在Mysql中,含有空值的列很难进行查询优化,因为他们使索引统计信息比较起来更复杂,应该用0,特殊的值,或者空串来标识

 

普通索引

普通索引仅有一个功能:加速查询

创建表

create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index ix_name (name)
)

创建

create index index_name on table_name(column_name)

查看

show index from table_name;

删除

drop index_name on table_name;

注意:对于创建索引时如果是BLOB 和 TEXT 类型,必须指定length。

create index ix_extra on in1(extra(32));

缺点

虽然索引提高了查询速度,但是会降低更新表的速度,如果对表进行INSERT UPDATE和DELETE,Mysql不仅要更新数据,还有保存更新索引文件,而且建立索引会占磁盘索引对应的文件

- 查看执行时间
    set profiling = 1;
    SQL...
    show profiles;

详细介绍可以看上面的文章

 

小例子

1、设计班级表,与学生表关联,并进行查询
2、设计分类表,自关联,并进行查询
3、创建视图存储上面的两个查询


# 班级表和学生表关联
1.班级表和学生表  班级表一条数据可以对应多条学生数据  1:n 因此关联外键设置在n这里
create table Class(
id int auto_increment primary key not null,
name varchar(10));


create table Student(
id int auto_increment primary key not null,
name varchar(10),
clsid int,
foreign key(clsid) references Class(id));


create view V_stu_class as
select Student.id,Student.name,Class.name as className 
from Student
inner join Class on Student.clsid=Class.id



# 自关联
create table typeClass(
id int auto_increment primary key not null,
name varchar(10),
pid int,
foreign key(pid) references typeClass(id));

create view V_types as
select son.*
from typeClass as father
inner join TypeClass as son on son.pid=father.id

 

Python3.6数据库操作Demo

首先Python3x之后需要安装 pymysql

In [1]: import os

In [2]: os.__file__
Out[2]: '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/os.py'

In [3]: 

以上目录能找到自带的安装包,我们执行

pip3 install pymysql

可以在该目录下找到site-packages文件夹,里面有我们自行安装的所有安装包,我们在cmd下面import会在该目录下自动查找,OK

配置PYCharm

但是我们用PYCharm的时候,你import你自行安装的包,是会报错的,告诉我们找不到该moduel,由于上不了图了,说下步骤

1.打开PYCharm,File  ------ Default Settings---------选择Project Interpreter,右侧会出现默认的配置环境

2.由于默认的环境不会加载site-packages,需要自己配置新的,点击齿轮,选择Add

3.这里的弹出框默认值不用管,只要把下面的Inherit global site-packages选上,第三方包就出现了

4.编译的时候右上角会出现对应的文件名选项,点击Edit Configuration选择对应的环境即可

以下是配置好之后的代码

逻辑代码

import pymysql

config = {
    'host':'192.168.0.61',
    'port':3306,
    'user':'root',
    'password':'mikejing',
    'db':'python',
    'charset':'utf8'
}
# 链接打开数据库
db = pymysql.connect(**config)

# 使用cousor() 创建一个游标对象 cursor
cursor = db.cursor()

# 使用excute执行sql语句
cursor.execute("SELECT VERSION()")

# 使用fetchone获取单条数据
data = cursor.fetchone()
print("Database version:%s"%data)


# sql = "insert into students (name) values('握草')"
# sql = "update students set name='框要是' where id=12"
# sql = "delete from students where id=12"
# data = input("请输入姓名:")
# sql = "insert into students (name) values(%s)"
# cursor.execute(sql, data)

sql = "select * from students where id=13"
cursor.execute(sql)
info = cursor.fetchone()
print(info)

sql = "select * from students"
cursor.execute(sql)
info1 = cursor.fetchall()
print(info1)

try:
    cursor.execute("show tables")
except Exception as result:
    print(result)

print(cursor.fetchall())

name =input("请输入修改后的名字:")
ids = input("请输入修改用户ID:")
params = [name,ids]
sql = "update students set name=%s where id=%s"
cursor.execute(sql,params)





# 默认开启事务,需要提交
db.commit()
cursor.close()
# 关闭数据库
db.close()

面向对象封装

对象

import pymysql

class MysqlHelper(object):
    def __init__(self,host, port, user, password, db, charset='utf8'):
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.db = db
        self.charset = charset

    def connect(self):
        self.con = pymysql.connect(host=self.host,port=self.port,user=self.user,password=self.password,db=self.db,charset=self.charset)
        self.cursor = self.con.cursor()

    def dealloc(self):
        self.con.close()
        self.cursor.close()

    def cud(self, sql, params):
        try:
            self.connect()
            self.cursor.execute(sql,params)
            self.con.commit()
            self.dealloc()
        except Exception as result:
            print(result)

    def watch(self, sql, params=[]):
        try:
            self.connect()
            self.cursor.execute(sql,params)
            result = self.cursor.fetchall()
            self.con.commit
            self.dealloc()
            return result
        except Exception as result:
            print("error:%s"%result)

使用

import MysqlHelper



helper = MysqlHelper.MysqlHelper('192.168.0.61', 3306, 'root', 'mikejing', 'python')

name = input("请输入修改后的名字:")
ids = input("请输入需要修改的用户id:")
params = (name, ids)
sql = "update students set name=%s where id=%s"

# 或者直接凭借
# sql = "update students set name=%s where id=%s"%(name, ids)

helper.cud(sql, params)


sql = "select * from students where id >20"
result = helper.watch(sql)
print(result)


/Users/mintou/venv/bin/python /Users/mintou/Desktop/PYCharm/tPython.py
请输入修改后的名字:29岁翻倍
请输入需要修改的用户id:30
((24, 'hehehe', b'\x00', datetime.datetime(1990, 1, 1, 0, 0), b'\x00', 100, 'cixi', 'www.ads.com'), (25, '我是神e', b'\x00', datetime.datetime(1990, 1, 1, 0, 0), b'\x00', 100, 'cixi', 'www.ads.com'), (26, 'iOS大神', b'\x00', datetime.datetime(1990, 1, 1, 0, 0), b'\x00', 100, 'cixi', 'www.ads.com'), (27, '宓珂璟', b'\x01', None, b'\x00', None, None, None), (28, 'python大神', b'\x01', None, b'\x00', None, None, None), (30, '29岁翻倍', b'\x01', None, b'\x00', None, None, None))

Process finished with exit code 0

登录Demo

还是用上面的MysqlHelper工具 用sha1试试

正常登录是RSA,用户在客户端输入密码,通过公钥加密给后台,后台私钥解密,加盐之后然后AES,接着存入数据库,就是注册

下次登录的时候,输入用户名密码,输入密码,公钥加密,后台私钥解密,然后根据用户名去数据库select,匹配上就登录成功

import MysqlHelper
import hashlib

helper = MysqlHelper.MysqlHelper('192.168.0.61', 3306, 'root', 'mikejing', 'python')

def sha1Operation(pwd):
    hash_pwd = pwd.encode("utf-8")
    hashTool = hashlib.sha1()
    hashTool.update(hash_pwd)
    return hashTool.hexdigest()

print("注册用户密码")
name = input("name:")
pwd = input("pwd:")
parmes = (name,sha1Operation(pwd))
sql = "insert into userinofs values(0,%s,%s)"
helper.cud(sql, parmes)

print("*"*50+"注册成功" + "*"*50)

while True:
    print("登录")
    name = input("name:")
    pwd = input("pwd:")
    parames = (name)
    sql = "select pwd from userinofs where username = %s"
    result = helper.watch(sql, parames)
    if len(result) == 0:
        print("用户名不存在")
    elif result[0][0] == sha1Operation(pwd):
        print("登录成功")
        break;
    else:
        print("密码错误")

 

 

参考文章

Python3各种模块安装(比如Mysql)

Mysql安装初始化

find命令

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值