多線程與MySQL(十)


1.1 多線程

在傳統操作系統中,每個進程有一個地址空間,而且默認就有一個控制線程

  線程顧名思義,就是一條流水線工作的過程,一條流水線必須屬於一個車間,一個車間的工作過程是一個進程

    車間負責把資源整合到一起,是一個資源單位,而一個車間內至少有一個流水線

    流水線的工作需要電源,電源就相當於cpu

  所以,進程只是用來把資源集中到一起(進程只是一個資源單位,或者說資源集合),而線程才是cpu上的執行單位。

  多線程(即多個控制線程)的概念是,在一個進程中存在多個控制線程,多個控制線程共享該進程的地址空間,相當於一個車間內有多條流水線,都共用一個車間的資源。

     例如,北京地鐵與上海地鐵是不同的進程,而北京地鐵里的13號線是一個線程,北京地鐵所有的線路共享北京地鐵所有的資源,比如所有的乘客可以被所有線路拉。

l  創建進程的開銷要遠大於線程?

如果我們的軟件是一個工廠,該工廠有多條流水線,流水線工作需要電源,電源只有一個即cpu(單核cpu),一個車間就是一個進程,一個車間至少一條流水線(一個進程至少一個線程),創建一個進程,就是創建一個車間(申請空間,在該空間內建至少一條流水線),而建線程,就只是在一個車間內造一條流水線,無需申請空間,所以創建開銷小

l  進程之間是競爭關系,線程之間是協作關系?

車間直接是競爭/搶電源的關系,競爭(不同的進程直接是競爭關系,是不同的程序員寫的程序運行的,迅雷搶占其他進程的網速,360把其他進程當做病毒干死),一個車間的不同流水線式協同工作的關系(同一個進程的線程之間是合作關系,是同一個程序寫的程序內開啟動,迅雷內的線程是合作關系,不會自己干自己)

1.1.1 為何要用多線程

  多線程指的是,在一個進程中開啟多個線程,簡單的講:如果多個任務共用一塊地址空間,那么必須在一個進程內開啟多個線程。詳細的講分為4點:

  1. 多線程共享一個進程的地址空間

    2. 線程比進程更輕量級,線程比進程更容易創建可撤銷,在許多操作系統中,創建一個線程比創建一個進程要快10-100倍,在有大量線程需要動態和快速修改時,這一特性很有用

    3. 若多個線程都是cpu密集型的,那么並不能獲得性能上的增強,但是如果存在大量的計算和大量的I/O處理,擁有多個線程允許這些活動彼此重疊運行,從而會加快程序執行的速度。

4. 在多cpu系統中,為了最大限度的利用多核,可以開啟多個線程,比開進程開銷要小的多。(這一條並不適用於python)

 

 

 

1.2 死鎖現象與遞歸鎖

進程也有死鎖與遞歸鎖。

所謂死鎖: 是指兩個或兩個以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。

  遞歸鎖,在Python中為了支持在同一線程中多次請求同一資源,python提供了可重入鎖RLock,

這個RLock內部維護着一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。上面的例子如果使用RLock代替Lock,則不會發生死鎖:

 

from threading import Thread,Lock,RLock

import time

 

# mutexA=Lock()

# mutexB=Lock()

 

mutexA=mutexB=RLock()  #一個線程拿到鎖,counter加1,該線程內又碰到加鎖的情況,則counter繼續加1,這期間所有其他線程都只能等待,等待該線程釋放所有鎖,即counter遞減到0為止

 

class MyThread(Thread):

    def run(self):

        self.f1()

        self.f2()

 

    def f1(self):

        mutexA.acquire()

        print('%s 拿到了A鎖' %self.name)

 

        mutexB.acquire()

        print('%s 拿到了B鎖' % self.name)

        mutexB.release() #1

 

        mutexA.release() #0

 

    def f2(self):

        mutexB.acquire()

        print('%s 拿到了B鎖' % self.name)

        time.sleep(0.1)

 

        mutexA.acquire()

        print('%s 拿到了A鎖' % self.name)

        mutexA.release()

 

        mutexB.release()

 

 

 

if __name__ == '__main__':

    for i in range(10):

        t=MyThread()

        t.start()

 

 

1.3 信號量Semaphore

同進程的一樣,Semaphore管理一個內置的計數器,每當調用acquire()時內置計數器-1;調用release() 時內置計數器+1;計數器不能小於0;當計數器為0時,acquire()將阻塞線程直到其他線程調用release()。

實例:(同時只有5個線程可以獲得semaphore,即可以限制最大連接數為5):

from threading import Thread,Semaphore,current_thread

import time,random

 

sm=Semaphore(5)

 

def task():

    with sm:

        print('%s is laing' %current_thread().getName())

        time.sleep(random.randint(1,3))

 

if __name__ == '__main__':

    for i in range(20):

        t=Thread(target=task)

        t.start()

 

與進程池是完全不同的概念,進程池Pool(4),最大只能產生4個進程,而且從頭到尾都只是這四個進程,不會產生新的,而信號量是產生一堆線程/進程

1.4 Event事件

同進程的一樣,線程的一個關鍵特性是每個線程都是獨立運行且狀態不可預測。如果程序中的其 他線程需要通過判斷某個線程的狀態來確定自己下一步的操作,這時線程同步問題就會變得非常棘手。為了解決這些問題,我們需要使用threading庫中的Event對象。 對象包含一個可由線程設置的信號標志,它允許線程等待某些事件的發生。在 初始情況下,Event對象中的信號標志被設置為假。如果有線程等待一個Event對象, 而這個Event對象的標志為假,那么這個線程將會被一直阻塞直至該標志為真。一個線程如果將一個Event對象的信號標志設置為真,它將喚醒所有等待這個Event對象的線程。如果一個線程等待一個已經被設置為真的Event對象,那么它將忽略這個事件, 繼續執行

event.isSet():返回event的狀態值;

 

event.wait():如果 event.isSet()==False將阻塞線程;

 

event.set(): 設置event的狀態值為True,所有阻塞池的線程激活進入就緒狀態, 等待操作系統調度;

 

event.clear():恢復event的狀態值為False。

 

 

例如,有多個工作線程嘗試鏈接MySQL,我們想要在鏈接前確保MySQL服務正常才讓那些工作線程去連接MySQL服務器,如果連接不成功,都會去嘗試重新連接。那么我們就可以采用threading.Event機制來協調各個工作線程的連接操作

from threading import Thread,Event,current_thread

import time

 

event=Event()

 

def check():

    print('checking MySQL...')

    time.sleep(5)

    event.set()

 

def conn():

    count=1

    while not event.is_set():

        if count > 3:

            raise TimeoutError('超時')

        print('%s try to connect MySQL time %s' %(current_thread().getName(),count))

        event.wait(1)

        count+=1

 

    print('%s connected MySQL' %current_thread().getName())

 

if __name__ == '__main__':

    t1=Thread(target=check)

    t2=Thread(target=conn)

    t3=Thread(target=conn)

    t4=Thread(target=conn)

 

 

    t1.start()

    t2.start()

    t3.start()

    t4.start()

 

 

1.5 定時器

定時器,指定n秒后執行某操作

from threading import Timer

 

 

def hello(name):

    print("hello, world %s " %name)

 

 

t = Timer(3, hello,args=('egon',))

t.start()  # after 1 seconds, "hello, world" will be printed

 

 

1.6 線程queue

queue隊列 :使用import queue,用法與進程Queue一樣

import queue

 

q=queue.Queue(3) #隊列:先進先出

 

q.put(1)

q.put(2)

q.put(3)

# q.put(4)

# q.put_nowait(4)

# q.put(4,block=False)

q.put(4,block=True,timeout=3)

 

 

# print(q.get())

# print(q.get())

# print(q.get())

 

q=queue.LifoQueue(3) #堆棧:后進先出

q.put(1)

q.put(2)

q.put(3)

 

print(q.get())

print(q.get())

print(q.get())

 

q=queue.PriorityQueue(3) #優先級隊列

q.put((10,'a'))

q.put((-3,'b'))

q.put((100,'c'))

 

print(q.get())

print(q.get())

print(q.get())

 

 

 

1.7 進程池線程池

#提交任務的兩種方式:

#同步調用:提交完任務后,就在原地等待,等待任務執行完畢,拿到任務的返回值,才能繼續下一行代碼,導致程序串行執行

#異步調用+回調機制:提交完任務后,不在原地等待,任務一旦執行完畢就會觸發回調函數的執行, 程序是並發執行

 

#進程的執行狀態:

#阻塞

#非阻塞

 

 

1.7.1 同步調用示例:

# from multiprocessing import Pool

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

import time,random,os

 

def task(n):

    print('%s is ruuning' %os.getpid())

    time.sleep(random.randint(1,3))

    return n**2

 

def handle(res):

    print('handle res %s' %res)

 

if __name__ == '__main__':

    #同步調用

    pool=ProcessPoolExecutor(2)

 

    for i in range(5):

        res=pool.submit(task,i).result()

        # print(res)

        handle(res)

 

    pool.shutdown(wait=True)

    # pool.submit(task,33333)

    print('')

 

 

 

1.7.2 異步調用示例:

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

import time,random,os

 

def task(n):

    print('%s is ruuning' %os.getpid())

    time.sleep(random.randint(1,3))

    # res=n**2

    # handle(res)

    return n**2

 

def handle(res):

    res=res.result()

    print('handle res %s' %res)

 

if __name__ == '__main__':

    #異步調用

    pool=ProcessPoolExecutor(2)

 

    for i in range(5):

        obj=pool.submit(task,i)

        obj.add_done_callback(handle) #handle(obj)

 

    pool.shutdown(wait=True)

    print('')

 

 

 

1.7.3 線程池

from concurrent.futures import ThreadPoolExecutor

from threading import current_thread

import requests

import time

 

def get(url):

    print('%s GET %s' %(current_thread().getName(),url))

    response=requests.get(url)

    time.sleep(2)

    if response.status_code == 200:

        return {'url':url,'content':response.text}

 

def parse(res):

    res=res.result()

    print('parse:[%s] res:[%s]' %(res['url'],len(res['content'])))

 

 

if __name__ == '__main__':

    pool=ThreadPoolExecutor(2)

 

    urls=[

        'https://www.baidu.com',

        'https://www.python.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

    ]

    for url in urls:

        pool.submit(get,url).add_done_callback(parse)

 

    pool.shutdown(wait=True)

 

 

1.8 協程

單純地切換反而會降低運行效率

協程:是單線程下的並發,又稱微線程,纖程。英文名Coroutine。一句話說明什么是線程:協程是一種用戶態的輕量級線程,即協程是由用戶程序自己控制調度的。

總結協程特點:

必須在只有一個單線程里實現並發

修改共享數據不需加鎖

用戶程序里自己保存多個控制流的上下文棧

附加:一個協程遇到IO操作自動切換到其它協程(如何實現檢測IO,yield、greenlet都無法實現,就用到了gevent模塊(select機制))

1.8.1 串行執行

import time

def consumer(res):

    '''任務1:接收數據,處理數據'''

    pass

 

def producer():

    '''任務2:生產數據'''

    res=[]

    for i in range(10000000):

        res.append(i)

    return res

 

start=time.time()

#串行執行

res=producer()

consumer(res)

stop=time.time()

print(stop-start)

 

 

 

 

1.8.2 基於yield並發執行

import time

def consumer():

    '''任務1:接收數據,處理數據'''

    while True:

        print('consumer')

        x=yield

        time.sleep(100)

 

def producer():

    '''任務2:生產數據'''

    g=consumer()

    next(g)

    for i in range(10000000):

        print('producer')

        g.send(i)

 

start=time.time()

#基於yield保存狀態,實現兩個任務直接來回切換,即並發的效果

#PS:如果每個任務中都加上打印,那么明顯地看到兩個任務的打印是你一次我一次,即並發執行的.

producer()

 

stop=time.time()

print(stop-start) #

 

 

1.9 greenlet模塊

如果我們在單個線程內有20個任務,要想實現在多個任務之間切換,使用yield生成器的方式過於麻煩(需要先得到初始化一次的生成器,然后再調用send。。。非常麻煩),而使用greenlet模塊可以非常簡單地實現這20個任務直接的切換

安裝模塊

pip3 install greenlet

 

 

from greenlet import greenlet

import time

 

def eat(name):

    print('%s eat 1' %name)

    time.sleep(1000)

    g2.switch('egon')

    print('%s eat 2' %name)

    g2.switch()

 

 

def play(name):

    print('%s play 1' % name)

    g1.switch()  #可以在第一次switch時傳入參數,以后都不需要

    print('%s play 2' % name)

 

g1=greenlet(eat)

g2=greenlet(play)

 

greenlet只是提供了一種比generator更加便捷的切換方式,當切到一個任務執行時如果遇到io,那就原地阻塞,仍然是沒有解決遇到IO自動切換來提升效率的問題。

單線程里的這20個任務的代碼通常會既有計算操作又有阻塞操作,我們完全可以在執行任務1時遇到阻塞,就利用阻塞的時間去執行任務2。。。。如此,才能提高效率,這就用到了Gevent模塊。

1.10 gevent模塊

Gevent 是一個第三方庫,可以輕松通過gevent實現並發同步或異步編程,在gevent中用到的主要模式是Greenlet, 它是以C擴展模塊形式接入Python的輕量級協程。 Greenlet全部運行在主程序操作系統進程的內部,但它們被協作式地調度。

#用法

g1=gevent.spawn(func,1,,2,3,x=4,y=5)創建一個協程對象g1,spawn括號內第一個參數是函數名,如eat,后面可以有多個參數,可以是位置實參或關鍵字實參,都是傳給函數eat的

 

g2=gevent.spawn(func2)

 

g1.join() #等待g1結束

 

g2.join() #等待g2結束

 

#或者上述兩步合作一步:gevent.joinall([g1,g2])

 

g1.value#拿到func1的返回值

 

 

from gevent import monkey;monkey.patch_all()

import gevent

import time

 

def eat(name):

    print('%s eat 1' %name)

    # gevent.sleep(3)

    time.sleep(3)

    print('%s eat 2' %name)

 

 

def play(name):

    print('%s play 1' % name)

    # gevent.sleep(2)

    time.sleep(3)

    print('%s play 2' % name)

 

g1=gevent.spawn(eat,'egon')

g2=gevent.spawn(play,'alex')

# gevent.sleep(1)

 

# g1.join()

# g2.join()

gevent.joinall([g1,g2])

 

練習

通過gevent實現單線程下的socket並發(from gevent import monkey;monkey.patch_all()一定要放到導入socket模塊之前,否則gevent無法識別socket的阻塞)

服務端

from gevent import monkey,spawn;monkey.patch_all()

from threading import current_thread

from socket import *

 

def comunicate(conn):

    print('子線程:%s' %current_thread().getName())

    while True:

        try:

            data=conn.recv(1024)

            if not data:break

            conn.send(data.upper())

        except ConnectionResetError:

            break

    conn.close()

 

def server(ip,port):

    print('主線程:%s' %current_thread().getName())

    server = socket(AF_INET, SOCK_STREAM)

    server.bind((ip,port))

    server.listen(5)

 

    while True:

        conn, addr = server.accept()

        print(addr)

        # comunicate(conn)

        # t=Thread(target=comunicate,args=(conn,))

        # t.start()

        spawn(comunicate,conn)

 

    server.close()

 

if __name__ == '__main__':

    g=spawn(server,'127.0.0.1', 8081)

    g.join()

 

 

客戶端

多線程並發多個客戶端

from socket import *

from threading import current_thread,Thread

 

def client():

    client=socket(AF_INET,SOCK_STREAM)

    client.connect(('127.0.0.1',8081))

 

    while True:

        client.send(('%s say hello' %current_thread().getName()).encode('utf-8'))

        data=client.recv(1024)

        print(data.decode('utf-8'))

 

    client.close()

 

if __name__ == '__main__':

    for i in range(500):

        t=Thread(target=client)

        t.start()

 

 

 

1.11 MySQL數據庫相關概念

MySQL是一個關系型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下公司。MySQL 最流行的關系型數據庫管理系統,在 WEB 應用方面MySQL是最好的 RDBMS (Relational Database Management System,關系數據庫管理系統) 應用軟件之一。

1、數據庫服務器:計算機

2、數據庫管理軟件:MySQL

3、數據庫/庫:文件夾

4、表:文件

5、記錄:一個事物的一系列典型的特征:egon,male,18,oldgirl

6、數據:事物的特征,sex='male'

1.11.1 mysql是什么

#mysql就是一個基於socket編寫的C/S架構的軟件

#客戶端軟件

  mysql自帶:如mysql命令,mysqldump命令等

  python模塊:如pymysql

 

1.11.2 數據庫管理軟件分類

#分兩大類:

  關系型:如sqllite,db2,oracle,access,sql server,MySQL,注意:sql語句通用

  非關系型:mongodb,redis,memcache

#可以簡單的理解為:

    關系型數據庫需要有表結構

    非關系型數據庫是key-value存儲的,沒有表結構

1.11.3 下載安裝

1.11.3.1  Linux版本

一、二進制rpm包安裝

yum -y install mysql-server mysql

 

 

二、源碼安裝

1.解壓tar包

cd /software

tar -xzvf mysql-5.6.21-linux-glibc2.5-x86_64.tar.gz

mv mysql-5.6.21-linux-glibc2.5-x86_64 mysql-5.6.21

 

 

2.添加用戶與組

groupadd mysql

useradd -r -g mysql mysql

chown -R mysql:mysql mysql-5.6.21

 

 

3.安裝數據庫

su mysql

cd mysql-5.6.21/scripts

./mysql_install_db --user=mysql --basedir=/software/mysql-5.6.21 --datadir=/software/mysql-5.6.21/data

 

 

4.配置文件

cd /software/mysql-5.6.21/support-files

cp my-default.cnf /etc/my.cnf

cp mysql.server /etc/init.d/mysql

vim /etc/init.d/mysql   #若mysql的安裝目錄是/usr/local/mysql,則可省略此步

修改文件中的兩個變更值

basedir=/software/mysql-5.6.21

datadir=/software/mysql-5.6.21/data

 

 

5.配置環境變量

vim /etc/profile

export MYSQL_HOME="/software/mysql-5.6.21"

export PATH="$PATH:$MYSQL_HOME/bin"

source /etc/profile

 

 

6.添加自啟動服務

chkconfig --add mysql

chkconfig mysql on

 

 

7.啟動mysql

service mysql start

 

 

8.登錄mysql及改密碼與配置遠程訪問

mysqladmin -u root password 'your_password'     #修改root用戶密碼

mysql -u root -p     #登錄mysql,需要輸入密碼

mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_password' WITH GRANT OPTION;     #允許root用戶遠程訪問

mysql>FLUSH PRIVILEGES;     #刷新權限

 

 

三、源碼安裝mariadb

1. 解壓
tar zxvf  mariadb-5.5.31-linux-x86_64.tar.gz  

mv mariadb-5.5.31-linux-x86_64 /usr/local/mysql //必需這樣,很多腳本或可執行程序都會直接訪問這個目錄

 

 
2. 權限
groupadd mysql             //增加 mysql 屬組

useradd -g mysql mysql     //增加 mysql 用戶 並歸於mysql 屬組

chown mysql:mysql -Rf  /usr/local/mysql    // 設置 mysql 目錄的用戶及用戶組歸屬。

chmod +x -Rf /usr/local/mysql    //賜予可執行權限

 

 
3. 拷貝配置文件
cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf     //復制默認mysql配置 文件到/etc目錄

 

 
4. 初始化
/usr/local/mysql/scripts/mysql_install_db --user=mysql          //初始化數據庫

cp  /usr/local/mysql/support-files/mysql.server    /etc/init.d/mysql    //復制mysql服務程序 到系統目錄

chkconfig  mysql on     //添加mysql 至系統服務並設置為開機啟動

service  mysql  start  //啟動mysql

 

 
5. 環境變量配置
vim /etc/profile   //編輯profile,將mysql的可執行路徑加入系統PATH

export PATH=/usr/local/mysql/bin:$PATH

source /etc/profile  //使PATH生效。

 

 
6. 賬號密碼
mysqladmin -u root password 'yourpassword' //設定root賬號及密碼

mysql -u root -p  //使用root用戶登錄mysql

use mysql  //切換至mysql數據庫。

select user,host,password from user; //查看系統權限

drop user ''@'localhost'; //刪除不安全的賬戶

drop user root@'::1';

drop user root@127.0.0.1;

select user,host,password from user; //再次查看系統權限,確保不安全的賬戶均被刪除。

flush privileges;  //刷新權限

 

 
7. 一些必要的初始配置
1)修改字符集為UTF8
vi /etc/my.cnf

在[client]下面添加 default-character-set = utf8

在[mysqld]下面添加 character_set_server = utf8

 

2)增加錯誤日志

vi /etc/my.cnf

在[mysqld]下面添加:

log-error = /usr/local/mysql/log/error.log

general-log-file = /usr/local/mysql/log/mysql.log

3) 設置為不區分大小寫,linux下默認會區分大小寫。

vi /etc/my.cnf

在[mysqld]下面添加:

lower_case_table_name=1 
修改完重啟:
service  mysql  restart

 

 

1.11.3.2  Window版本

安裝

#1、下載:MySQL Community Server 5.7.16

http://dev.mysql.com/downloads/mysql/

 

#2、解壓

如果想要讓MySQL安裝在指定目錄,那么就將解壓后的文件夾移動到指定目錄,如:C:\mysql-5.7.16-winx64

 

#3、添加環境變量

【右鍵計算機】--》【屬性】--》【高級系統設置】--》【高級】--》【環境變量】--》【在第二個內容框中找到 變量名為Path 的一行,雙擊】 --> 【將MySQL的bin目錄路徑追加到變值值中,用 ; 分割】

 

#4、初始化

mysqld --initialize-insecure

 

 

#5、啟動MySQL服務

mysqld # 啟動MySQL服務

 

 

#6、啟動MySQL客戶端並連接MySQL服務

mysql -u root -p # 連接MySQL服務器

 

 

將MySQL服務制作成windows服務

上一步解決了一些問題,但不夠徹底,因為在執行【mysqd】啟動MySQL服務器時,當前終端會被hang住,那么做一下設置即可解決此問題:
注意:--install前,必須用mysql啟動命令的絕對路徑
# 制作MySQL的Windows服務,在終端執行此命令:
"c:\mysql-5.7.16-winx64\bin\mysqld" --install

 

 
# 移除MySQL的Windows服務,在終端執行此命令:
"c:\mysql-5.7.16-winx64\bin\mysqld" --remove

 

注冊成服務之后,以后再啟動和關閉MySQL服務時,僅需執行如下命令:
# 啟動MySQL服務
net start mysql

 

# 關閉MySQL服務
net stop mysql

 

 

1.12 重置密碼

1.12.1 設置密碼

C:\Users\Administrator> mysqladmin -uroot -p password "123"

 

 

1.12.2 重置密碼

net stop MySQL

mysqld --skip-grant-tables

mysql -uroot -p

    update mysql.user set password=password("") where user='root' and host="localhost";

    flush privileges;

 

C:\Users\Administrator>tasklist |findstr mysql

mysqld.exe                    6316 Console                    1    454,544 K

 

C:\Users\Administrator>taskkill /F /PID 6316

成功: 已終止 PID 為 6316 的進程。

 

C:\Users\Administrator>net start MySQL

MySQL 服務正在啟動 .

MySQL 服務已經啟動成功。

 

 

1.13 統一字符編碼

#1. 修改配置文件

[mysqld]

default-character-set=utf8

[client]

default-character-set=utf8

[mysql]

default-character-set=utf8

 

#mysql5.5以上:修改方式有所改動

[mysqld]

character-set-server=utf8

collation-server=utf8_general_ci

[client]

default-character-set=utf8

[mysql]

default-character-set=utf8

 

 

#2. 重啟服務

#3. 查看修改結果:

mysql> \s

show variables like '%char%'

 

 

1.14 初識SQL

有了mysql這個數據庫軟件,就可以將程序員從對數據的管理中解脫出來,專注於對程序邏輯的編寫

mysql服務端軟件即mysqld幫我們管理好文件夾以及文件,前提是作為使用者的我們,需要下載mysql的客戶端,或者其他模塊來連接到mysqld,然后使用mysql軟件規定的語法格式去提交自己命令,實現對文件夾或文件的管理。該語法即sql(Structured Query Language 即結構化查詢語言)

SQL語言主要用於存取數據、查詢數據、更新數據和管理關系數據庫系統,SQL語言由IBM開發。SQL語言分為3種類型:

#1、DDL語句    數據庫定義語言: 數據庫、表、視圖、索引、存儲過程,例如CREATE DROP ALTER

#2、DML語句    數據庫操縱語言: 插入數據INSERT、刪除數據DELETE、更新數據UPDATE、查詢數據SELECT

#3、DCL語句    數據庫控制語言: 例如控制用戶的訪問權限GRANT、REVOKE

 

1.14.1 操作文件夾(庫)

1.14.1.1  增

create database db1 charset utf8;

 

1.14.1.2  查

show databases;

show create database db1;

 

1.14.1.3  改

alter database db1 charset gbk;

 

1.14.1.4  刪

drop database db1;

 

 

1.14.2 操作文件(表)

1.14.2.1  查看當前所在的文件夾:

select database();

 

1.14.2.2  切換文件夾:

use db1;

 

1.14.2.3  增

create table t1(id int,name char);

 

1.14.2.4  查

show tables;

show create table t1;

desc t1;

 

1.14.2.5  改

alter table t1 add sex char;

alter table t1 drop sex;

alter table t1 modify name char(16);

alter table t1 change name Name char(13);

 

1.14.2.6  刪

drop table t1;

 

 

1.14.3 操作文件的內容(記錄)

1.14.3.1  增

insert into db1.t1 values

 (1,'egon'),

 (2,'alex'),

 (3,'wxx');

 

1.14.3.2  查

select id,name from db1.t1;

select * from db1.t1;

 

1.14.3.3  改

update t1 set name='SB' where id=2;

 

1.14.3.4  刪

delete from t1 where id=2;

 

 

1.15 存儲引擎

儲引擎即表類型,mysql根據不同的表類型會有不同的處理機制

查看引擎

show engines;

 

創建引擎

create table t1(id int)engine=innodb;

create table t2(id int)engine=myisam;

create table t3(id int)engine=memory;

create table t4(id int)engine=blackhole;

 

 

1.16 數值類型

1.16.1 整型(默認有符號)

create table t8(n tinyint);

insert into t8 values(-1);

insert into t8 values(128);

insert into t8 values(-129);

 

create table t9(n tinyint unsigned);

insert into t9 values(-1),(256);

 

 

#整型的寬度代表顯示寬度

create table t11(n int(3) unsigned zerofill);

create table t12(n int unsigned zerofill);

 

create table t13(

    id int

);

 

 

 

 

 

1.16.2 浮點型

create table t13(x float(255,30));

create table t14(x double(255,30));

create table t15(x decimal(65,30));

 

 

insert into t13 values(1.111111111111111111111111111111);

insert into t14 values(1.111111111111111111111111111111);

insert into t15 values(1.111111111111111111111111111111);

 

 

1.17 日期類型

create table student(

    id int,

    name char(16),

    born_year year,

    birth_date date,

    class_time time,

    reg_time datetime

);

 

insert into student values

(1,'egon',now(),now(),now(),now())

;

 

insert into student values

(2,'alex','1999','1999-11-11','11:11:11',"1999-11-11 11:11:11")

 

 

1.18 字符類型

char:定長

varchar:變長

 

#寬度代表的是字符的個數

create table t16(name char(5));

create table t17(name varchar(5));

 

insert into t16 values('李傑 '); #'李傑   '

insert into t17 values('李傑 '); #'李傑 '

 

select char_length(name) from t16; #5

select char_length(name) from t17; #3

 

mysql> set sql_mode='PAD_CHAR_TO_FULL_LENGTH';

 

select * from t16 where name='李傑';

select * from t17 where name='李傑';

 

select * from t16 where name like '李傑';

 

name char(5)

egon |alex |wxx  |

 

 

name varchar(5)

1bytes+egon|1bytes+alex|1bytes+wxx|

 

1.19 枚舉類型與集合類型

create table employee(

    id int,

    name char(10),

    sex enum('male','female','other'),

    hobbies set('play','eat','music','read')

);

 

insert into employee values

(1,'egon','male','music,read');

 

insert into employee values

(2,'alex','xxxx','music,read');

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM