1、整理今天所學(xué)的知識(shí)點(diǎn)
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
1.主從復(fù)制
基本步驟:
1. 在主服務(wù)器上,必須開啟二進(jìn)制日志機(jī)制和配置一個(gè)獨(dú)立的ID
2. 在每一個(gè)從服務(wù)器上,配置一個(gè)唯一的ID,創(chuàng)建一個(gè)用來專門復(fù)制主服務(wù)器數(shù)據(jù)的賬號(hào)
3. 在開始復(fù)制進(jìn)程前,在主服務(wù)器上記錄二進(jìn)制文件的位置信息
4. 如果在開始復(fù)制之前,數(shù)據(jù)庫中已經(jīng)有數(shù)據(jù),就必須先創(chuàng)建一個(gè)數(shù)據(jù)快照(可以使用mysqldump導(dǎo)出數(shù)據(jù)庫,或者直接復(fù)制數(shù)據(jù)文件)
5. 配置從服務(wù)器要連接的主服務(wù)器的IP地址和登陸授權(quán),二進(jìn)制日志文件名和位置
在主服務(wù)器Ubuntu上進(jìn)行備份,執(zhí)行命令:
mysqldump -uroot -pmysql --all-databases --lock-all-tables > ~/master_db.sql
說明
-u :用戶名
-p :示密碼
--all-databases :導(dǎo)出所有數(shù)據(jù)庫
--lock-all-tables :執(zhí)行操作時(shí)鎖住所有表,防止操作時(shí)有數(shù)據(jù)修改
~/master_db.sql :導(dǎo)出的備份數(shù)據(jù)(sql文件)位置,可自己指定
在從服務(wù)器Windows上進(jìn)行數(shù)據(jù)還原
登陸數(shù)據(jù)庫,然后運(yùn)行
source master_db.sql
配置主服務(wù)器master(Ubuntu中的MySQL)
編輯設(shè)置mysqld的配置文件,設(shè)置log_bin和server-id
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
在最后添加這兩句代碼
server-id = 1
log_bin = master-bin

重啟服務(wù)器(修改配置都要重新開啟服務(wù)器)
Slave從服務(wù)器配置
1、修改配置文件
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
然后在最后加入三行代碼如下:
server-id = 2
relay-log = slave-relay-bin
relay-log-index = slave-relay-bin.index
4.查看主服務(wù)器狀態(tài):
show master status;

Slave從服務(wù)器配置
1、修改配置文件
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
然后在最后加入三行代碼如下:
server-id = 2
relay-log = slave-relay-bin
relay-log-index = slave-relay-bin.index

2、重啟服務(wù)
sudo service mysql restart
登錄Slave從服務(wù)器,運(yùn)行命令
change master to master_host='192.168.12.39',master_port=3306,master_user='masterbackup',master_password='masterbackup',master_log_file='master-bin.000006',master_log_pos=310;

啟動(dòng)Slave數(shù)據(jù)同步

查看Slave信息

如果有兩個(gè)yes,表示成功。
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
2.悲觀鎖和樂觀鎖
1.3.11.1 悲觀鎖(Pessimistic Lock)
在查詢的時(shí)候,鎖起來,事務(wù)結(jié)束后,釋放。
悲觀鎖的特點(diǎn)是先獲取鎖,再進(jìn)行業(yè)務(wù)操作,即“悲觀”的認(rèn)為獲取鎖是非常有可能失敗的,因此要先確保獲取鎖成功再進(jìn)行業(yè)務(wù)操作。通常所說的“一鎖二查三更新”即指的是使用悲觀鎖。通常來講在數(shù)據(jù)庫上的悲觀鎖需要數(shù)據(jù)庫本身提供支持,即通過常用的select … for update操作來實(shí)現(xiàn)悲觀鎖。當(dāng)數(shù)據(jù)庫執(zhí)行select for update時(shí)會(huì)獲取被select中的數(shù)據(jù)行的行鎖,因此其他并發(fā)執(zhí)行的select… for update如果試圖選中同一行則會(huì)發(fā)生排斥(需要等待行鎖被釋放),因此達(dá)到鎖的效果。select for update獲取的行鎖會(huì)在當(dāng)前事務(wù)結(jié)束時(shí)自動(dòng)釋放,因此必須在事務(wù)中使用。
這里需要注意的一點(diǎn)是不同的數(shù)據(jù)庫對(duì)select for update的實(shí)現(xiàn)和支持都是有所區(qū)別的,例如oracle支持select for update no wait,表示如果拿不到鎖立刻報(bào)錯(cuò),而不是等待,mysql就沒有no wait這個(gè)選項(xiàng)。另外mysql還有個(gè)問題是select for update語句執(zhí)行中所有掃描過的行都會(huì)被鎖上,這一點(diǎn)很容易造成問題。因此如果在mysql中用悲觀鎖務(wù)必要確定走了索引,而不是全表掃描。
1.3.11.2 樂觀鎖(Optimistic Lock)
查詢的時(shí)候,不需要操作,更改的時(shí)候再判斷。
樂觀鎖的特點(diǎn)先進(jìn)行業(yè)務(wù)操作,不到萬不得已不去拿鎖。即“樂觀”的認(rèn)為拿鎖多半是會(huì)成功的,因此在進(jìn)行完業(yè)務(wù)操作需要實(shí)際更新數(shù)據(jù)的最后一步再去拿一下鎖就好。
樂觀鎖在數(shù)據(jù)庫上的實(shí)現(xiàn)完全是邏輯的,不需要數(shù)據(jù)庫提供特殊的支持。一般的做法是在需要鎖的數(shù)據(jù)上增加一個(gè)版本號(hào),或者時(shí)間戳,然后按照如下方式實(shí)現(xiàn):
1. SELECT data AS old_data, version AS old_version FROM …;
2. 根據(jù)獲取的數(shù)據(jù)進(jìn)行業(yè)務(wù)操作,得到new_data和new_version
3. UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
? ? // 樂觀鎖獲取成功,操作完成
} else {
? ? // 樂觀鎖獲取失敗,回滾并重試
}
樂觀鎖是否在事務(wù)中其實(shí)都是無所謂的,其底層機(jī)制是這樣:在數(shù)據(jù)庫內(nèi)部update同一行的時(shí)候是不允許并發(fā)的,即數(shù)據(jù)庫每次執(zhí)行一條update語句時(shí)會(huì)獲取被update行的寫鎖,直到這一行被成功更新后才釋放。因此在業(yè)務(wù)操作進(jìn)行前獲取需要鎖的數(shù)據(jù)的當(dāng)前版本號(hào),然后實(shí)際更新數(shù)據(jù)時(shí)再次對(duì)比版本號(hào)確認(rèn)與之前獲取的相同,并更新版本號(hào),即可確認(rèn)這之間沒有發(fā)生并發(fā)的修改。如果更新失敗即可認(rèn)為老版本的數(shù)據(jù)已經(jīng)被并發(fā)修改掉而不存在了,此時(shí)認(rèn)為獲取鎖失敗,需要回滾整個(gè)業(yè)務(wù)操作并可根據(jù)需要重試整個(gè)過程。
1.3.11.3 總結(jié)
樂觀鎖在不發(fā)生取鎖失敗的情況下開銷比悲觀鎖小,但是一旦發(fā)生失敗回滾開銷則比較大,因此適合用在取鎖失敗概率比較小的場(chǎng)景,可以提升系統(tǒng)并發(fā)性能
樂觀鎖還適用于一些比較特殊的場(chǎng)景,例如在業(yè)務(wù)操作過程中無法和數(shù)據(jù)庫保持連接等悲觀鎖無法適用的地方
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
3.引擎
4.pymysql的安裝及增刪改查
import pymysql
# 獲取連接對(duì)象
my_conn = pymysql.connect(
? ? host='192.168.0.138',
? ? user='root',
? ? password='root',
? ? database='mydb',
? ? port=3306,
? ? charset='utf8'
)
# 獲取可執(zhí)行sql的對(duì)象
my_cursor = my_conn.cursor()
# sql語句
sql = 'insert into t_user(name,pwd) values("{}","{}")'.format('laowang', '123456')
print(sql)
# 執(zhí)行sql語句
num = my_cursor.execute(sql)
print(num)
# 提交
my_conn.commit()
# 關(guān)閉
my_cursor.close()
my_conn.close()
、、、、、、、、、、、、、、、、、、、、、、、、、、
1.增
import pymysql
# 獲取連接對(duì)象
my_conn = pymysql.connect(
? ? host='192.168.0.138',
? ? user='root',
? ? password='root',
? ? database='mydb',
? ? port=3306,
? ? charset='utf8'
)
# 獲取可執(zhí)行sql的對(duì)象
my_cursor = my_conn.cursor()
# sql語句
sql = 'insert into t_user(name,pwd) values("{}","{}")'.format('laowang', '123456')
print(sql)
# 執(zhí)行sql語句
num = my_cursor.execute(sql)
print(num)
# 提交
my_conn.commit()
# 關(guān)閉
my_cursor.close()
my_conn.close()

2.改
import pymysql
my_conn = pymysql.connect(
? ? host='192.168.0.138',
? ? user='root',
? ? password='root',
? ? database='mydb',
? ? port=3306,
? ? charset='utf8'
)
# 獲取可執(zhí)行sql的對(duì)象
my_cursor = my_conn.cursor()
sql1 = 'update bank set money = money-20 where id = 1'
sql2 = 'update bank set money = money+20 where id = 2'
#捕捉異常
try:
? ? my_cursor.execute(sql1)
? ? my_cursor.execute(sql2)
? ? my_conn.commit()
except Exception as ex:
? ? my_conn.rollback()
finally:
? ? my_cursor.close()
? ? my_conn.close()


3.查
import pymysql
def f1():
? ? # 獲取連接對(duì)象
? ? my_conn = pymysql.connect(
? ? ? ? host='192.168.0.138',
? ? ? ? user='root',
? ? ? ? password='root',
? ? ? ? database='mydb',
? ? ? ? port=3306,
? ? ? ? charset='utf8'
? ? )
? ? # 獲取可執(zhí)行sql的對(duì)象
? ? my_cursor = my_conn.cursor()
? ? # sql語句
? ? sql = 'select empno,ename,hiredate from EMP'
? ? # 執(zhí)行sql語句
? ? my_cursor.execute(sql)
? ? # 獲取查詢數(shù)據(jù)
? ? rows = my_cursor.fetchall()
? ? for empno, ename, hiredate in rows:
? ? ? ? print(empno, ename, hiredate)
? ? # 關(guān)閉
? ? my_cursor.close()
? ? my_conn.close()
def f2():
? ? my_conn = pymysql.connect(
? ? ? ? host='192.168.0.138',
? ? ? ? user='root',
? ? ? ? password='root',
? ? ? ? database='mydb',
? ? ? ? port=3306,
? ? ? ? charset='utf8'
? ? )
? ? # 獲取可執(zhí)行sql的對(duì)象
? ? my_cursor = my_conn.cursor()
? ? sql = 'select empno,ename,hiredate from EMP'
? ? my_cursor.execute(sql)
? ? # 獲取查詢數(shù)據(jù)
? ? row = my_cursor.fetchone()
? ? print(row)
? ? my_cursor.close()
? ? my_conn.close()
if __name__ == '__main__':
? ? # f2()
? ? f1()

4.
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
2、新建一個(gè)學(xué)生表(姓名,密碼,出生日期,地址),使用python代碼完成循環(huán)插入5個(gè)學(xué)生信息。
要求如下:
1、姓名唯一,如果重復(fù)提示重復(fù)輸入,直到用戶輸入正確為止。
2、出生日期要求用戶輸入的格式y(tǒng)yyy-mm-dd,如果錯(cuò)誤,重新輸入,直到用戶輸入正確為止。
3、5個(gè)學(xué)生輸入完畢后,顯示5個(gè)學(xué)生的信息。
import pymysql
my_conn = pymysql.connect(
? ? host='192.168.0.138',
? ? user='root',
? ? password='root',
? ? database='mydb',
? ? port=3306,
? ? charset='utf8'
)
my_cursor = my_conn.cursor()
try:
? ? for i in range(1):
? ? ? ? id = input("請(qǐng)輸入學(xué)生id")
? ? ? ? name= input("請(qǐng)輸入學(xué)生姓名")
? ? ? ? pwd = input("請(qǐng)輸入學(xué)生密碼")
? ? ? ? hiredate = input("請(qǐng)輸入學(xué)生出生日期")
? ? ? ? addres = input("請(qǐng)輸入學(xué)生地址")
? ? sql = 'insert into student(id,name,pwd,hiredate,addres)? values(%s,%s,%s,%s,%s)'
? ? num = my_cursor.execute(sql,[id,name,pwd,hiredate,addres])
? ? print(num)
? ? my_conn.commit()
except:
? ? print("請(qǐng)輸入正確的出生日期")
? ? my_cursor.close()
? ? my_conn.close()
