数据库学习(1)事务

1.先举个事务例子,也就是网上经常出现的例子,转账的例子:从账户A转账50元到账户B。这个事务可以定义为:

read(A)
A:=A-50
write(A)
read(B)
B:=B+50
write(B)

其中,read(X)从数据库把数据项X传到read操作的事务的主存缓存区中。write(X)从主缓存中把数据项X存入数据库。
这个操作必须全部执行,或者全部不执行,如果只执行一部分,比如执行了

read(A)
A:=A-50
write(A)

却没执行

read(B)
B:=B+50
write(B)

就会出现A账户的钱变少,B却没有收到转账的情况。所以该事务的步骤不能分割。转账前后A和B的账户总额要不变。而且有人从A中取钱的话不能影响当前事务的执行。这个事务执行完之后,数据就被持久化到数据库中了。

2.关于事务的几个概念。
事务:访问并可能更新各种数据项的一个程序执行单元。
原子性:事务的步骤集合必须作为一个单一的、不可分割的单元出现。要么执行全部内容,要么不执行。如果事务的执行过程中有失败,则要撤销任何对数据库的修改。
不可分割,如果只执行一半,另一半执行错误,那么可能会造成错误。
隔离性:当前事务对数据库的操作不会感知到别的事务的操作,数据库采取特殊的处理来确保事务而不受并发的事务干扰。准确地说,并非要求做到完全无干扰。数据库规定了多种事务隔离界别,不同的隔离级别对应不用的干扰成都,隔离级别越高,数据一致性越好,但并发行越弱。
持久性:一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中。即使在事务提交后,数据库马上崩溃,在数据库重启时,也必须保证能够通过某种机制恢复数据。
一致性:超出了数据完整性约束,如何实现是程序员的职责。这个概念还是比较抽象。
完整性约束:取值非空not null、unique约束,check约束、参照完整性等。
事务状态图

事务状态图.png

活动状态:事务执行时
部分提交状态:最后一条语句执行后
失败状态:执行不能继续后
提交状态:成功完成后
中止状态:事务回滚,数据库已回复事务开始前的状态

事务从活动状态开始,当执行完最后一条语句后进入部分提交状态,然后数据库往磁盘上写入足够的信息,即日志,确保及时出现故障,在数据库系统重启后也能重新执行最后的事务,这条信息写完后,事务就进入了提交状态。

3.mysql中事务:
在mysql数据库中执行下面语句:
begin;
insert into lihong_tbl (NAME,account) VALUES ("悠悠",4000);
insert into lihong_tbl (NAME,account) VALUES ("菲菲",8000);
UPDATE lihong_tbl SET account = 5000 WHERE name = "悠悠";
UPDATE lihong_tbl SET account = 7000 WHERE name = "菲菲";

在没有commit前查询一下。可以看到表中还没有记录。


image.png

然后执行commit;
再查看一下表,可以看到,已经有了刚才的记录。

image.png

使用rollback:
begin;
DELETE from lihong_tbl where id = 8;
ROLLBACK;
数据库并未删除这条记录;

4.在mysql中操作事务:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import pymysql

# 打开数据库连接
db = pymysql.connect("test.com", "testusername", "testpw", "testdb", charset='utf8' )

# 使用cursor()方法获取操作游标
cursor = db.cursor()

# 使用execute方法执行SQL语句
cursor.execute("SELECT VERSION()")

# 使用 fetchone() 方法获取一条数据
data = cursor.fetchone()

print("Database version : %s " % data)

userNameA = "菲菲"
userNameB = "悠悠"
sqlA1 = "select account from lihong_tbl where NAME = " + "\"" + userNameA + "\""
# print(sqlA1)
cursor.execute(sqlA1)
accountA = cursor.fetchone()[0]
print("转账前账户A金额:", accountA)
accountA += 500

sqlA2 = "update lihong_tbl set account =" + str(accountA) + " where NAME = " + "\"" + userNameA + "\""
# print(sqlA2)
cursor.execute(sqlA2)


sqlB1 = "select account from lihong_tbl where NAME = " + "\"" + userNameB + "\""
# print(sqlB1)
cursor.execute(sqlB1)
accountB = cursor.fetchone()[0]
print("转账前账户B金额:", accountB)
accountB = accountB-500

sqlB2 = "update lihong_tbl set account =" + str(accountB) + " where NAME = " + "\"" + userNameB + "\""
# print(sqlA2)
cursor.execute(sqlB2)

db.commit()


cursor.execute(sqlA1)
accountA = cursor.fetchone()[0]
print("commit后账户A金额:", accountA)

cursor.execute(sqlB1)
accountB = cursor.fetchone()[0]
print("commit后账户B金额:", accountB)

# 关闭数据库连接
db.close()

打印结果:
转账前账户A金额: 21000
转账前账户B金额: 6500
commit后账户A金额: 21500
commit后账户B金额: 6000

5.有关数据库的约束:
1)非空约束:用not null约束的字段不能为null值,必须给定具体的数据
2)唯一性约束(unique):unique约束的字段,具有唯一性,不可重复,但可以为null
3)主键约束(primary key):给某个字段添加主键约束之后,该字段不能重复也不能为空,效果和”not null unique”约束相同,但是本质不同。主键约束除了可以做到”not null unique”之外,还会默认添加”索引——index”
4)外键约束(foreign key):若有两个表A、B,id是A的主键,而B中也有id字段,则id就是表B的外键,外键约束主要用来维护两个表之间数据的一致性。

mysql举例操作:

创建表test01,name非空,telephone是主键:
create table test01(
id int(10),
name varchar(32) not null,
telephone varchar(32) primary key,
age int(10)
);

查看列属性:show COLUMNS from test01

改变name属性为unique:ALTER TABLE test01 ADD UNIQUE (name)

添加check约束:ALTER TABLE test01 ADD CHECK (age>0)

创建表test02,外键是test01中的telephone:
create table test02(
gradeid int(10) primary key auto_increment,
grade int(32) not null,
tele varchar(32),
foreign key(tele) references test01(telephone)
);

你可能感兴趣的:(数据库学习(1)事务)