1、整理今天所学的知识点
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
1.主从复制
基本步骤:
1. 在主服务器上,必须开启二进制日志机制和配置一个独立的ID
2. 在每一个从服务器上,配置一个唯一的ID,创建一个用来专门复制主服务器数据的账号
3. 在开始复制进程前,在主服务器上记录二进制文件的位置信息
4. 如果在开始复制之前,数据库中已经有数据,就必须先创建一个数据快照(可以使用mysqldump导出数据库,或者直接复制数据文件)
5. 配置从服务器要连接的主服务器的IP地址和登陆授权,二进制日志文件名和位置
在主服务器Ubuntu上进行备份,执行命令:
mysqldump -uroot -pmysql --all-databases --lock-all-tables > ~/master_db.sql
说明
-u :用户名
-p :示密码
--all-databases :导出所有数据库
--lock-all-tables :执行操作时锁住所有表,防止操作时有数据修改
~/master_db.sql :导出的备份数据(sql文件)位置,可自己指定
在从服务器Windows上进行数据还原
登陆数据库,然后运行
source master_db.sql
配置主服务器master(Ubuntu中的MySQL)
编辑设置mysqld的配置文件,设置log_bin和server-id
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
在最后添加这两句代码
server-id = 1
log_bin = master-bin
重启服务器(修改配置都要重新开启服务器)
Slave从服务器配置
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.查看主服务器状态:
show master status;
Slave从服务器配置
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、重启服务
sudo service mysql restart
登录Slave从服务器,运行命令
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;
启动Slave数据同步
查看Slave信息
如果有两个yes,表示成功。
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
2.悲观锁和乐观锁
1.3.11.1 悲观锁(Pessimistic Lock)
在查询的时候,锁起来,事务结束后,释放。
悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select… for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
这里需要注意的一点是不同的数据库对select for update的实现和支持都是有所区别的,例如oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,mysql就没有no wait这个选项。另外mysql还有个问题是select for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在mysql中用悲观锁务必要确定走了索引,而不是全表扫描。
1.3.11.2 乐观锁(Optimistic Lock)
查询的时候,不需要操作,更改的时候再判断。
乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。
乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。一般的做法是在需要锁的数据上增加一个版本号,或者时间戳,然后按照如下方式实现:
1. SELECT data AS old_data, version AS old_version FROM …;
2. 根据获取的数据进行业务操作,得到new_data和new_version
3. UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
// 乐观锁获取成功,操作完成
} else {
// 乐观锁获取失败,回滚并重试
}
乐观锁是否在事务中其实都是无所谓的,其底层机制是这样:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据时再次对比版本号确认与之前获取的相同,并更新版本号,即可确认这之间没有发生并发的修改。如果更新失败即可认为老版本的数据已经被并发修改掉而不存在了,此时认为获取锁失败,需要回滚整个业务操作并可根据需要重试整个过程。
1.3.11.3 总结
乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能
乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
3.引擎
4.pymysql的安装及增删改查
import pymysql
# 获取连接对象
my_conn = pymysql.connect(
host='192.168.0.138',
user='root',
password='root',
database='mydb',
port=3306,
charset='utf8'
)
# 获取可执行sql的对象
my_cursor = my_conn.cursor()
# sql语句
sql = 'insert into t_user(name,pwd) values("{}","{}")'.format('laowang', '123456')
print(sql)
# 执行sql语句
num = my_cursor.execute(sql)
print(num)
# 提交
my_conn.commit()
# 关闭
my_cursor.close()
my_conn.close()
、、、、、、、、、、、、、、、、、、、、、、、、、、
1.增
import pymysql
# 获取连接对象
my_conn = pymysql.connect(
host='192.168.0.138',
user='root',
password='root',
database='mydb',
port=3306,
charset='utf8'
)
# 获取可执行sql的对象
my_cursor = my_conn.cursor()
# sql语句
sql = 'insert into t_user(name,pwd) values("{}","{}")'.format('laowang', '123456')
print(sql)
# 执行sql语句
num = my_cursor.execute(sql)
print(num)
# 提交
my_conn.commit()
# 关闭
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'
)
# 获取可执行sql的对象
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():
# 获取连接对象
my_conn = pymysql.connect(
host='192.168.0.138',
user='root',
password='root',
database='mydb',
port=3306,
charset='utf8'
)
# 获取可执行sql的对象
my_cursor = my_conn.cursor()
# sql语句
sql = 'select empno,ename,hiredate from EMP'
# 执行sql语句
my_cursor.execute(sql)
# 获取查询数据
rows = my_cursor.fetchall()
for empno, ename, hiredate in rows:
print(empno, ename, hiredate)
# 关闭
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'
)
# 获取可执行sql的对象
my_cursor = my_conn.cursor()
sql = 'select empno,ename,hiredate from EMP'
my_cursor.execute(sql)
# 获取查询数据
row = my_cursor.fetchone()
print(row)
my_cursor.close()
my_conn.close()
if __name__ == '__main__':
# f2()
f1()
4.
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
2、新建一个学生表(姓名,密码,出生日期,地址),使用python代码完成循环插入5个学生信息。
要求如下:
1、姓名唯一,如果重复提示重复输入,直到用户输入正确为止。
2、出生日期要求用户输入的格式yyyy-mm-dd,如果错误,重新输入,直到用户输入正确为止。
3、5个学生输入完毕后,显示5个学生的信息。
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("请输入学生id")
name= input("请输入学生姓名")
pwd = input("请输入学生密码")
hiredate = input("请输入学生出生日期")
addres = input("请输入学生地址")
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("请输入正确的出生日期")
my_cursor.close()
my_conn.close()