MySQL数据库(3)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: MySQL数据库(3)

表操作

一般情况下,我们针对只要通过索引列去搜搜都可以 命中 索引(通过索引结构加速查找)。

但是,还是会有一些特殊的情况,让我们无法命中索引(即使创建了索引),这也是需要大家在开发中要注意的。

类型不一致

select * from big where name = 123;     -- 未命中
select * from big where email = 123;    -- 未命中
特殊的主键:
    select * from big where id = "123"; -- 命中

使用不等于

select * from big where name != "xx";              -- 未命中
select * from big where email != "wupeiqi@live.com";  -- 未命中
特殊的主键:
    select * from big where id != 123;  -- 命中

or,当or条件中有未建立索引的列才失效。

select * from big where id = 123 or password="xx";          -- 未命中
select * from big where name = "wupeiqi" or password="xx";  -- 未命中
特别的:
    select * from big where id = 10 or password="xx" and name="xx"; -- 命中

排序,当根据索引排序时候,选择的映射如果不是索引,则不走索引。

select * from big order by name asc;     -- 未命中
select * from big order by name desc;    -- 未命中
特别的主键:
    select * from big order by id desc;  -- 命中

like,模糊匹配时。

select * from big where name like "%u-12-19999";    -- 未命中
select * from big where name like "_u-12-19999";    -- 未命中
select * from big where name like "wu-%-10";        -- 未命中
特别的:
    select * from big where name like "wu-1111-%";  -- 命中
    select * from big where name like "wuw-%";      -- 命中

使用函数

select * from big where reverse(name) = "wupeiqi";  -- 未命中
特别的:
    select * from big where name = reverse("wupeiqi");  -- 命中

最左前缀,如果是联合索引,要遵循最左前缀原则。

如果联合索引为:(name,password)
    name and password       -- 命中
    name                    -- 命中
    password                -- 未命中
    name or password        -- 未命中

事务

innodb引擎中支持事务,myisam不支持。  


例如:xx给oo 转账 100,那就会涉及2个步骤。


xx账户 减100


oo账户 加 100


这两个步骤必须同时完成才算完成,并且如果第一个完成、第二步失败,还是回滚到初始状态。


事务,就是来解决这种情况的。 大白话:要成功都成功;要失败都失败。


事务的具有四大特性(ACID):

原子性(Atomicity)


原子性是指事务包含的所有操作不可分割,要么全部成功,要么全部失败回滚。

一致性(Consistency)


执行的前后数据的完整性保持一致。

隔离性(Isolation)


一个事务执行的过程中,不应该受到其他事务的干扰。

持久性(Durability)


事务一旦结束,数据就持久到数据库

begin;
update users set amount=amount-2 where id=1;
update users set amount=amount+2 where id=2;
commit;
import pymysql
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root123', charset="utf8", db='userdb')
cursor = conn.cursor()
# 开启事务
conn.begin()
try:
    cursor.execute("update users set amount=1 where id=1")
    int('asdf')
    cursor.execute("update tran set amount=2 where id=2")
except Exception as e:
    # 回滚
    print("回滚")
    conn.rollback()
else:
    # 提交
    print("提交")
    conn.commit()
cursor.close()
conn.close()

在用MySQL时,不知你是否会疑问:同时有很多做更新、插入、删除动作,MySQL如何保证数据不出错呢?


MySQL中自带了锁的功能,可以帮助我们实现开发过程中遇到的同时处理数据的情况。对于数据库中的锁,从锁的范围来讲有:


表级锁,即A操作表时,其他人对整个表都不能操作,等待A操作完之后,才能继续。


行级锁,即A操作表时,其他人对指定的行数据不能操作,其他行可以操作,等待A操作完之后,才能继续。


MYISAM支持表锁,不支持行锁;

InnoDB引擎支持行锁和表锁。


即:在MYISAM下如果要加锁,无论怎么加都会是表锁。

   在InnoDB引擎支持下如果是基于索引查询的数据则是行级锁,否则就是表锁。


在innodb引擎中,update、insert、delete的行为内部都会先申请锁(排它锁),申请到之后才执行相关操作,最后再释放锁。


所以,当多个人同时像数据库执行:insert、update、delete等操作时,内部加锁后会排队逐一执行。

而select则默认不会申请锁。

select * from xxx;

for update,排它锁,加锁之后,其他不可以读写。

begin; 
    select * from L1 where name="武沛齐" for update;    -- name列不是索引(表锁)
commit;
begin; -- 或者 start transaction;
    select * from L1 where id=1 for update;           -- id列是索引(行锁)
commit;

lock in share mode ,共享锁,加锁之后,其他可读但不可写。

begin; 
    select * from L1 where name="武沛齐" lock in share mode;    -- 假设name列不是索引(表锁)
commit;
begin; -- 或者 start transaction;
    select * from L1 where id=1 lock in share mode;           -- id列是索引(行锁)
commit;

排它锁

排它锁( for update),加锁之后,其他事务不可以读写。


应用场景:总共100件商品,每次购买一件需要让商品个数减1 。


A: 访问页面查看商品剩余 100

B: 访问页面查看商品剩余 100


此时 A、B 同时下单,那么他们同时执行SQL:

   update goods set count=count-1 where id=3

由于Innodb引擎内部会加锁,所以他们两个即使同一时刻执行,内部也会排序逐步执行。



但是,当商品剩余 1个时,就需要注意了。

A: 访问页面查看商品剩余 1

B: 访问页面查看商品剩余 1


此时 A、B 同时下单,那么他们同时执行SQL:

   update goods set count=count-1 where id=3

这样剩余数量就会出现 -1,很显然这是不正确的,所以应该怎么办呢?

-- 这种情况下,可以利用 排它锁,在更新之前先查询剩余数量,只有数量 >0 才可以购买,所以,下单时应该执行:
    begin; -- start transaction;
    select count from goods where id=3 for update;
    -- 获取个数进行判断
    if 个数>0:
        update goods set count=count-1 where id=3;
    else:
        -- 已售罄
    commit;
import pymysql
import threading
def task():
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root123', charset="utf8", db='userdb')
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    # cursor = conn.cursor()
    # 开启事务
    conn.begin()
    cursor.execute("select id,age from tran where id=2 for update")
    # fetchall      ( {"id":1,"age":10},{"id":2,"age":10}, )   ((1,10),(2,10))
    # {"id":1,"age":10}   (1,10)
    result = cursor.fetchone()
    current_age = result['age']
    if current_age > 0:
        cursor.execute("update tran set age=age-1 where id=2")
    else:
        print("已售罄")
    conn.commit()
    cursor.close()
    conn.close()
def run():
    for i in range(5):
        t = threading.Thread(target=task)
        t.start()
if __name__ == '__main__':
    run()

数据库连接池

import threading
import pymysql
from dbutils.pooled_db import PooledDB
MYSQL_DB_POOL = PooledDB(
    creator=pymysql,  # 使用链接数据库的模块
    maxconnections=5,  # 连接池允许的最大连接数,0和None表示不限制连接数
    mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
    maxcached=3,  # 链接池中最多闲置的链接,0和None不限制
    blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
    setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
    ping=0,
    # ping MySQL服务端,检查是否服务可用。
    # 如:0 = None = never, 1 = default = whenever it is requested, 
    # 2 = when a cursor is created, 4 = when a query is executed, 7 = always
    host='127.0.0.1',
    port=3306,
    user='root',
    password='root123',
    database='userdb',
    charset='utf8'
)
def task():
    # 去连接池获取一个连接
    conn = MYSQL_DB_POOL.connection()
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    cursor.execute('select sleep(2)')
    result = cursor.fetchall()
    print(result)
    cursor.close()
    # 将连接交换给连接池
    conn.close()
def run():
    for i in range(10):
        t = threading.Thread(target=task)
        t.start()
if __name__ == '__main__':
    run()

推荐使用上下文管理方式:

# db_context.py
import threading
import pymysql
from dbutils.pooled_db import PooledDB
POOL = PooledDB(
    creator=pymysql,  # 使用链接数据库的模块
    maxconnections=5,  # 连接池允许的最大连接数,0和None表示不限制连接数
    mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
    maxcached=3,  # 链接池中最多闲置的链接,0和None不限制
    blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
    setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
    ping=0,
    host='127.0.0.1',
    port=3306,
    user='root',
    password='root123',
    database='userdb',
    charset='utf8'
)
class Connect(object):
    def __init__(self):
        self.conn = conn = POOL.connection()
        self.cursor = conn.cursor(pymysql.cursors.DictCursor)
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.close()
        self.conn.close()
    def exec(self, sql, **kwargs):
        self.cursor.execute(sql, kwargs)
        self.conn.commit()
    def fetch_one(self, sql, **kwargs):
        self.cursor.execute(sql, kwargs)
        result = self.cursor.fetchone()
        return result
    def fetch_all(self, sql, **kwargs):
        self.cursor.execute(sql, kwargs)
        result = self.cursor.fetchall()
        return result
from db_context import Connect
with Connect() as obj:
    # print(obj.conn)
    # print(obj.cursor)
    ret = obj.fetch_one("select * from d1")
    print(ret)
    ret = obj.fetch_one("select * from d1 where id=%(id)s", id=3)
    print(ret)
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
10月前
|
供应链 数据库连接 PHP
反向海淘商业模式案例:Pandabuy VS Hoobuy VS CSSBUY 无货源淘宝微店代购系统搭建攻略
反向海淘是全球化下新兴的电商模式,满足海外消费者对中国高性价比商品的需求。Pandabuy、Hoobuy 和 CSSBUY 等平台整合供应链和物流资源,实现中国商品高效流通。本文分析这些平台商业模式,提供无货源代购系统搭建攻略及PHP代码示例,涵盖数据库连接、订单处理和商品查询等功能。随着市场需求增长、供应链优势、技术支持和政策利好,反向海淘前景广阔。
|
11月前
|
弹性计算 大数据 云计算
|
10月前
|
机器学习/深度学习 算法
《动量法:梯度下降算法的加速引擎》
动量法(Momentum)改进了梯度下降算法收敛慢、易震荡和陷入局部最优等问题。通过引入历史梯度信息,动量法加速了参数更新,使模型在平坦区域也能快速收敛。它平滑了更新方向,减少了高曲率区域的震荡,增强了逃离局部最优的能力。此外,动量法提高了优化效率,减少了迭代次数,并可与其他优化算法结合,进一步提升训练效果。总之,动量法显著改善了梯度下降的性能,成为深度学习中不可或缺的优化技术。
290 2
|
10月前
|
存储 移动开发 JavaScript
网页 HTML 自动播放下一首音乐
在 HTML5 中实现自动播放下一首音乐,通过管理音乐列表、操作音频元素和监听事件完成。创建包含多个音乐链接的列表,使用 `<audio>` 元素加载音乐,监听 `ended` 事件,在当前音乐结束时自动播放下一首。示例代码展示了如何使用 JavaScript 实现这一功能,确保无缝切换音乐。
|
11月前
|
存储 安全 BI
PeopleSoft中的文件上传与下载:实现与优化
PeopleSoft中的文件上传与下载:实现与优化
331 7
|
9月前
|
监控 中间件 关系型数据库
课时8:阿里云互联网中间件:让企业实现业务云化持续创新
阿里云互联网中间件包含EDAS、DRDS、MQ、ARMS和CSB五大核心产品,为企业提供稳定高效的分布式应用服务。历经阿里巴巴多年打磨,支持海量并发与复杂架构,助力企业轻松实现业务云化及持续创新。通过这些中间件,企业可以高效开发、托管分布式应用,应对不确定的业务需求,推动数字化转型。
308 0
|
10月前
|
算法 小程序 API
2025年最新蓝牙Beacon技术深度剖析与停车场定位导航实战指南
本文通过分析蓝牙Beacon技术工作原理、停车场定位导航硬件部署、蓝牙信号平滑处理等,旨在剖析蓝牙Beacon技术在停车场定位导航系统中的实际应用与优势,迅速定位空闲车位,提供反向寻车功能,并优化停车场管理流程,有效解决大型停车场中的找车位难题。如需获取详细解决方案可前往文章最下方获取,如有项目需求及技术合作可私信作者。
717 0
|
12月前
|
存储 算法 决策智能
《C 语言下模拟退火算法于组合优化的应用要点全解析》
组合优化问题是计算机科学与数学的交叉领域中的研究热点。模拟退火算法作为一种基于概率的随机搜索方法,通过模拟固体退火过程,能够在解空间中高效寻找全局最优或近似最优解。本文探讨了用C语言实现模拟退火算法的关键步骤,包括算法原理、数据结构设计、温度参数控制、邻域生成与搜索策略、接受准则、终止条件及性能评估与调优,旨在为解决组合优化问题提供有效途径。
240 11
|
传感器
水传感器的技术原理有哪些
水传感器通过多种技术原理检测水质,包括电导率测量、光学感应、化学反应和生物传感等方法,可监测pH值、溶解氧、浊度等参数。
|
关系型数据库 测试技术 分布式数据库