python开发数据库系统的核心是什么_学Python划重点 六 (数据库实列编程)

Python 中将数据保存到数据库中技术有很多,但主要分为两类:遵循Python DB-API 规范技术(Python Database API Specification) 和ORM 技术(Object-Relational mapping) 。Python DB-API 规范通过在Python 中编写SQL 语句访问数据库。ORM 技术是面向对象的,对数据的访问是通过对象实现的,程序员不需要使用SQL 语句。

在Python2.X 中操作MySQL 数据库可以通过Pyhon 的MySQLdb 模块实现,由于目前Python3.5 不支持MySQLdb 模块,所以我们使用pymysql 模块。

下面介绍数据库的基本操作步骤:

==1. 创建数据库连接==import pymysql

#连接数据库

conn = pymysql.connect(

host='localhost', # 数据库主机名或IP

port=3306 # 连接数据库端口号

user='root', # 访问数据库帐号

password='1234', # 访问数据库密码

database='mydatabase', # 数据库中的库名

charset='utf8') # 数据库编码格式

Connection 对象有一些重要的方法 : close() :关闭数据库连接,关闭之后再使用数据库连接将引发异常。 commit() :提交数据库事务。 rollback() :回滚数据库事务。 cursor() :获得Cursor 游标对象。

==2. 创建游标==

一个Cursor 游标对象表示一个数据库游标,游标暂时保存了SQL 操作所影响到的数据。 在数据库事务管理中游标非常重要,游标是通过数据库连接创建的,相同数据库连接创 建的游标所引起的数据变化,会马上反映到同一连接中的其他游标对象。但是不同数据 库连接中的游标,是否能及时反映出来,则与数据库事务管理有关。

游标Cursor 对象方法: 1.execute(operation[, parameters]) 执行一条SQL 语句,operation 是SQL 语句,parameters 是为SQL 提供的参数,可以是 序列或 字典 类型。返回值是整数,表示执行SQL 语句影响的行数。 2. executemany(operation[, seq_of_params]) 执行批量SQL 语句,operation 是SQL 语句,seq_of_params 是为SQL 提供的参数, seq_of_params 是 序列 。返回值是整数,表示执行SQL 语句影响的行数。 3.callproc(procname[, parameters]) 执行存储过程,procname 是存储过程名,parameters 是为存储过程提供的参数。 4.fetchone() 从结果集中返回一条记录的序列,如果没有数据返回None 。 5.fetchmany([size=cursor.arraysize) 从结果集中返回小于或等于size 的记录数序列,如果没有数据返回空序列,size 默认情况下是整个游标的行数。 6.fetchall() 从结果集中返回所有数据。

实列:

1. 创建数据库:

import pymysql

# 连接数据库

conn = pymysql.connect(

host='127.0.0.1',

port=3306,

user='root',

password='1234',

charset='utf8'

)

cursor = conn.cursor() # 拿到游标

cursor.execute("create database if not exists mydatabase") # 创建数据库

cursor.close() # 关闭游标

conn.close() # 关闭连接

2. 创建数据库表:

import pymysql

# 连接数据库

conn = pymysql.connect(

host='127.0.0.1',

port=3306,

user='root',

password='1234',

db='mydatabase',

charset='utf8'

)

cursor = conn.cursor() # 拿到游标

cursor.execute('''create table if not exists student (

number varchar(20) primary key,

name varchar(50) not null,

sex varchar(2) check (sex in(‘M’,‘F’)),

math double(4,1),

english double(4,1),

computer double(4,1)

''')

cursor.close()

conn.close()

3. 插入数据:

import pymysql

# 1. 创建数据库连接

conn = pymysql.connect(

host='127.0.0.1',

port=3306,

user='root',

password='1234',

db='mydatabase'

charset='utf8'

)

try:

# 2. 创建游标对象

with conn.cursor() as cursor: #with 代码块结束时就会关闭游标对象。

# 3. 执行sql 操作。插入多条语句

sql = 'insert into student(number, name, sex, math, english, computer) values (%s, %s, %s, %s, %s, %s)'

data = [

('1501', ' 炎黄', 'M', 78.5, 70.0, 100.0),

('1505', ' 吕萌萌', 'M', 100.0, 90.0, 95.0),

('1509', ' 石耀举', 'F', 60.5, 90.0, 70.0)

]

cursor.executemany(sql, data)

# 3. 执行sql 操作 。插入 单条 数据

data = ('1521', ' 王维', 'F', 68.4, 73.0, 55.0)

cursor.execute(sql, data) # 参数放在列表中,或放在元组中

# 4. 提交数据库事务

conn.commit()

# with 代码块结束 5. 自动关闭游标

except pymysql.DatabaseError:

conn.rollback() # 4. 回滚数据库事务

finally:

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

4. 删除数据

import pymysql

# 1. 创建数据库连接

conn = pymysql.connect(

host='127.0.0.1',

port=3306,

user='root',

password='1234',

db='mydatabase'

charset='utf8'

)

try:

# 2. 创建游标对象

with conn.cursor() as cursor:

# 3. 执行sql 语句

sql = 'delete from student where number=%s'

cursor.execute(sql, '1502')

cursor.executemany(sql, ('1505', '1507', '1514'))

# 4. 提交数据库事务

conn.commit()

# with 代码块结束 5. 关闭游标

except pymysql.DatabaseError:

conn.rollback()# 4. 回滚数据库事务

finally:

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

5. 修改数据

import pymysql

# 1. 创建数据库连接

conn = pymysql.connect(

host='127.0.0.1',

port=3306,

user='root',

password='1234',

db='mydatabase'

charset='utf8'

)

try:

#2. 创建游标对象

with conn.cursor() as cursor:

# 3. 执行sql 语句

sql = 'update student set name=%s where number > %s'

cursor.execute(sql, (' 水份', '1510'))

# 4. 提交数据库事务

conn.commit()

# with 代码块结束 5. 关闭游标

except pymysql.DatabaseError:

# 4. 回滚数据库事务

conn.rollback()

finally:

# 6. 关闭数据库连接

conn.close()

6. 查找数据

import pymysql

# 1. 创建数据库连接

conn = pymysql.connect(

host='127.0.0.1',

port=3306,

user='root',

password='1234',

db='mydatabase'

charset='utf8'

)

try:

# 2. 创建游标对象

with conn.cursor() as cursor:

# 3. 执行sql 操作

sql = 'select * from student'

cursor.execute(sql)

# 4. 提取结果集

# 提取所有数据,返回结果默认是元组形式,所以可以进行迭代处理

result_list = cursor.fetchall()

for row in result_list:

print(row)

print(' 共查询到:', cursor.rowcount, ' 条数据。')

# 4. 提取结果集。获取第一行数据

result1 = cursor.fetchone()

print(result1)

# 4. 提取结果集。获取前n 行数据

result2 = cursor.fetchmany(2)

print(result2)

# with 代码块结束 5. 关闭游标

finally:

# 6. 关闭数据库连接

conn.close()

7. 数据库配置文件的使用

配置文件configparser.ini

[db]

host = 127.0.0.1

port = 3306

user = root

password = 1234

database = mydatabase

charset = utf8

import pymysql

import configparser

config = configparser.ConfigParser()

config.read('config.ini', encoding='utf-8')

host = config['db']['host']

port = config.getint('db', 'port')

user = config['db']['user']

password = config['db']['password']

database = config['db']['database']

charset = config['db']['charset']

# 1. 创建数据库连接

conn = pymysql.connect(

host=host,

port=port,

user=user,

password=password,

database=database,

charset=charset

)

cursor 就是一个Cursor 对象,这个cursor 是一个实现了迭代器和生成器的对象,这个时候cursor 中还没有数据,只有等到fetchone() 或fetchall() 的时候才返回一个元组tuple ,才支持len() 和index() 操作,这也是它是迭代器的原因 。但同时为什么说它是生成器呢?因为cursor 只能用一次,即每用完一次之后记录其位置,等到下次再取的时候是从游标处再取而不是从头再来,而且fetch 完所有的数据之后,这个cursor 将不再有使用价值了,即不再能fetch 到数据了。

8. 学生管理系统

import pymysql

import wx

import wx.grid

class MyData():

def __init__(self):

self.tableText=["number","name","sex","math","english","computer"]

self.mydata=[]

self.conn = pymysql.connect(

host="127.0.0.1",

port=3306,

user="root",

password="123456",

database="student",

charset="utf8"

)

def Conn(self):

self.conn = pymysql.connect(

host="127.0.0.1",

port=3306,

user="root",

password="123456",

database="student",

charset="utf8"

)

def showData(self,number):

self.Conn()

try:

with self.conn.cursor() as cursor:

self.mydata=[]

if number=="":

sqlstr = "select * from test1"

cursor.execute(sqlstr, ())

else:

sqlstr = "select * from test1 where number=%s"

cursor.execute(sqlstr, (number))

result_list=cursor.fetchall()

for item in result_list:

print(item)

self.mydata.append(item)

except pymysql.DatabaseError:

self.conn.rollback()

finally:

self.conn.close()

def insterData(self,data):

self.Conn()

try:

with self.conn.cursor() as cursor:

sqlstr = """

insert into test1 (number,name,sex,math,english,computer)

values(%s,%s,%s,%s,%s,%s)

"""

cursor.execute(sqlstr, data)

self.conn.commit()

except pymysql.DatabaseError:

self.conn.rollback()

finally:

self.conn.close()

def uptateData(self,data):

self.Conn()

try:

with self.conn.cursor() as cursor:

sqlstr = "update test1 set number=%s,name= %s ,sex=%s,math=%s,english=%s,computer=%s where number=%s"

cursor.execute(sqlstr, data)

self.conn.commit()

except pymysql.DatabaseError:

self.conn.rollback()

finally:

self.conn.close()

def deleteData(self,number):

self.Conn()

try:

with self.conn.cursor() as cursor:

sqlstr = "delete from test1 where number=%s"

print(number)

cursor.execute(sqlstr, number)

self.conn.commit()

except pymysql.DatabaseError:

self.conn.rollback()

finally:

self.conn.close()

def colse(self):

self.conn.close()

class MyGridTable(wx.grid.GridTableBase):

def __init__(self,tableText,data):

super().__init__()

self.tableText=tableText

self.data=data

self.colLabels=tableText

def GetNumberRows(self):

return len(self.data)

def GetNumberCols(self):

return len(self.tableText)

def GetValue(self, row, col):

return self.data[row][col]

def GetColLabelValue(self, col):

return self.tableText[col]

class AddorChangeFrame(wx.Frame):

def __init__(self,frame):

if frame=="添加":

super().__init__(parent=None,size=(300,350),title="添加")

else:

super().__init__(parent=None, size=(300, 350), title="修改")

self.Center()

panel=wx.Panel(self)

number=wx.StaticText(parent=panel,id=-1,label="学号")

self.numbertext=wx.TextCtrl(parent=panel,id=-1)

box1=wx.BoxSizer()

box1.Add(number)

box1.Add(self.numbertext)

name = wx.StaticText(parent=panel, id=-1, label="姓名")

self.nametext = wx.TextCtrl(parent=panel, id=-1)

box2 = wx.BoxSizer()

box2.Add(name)

box2.Add(self.nametext)

sex = wx.StaticText(parent=panel, id=-1, label="性别")

self.sextext = wx.TextCtrl(parent=panel, id=-1)

box3 = wx.BoxSizer()

box3.Add(sex)

box3.Add(self.sextext)

math = wx.StaticText(parent=panel, id=-1, label="数学")

self.mathtext = wx.TextCtrl(parent=panel, id=-1)

box4 = wx.BoxSizer()

box4.Add(math)

box4.Add(self.mathtext)

english = wx.StaticText(parent=panel, id=-1, label="英语")

self.englishtext = wx.TextCtrl(parent=panel, id=-1)

box5 = wx.BoxSizer()

box5.Add(english)

box5.Add(self.englishtext)

computer = wx.StaticText(parent=panel, id=-1, label="学号")

self.computertext = wx.TextCtrl(parent=panel, id=-1)

box6 = wx.BoxSizer()

box6.Add(computer)

box6.Add(self.computertext)

if frame=="添加":

button1 = wx.Button(parent=panel, id=2, label="添加")

else:

button1=wx.Button(parent=panel,id=3,label="修改")

button2 = wx.Button(parent=panel, id=1, label="取消")

self.Bind(wx.EVT_BUTTON, self.on_button, id=1, id2=3)

box7=wx.BoxSizer()

box7.Add(button1)

box7.Add(button2)

mainbox=wx.BoxSizer(wx.VERTICAL)

mainbox.Add(box1,1,flag=wx.ALL,border=5)

mainbox.Add(box2,1,flag=wx.ALL,border=5)

mainbox.Add(box3,1,flag=wx.ALL,border=5)

mainbox.Add(box4,1,flag=wx.ALL,border=5)

mainbox.Add(box5,1,flag=wx.ALL,border=5)

mainbox.Add(box6,1,flag=wx.ALL,border=5)

mainbox.Add(box7, 1, flag=wx.ALL, border=5)

panel.SetSizer(mainbox)

def on_button(self, event):

id = event.GetId()

number=self.numbertext.GetValue()

name = self.nametext.GetValue()

sex = self.sextext.GetValue()

math = self.mathtext.GetValue()

english=self.englishtext.GetValue()

computer = self.computertext.GetValue()

data = MyData()

# 取消

if id == 1:

self.Close()

# 添加

elif id==2:

data.insterData((number, name, sex, math, english, computer))

self.Close()

# 修改

else:

data.uptateData((number, name, sex, math, english, computer,number))

self.Close()

class myFrame(wx.Frame):

def __init__(self):

super().__init__(parent=None,size=(700,400),title="学生信息管理系统")

self.Center()

panel=wx.Panel(self)

box1=wx.BoxSizer(wx.HORIZONTAL)

text1=wx.StaticText(parent=panel,id=-1,label="请输入学号:")

self.inputtext=wx.TextCtrl(parent=panel,id=-1)

findbutton=wx.Button(parent=panel,id=1,label="查询")

deletebutton = wx.Button(parent=panel, id=4, label="删除")

self.Bind(wx.EVT_BUTTON,self.on_button,id=1,id2=4)

b = wx.BoxSizer(wx.HORIZONTAL)

b.Add(text1,1,flag=wx.LEFT|wx.TOP|wx.BOTTOM,border=15)

b.Add(self.inputtext, 1,flag=wx.ALL,border=10)

b.Add(findbutton, 1,flag=wx.ALL,border=10)

b.Add(deletebutton, 1, flag=wx.ALL, border=10)

box1.Add(b,1,flag=wx.LEFT|wx.RIGHT,border=70)

self.grid = wx.grid.Grid(parent=panel,size=(580,255))

rowsizeinfo=wx.grid.GridSizesInfo(40,[])

self.grid.SetRowSizes(rowsizeinfo)

data=MyData()

data.showData("")

table = MyGridTable(data.tableText,data.mydata)

self.grid.SetTable(table, True)

box2 = wx.BoxSizer()

box2.Add(self.grid)

addbutton = wx.Button(parent=panel, id=2, label="添加")

updatebutton = wx.Button(parent=panel, id=3, label="修改")

box3 = wx.BoxSizer()

box3.Add(addbutton,1,flag=wx.EXPAND)

box3.Add(updatebutton, 1, flag=wx.EXPAND)

mainbox = wx.BoxSizer(wx.VERTICAL)

mainbox.Add(box1,1,flag=wx.EXPAND)

mainbox.Add(box2, 1,flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=50)

mainbox.Add(box3, 1,flag=wx.EXPAND)

panel.SetSizer(mainbox)

def on_button(self, event):

id = event.GetId()

data = MyData()

if id == 1:

data.showData(self.inputtext.GetValue())

print("查询!!!")

elif id==2:

print("添加!!!")

self.addFrame=AddorChangeFrame("添加")

self.addFrame.Show()

elif id == 3:

self.addFrame = AddorChangeFrame("修改")

self.addFrame.Show()

print("修改!!")

elif id == 4:

data.deleteData(self.inputtext.GetValue())

print("删除!!!")

if id !=1:# 显示全部

data.showData("")

table = MyGridTable(data.tableText, data.mydata)

self.grid.SetTable(table,True)

class myApp(wx.App):

def OnInit(self):

self.frame=myFrame()

self.frame.Show()

return True

if __name__=="__main__":

app=myApp()

app.MainLoop()

人生的光荣,不在于永不言败,而在于能够屡扑屡起 !

数据库的名字叫WawaDB,是用python实现的。由此可见python是灰常强大啊! 简介 记录日志的需求一般是这样的: 只追加,不修改,写入按时间顺序写入; 大量写,少量读,查询一般查询一个时间段的数据; MongoDB的固定集合很好的满足了这个需求,但是MongoDB占内存比较大,有点儿火穿蚊子,小题大做的感觉。 WawaDB的思路是每写入1000条日志,在一个索引文件里记录下当前的时间和日志文件的偏移量。 然后按时间询日志时,先把索引加载到内存中,用二分法查出时间点的偏移量,再打开日志文件seek到指定位置,这样就能很快定位用户需要的数据并读取,而不需要遍历整个日志文件。 性能 Core 2 P8400,2.26GHZ,2G内存,32 bit win7 写入测试: 模拟1分钟写入10000条数据,共写入5个小时的数据, 插入300万条数据,每条数据54个字符,用时2分51秒 读取测试:读取指定时间段内包含某个子串的日志 数据范围 遍历数据量 结果数 用时(秒) 5小时 300万 604 6.6 2小时 120万 225 2.7 1小时 60万 96 1.3 30分钟 30万 44 0.6 索引 只对日志记录的时间做索引, 简介里大概说了下索引的实现,二分查找肯定没B Tree效率高,但一般情况下也差不了一个数量级,而且实现特别简单。 因为是稀疏索引,并不是每条日志都有索引记录它的偏移量,所以读取数据时要往前多读一些数据,防止漏读,等读到真正所需的数据时再真正给用户返回数据。 如下图,比如用户要读取25到43的日志,用二分法找25,找到的是30所在的点, 索 引:0 10 20 30 40 50 日志:|.........|.........|.........|.........|.........|>>>a = [0, 10, 20, 30, 40, 50]>>>bisect.bisect_left(a, 35)>>>3>>>a[3]>>>30>>>bisect.bisect_left(a, 43)>>>5>>>a[5]>>>50 所以我们要往前倒一些,从20(30的前一个刻度)开始读取日志,21,22,23,24读取后因为比25小,所以扔掉, 读到25,26,27,...后返回给用户 读取到40(50的前一个刻度)后就要判断当前数据是否大于43了,如果大于43(返回全开区间的数据),就要停止读了。 整体下来我们只操作了大文件的很少一部分就得到了用户想要的数据。 缓冲区 为了减少写入日志时大量的磁盘写,索引在append日志时,把buffer设置成了10k,系统默认应该是4k。 同理,为了提高读取日志的效率,读取的buffer也设置了10k,也需要根据你日志的大小做适当调整。 索引的读写设置成了行buffer,每满一行都要flush到磁盘上,防止读到不完整的索引行(其实实践证明,设置了行buffer,还是能读到半拉的行)。 查询 啥?要支持SQL,别闹了,100行代码怎么支持SQL呀。 现在查询是直接传入一个lambada表达式,系统遍历指定时间范围内的数据行时,满足用户的lambada条件才会返回给用户。 当然这样会多读取很多用户不需要的数据,而且每行都要进行lambda表达式的运算,不过没办法,简单就是美呀。 以前我是把一个需要查询的条件和日志时间,日志文件偏移量都记录在索引里,这样从索引里查找出符合条件的偏移量,然后每条数据都如日志文件里seek一次,read一次。这样好处只有一个,就是读取的数据量少了,但缺点有两个: 索引文件特别大,不方便加载到内存中 每次读取都要先seek,貌似缓冲区用不上,特别慢,比连续读一个段的数据,并用lambda过滤慢四五倍 写入 前面说过了,只append,不修改数据,而且每行日志最前面是时间戳。 多线程 查询数据,可以多线程同时查询,每次查询都会打开一个新的日志文件的描述符,所以并行的多个读取不会打架。 写入的话,虽然只是append操作,但不确认多线程对文件进行append操作是否安全,所以建议用一个队列,一个专用线程进行写入。 锁 没有任何锁。 排序 默认查询出来的数据是按时间正序排列,如需其它排序,可取到内存后用python的sorted函数排序,想怎么排就怎么排。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值