建立连接
- 时区设定东8区
time_zone='+8:00'
- 字符集默认为 UTF8(或者加上
charset="utf8"
)
- autocommit 默认为 True,启动自动提交(重要)
1
2
3
|
import torndb
db = torndb.Connection('127.0.0.1:3306', 'database', 'user', 'password', time_zone='+8:00')
|
查询
查询是个 独立的事务
1
2
3
4
5
|
sql = '''SELECT * FROM user WHERE id = %s'''
info = db.get(sql, 1)
sql = '''SELECT * FROM user WHERE id > %s'''
rows = db.query(sql, 1)
|
更改
单个更改语句也是个 独立的事务
,不需要显式启用事务,autocommit 会自动 commit 提交
- 修改 update
- 插入 insert
- 删除 delete
1
2
3
4
5
6
7
8
9
10
11
12
|
sql = '''UPDATE user SET `status` = %s WHERE id = %s'''
# affected_row_count: 修改到的记录数量
affected_row_count = db.update(sql, 0, 1)
sql = '''INSERT INTO user (name, status) VALUES (%s, %s)'''
args = ["小明", 0]
# last_id: 插入后的记录 ID
last_id = db.insert(sql, *args)
sql = '''DELETE FROM user WHERE id = %s'''
# affected_row_count: 删除的记录数量
affected_row_count = db.execute_rowcount(sql, 1)
|
事务处理
多条 SQL 语句执行,为了避免并发操作带来的数据安全问题,需要显式启用事务。
- begin 开启事务
- rollback 回滚事务
- commit 提交事务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# 强制设定 autocommit=1
db._db.autocommit(True)
def do_transacion():
# begin 开启事务, 不受 autocommit 的影响
db._db.begin()
try:
sql = ''' SELECT `status` FROM user WHERE id = %s FOR UPDATE '''
info = db.get(sql, 1)
if not info:
raise Exception(u"记录不存在")
sql = ''' UPDATE user SET `status`=%s WHERE id=%s '''
db.update(sql, 1, 1)
db._db.commit()
except Exception as e:
db._db.rollback()
print(str(e))
return False
return True
# 事务是否执行成功?
is_success = do_transacion()
|
autocommit 的说明
MySQL 默认操作模式就是 autocommit=1 自动提交模式。这就表示除非显式地开始一个事务,否则每个查询都被当做一个单独的事务自动执行。
- 如果 autocommit=1,MySQL 会在收到 SQL 请求时立刻提交,单条 DML 语句(select、update、insert、delete)就是一个
事务
。
- 如果 autocommit=0,MySQL 需要等待 client 提交 commit 语句,才提交待执行的 SQL 语句。
- autocommit 不影响 begin 语句开启的事务,必须等待 client 提交 rollback/commit 语句,主动触发提交。
以上论述都是针对默认情况下,MySQL autocommit=1 的数据库操作方式,建议在 torndb 中将 autocommit 设置为 1,
有些场景或者项目里(为了性能),autocommit=0,这个时候就要特别小心了,没有 commit 之前的所有 SQL 都会处在一个事务中!
查询
查询操作不是独立的事务,和其他在途的 SQL 处于同一个事务内,依赖 更改
操作 commit,
所以使用方式同上
更改
更改操作需要主动执行 commit 才会持久化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 强制设定 autocommit=0
db._db.autocommit(False)
sql = '''UPDATE user SET `status` = %s WHERE id = %s'''
# affected_row_count: 无法获取
affected_row_count = db.update(sql, 0, 1)
db._db.commit()
sql = '''INSERT INTO user (name, status) VALUES (%s, %s)'''
args = ["小明", 0]
# last_id: 插入后的记录 ID
last_id = db.insert(sql, *args)
db._db.commit()
sql = '''DELETE FROM user WHERE id = %s'''
# affected_row_count: 删除的记录数量
affected_row_count = db.execute_rowcount(sql, 1)
db._db.commit()
|
事务处理
如果 autocommit=0,数据库没有开启自动提交,事务处理有两种方式,差不多。
- 方式一:begin 开启事务,不受 autocommit 的影响,同上
- 方式二:autocommit=0 本身就处于事务中,可以省略 begin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# 强制设定 autocommit=0
db._db.autocommit(False)
def do_transacion():
# begin 可以省略掉
# db._db.begin()
try:
sql = ''' SELECT `status` FROM user WHERE id = %s FOR UPDATE '''
info = db.get(sql, 1)
if not info:
raise Exception(u"记录不存在")
sql = ''' UPDATE user SET `status`=%s WHERE id=%s '''
db.update(sql, 1, 1)
db._db.commit()
except Exception as e:
db._db.rollback()
print(str(e))
return False
return True
# 事务是否执行成功?
is_success = do_transacion()
|
特别注意:同一个事务内的 SQL 操作,一定要使用同一个 MySQL 连接!
很多人意识不到这个问题, 在使用连接池的时候特别容易导致 MySQL 事务跨连接,造成未知的后果。