Python數據持久化操作簡單比較
Python的數據持久化操作主要是六類:普通文件、DBM文件、Pickled對象存儲、shelve對象存儲、對象數據庫存儲、關系數據庫存儲。
普通文件不解釋了,DBM就是把字符串的鍵值對存儲在文件里:
Python代碼
% python
>>> import anydbm
>>> file = anydbm.open('movie', 'c') # make a DBM file called 'movie'
>>> file['Batman'] = 'Pow!' # store a string under key 'Batman'
>>> file.keys( ) # get the file's key directory
['Batman']
>>> file['Batman'] # fetch value for key 'Batman'
'Pow!' Pickled就是把對象序列化到文件,可以存儲復雜類型:
Python代碼
% python
>>> table = {'a': [1, 2, 3],
'b': ['spam', 'eggs'],
'c': {'name':'bob'}}
>>>
>>> import pickle
>>> mydb = open('dbase', 'w')
>>> pickle.dump(table, mydb) 下面是反序列化:
Python代碼
% python
>>> import pickle
>>> mydb = open('dbase', 'r')
>>> table = pickle.load(mydb)
>>> table
{'b': ['spam', 'eggs'], 'a': [1, 2, 3], 'c': {'name': 'bob'}} shelve存儲差不多就是DBM和Pickled方式的結合,以鍵值對的形式把對象序列化到文件:
Python代碼
% python
>>> import shelve
>>> dbase = shelve.open("mydbase")
>>> object1 = ['The', 'bright', ('side', 'of'), ['life']]
>>> object2 = {'name': 'Brian', 'age': 33, 'motto': object1}
>>> dbase['brian'] = object2
>>> dbase['knight'] = {'name': 'Knight', 'motto': 'Ni!'}
>>> dbase.close( ) 取數據:
Python代碼
% python
>>> import shelve
>>> dbase = shelve.open("mydbase")
>>> len(dbase) # entries
2
>>> dbase.keys( ) # index
['knight', 'brian']
>>> dbase['knight'] # fetch
{'motto': 'Ni!', 'name': 'Knight'} 對象數據庫的存儲沒怎么了解,因為不習慣用它存儲數據。感覺應該和shelve差不多吧,只是把數據保存到了數據庫里(其實還是一個文件嘛),然后增加了些事務之類的高級功能。
Python中關系數據庫的存儲是重點,操作關系數據庫最“簡單”的就是直接用DB-API,就像Java里的JDBC;當然,數據結構復雜了、設計要求高了,就得找些ORM框架偷懶了,主要有獨立的SQLAlchemy,Django的自帶ORM等。這部分內容還是下一篇博客寫吧,我不喜歡文章拉得長長的……
簡單比較Python的數據持久化操作(二)
Python中操作關系數據庫最直接的就是用DB-API了,流程一般是:連接、執行SQL語句、提交、斷開。以MySQL為例,下面是各步驟的代碼示例:
首先是連接:
Python代碼
% python >>> import MySQLdb >>> conn = MySQLdb.connect(host='localhost', user='root', passwd='python')
接著便可以執行語句了,但在執行SQL語句前要先獲取指針:
Python代碼
>>> curs = conn.cursor( )
>>> curs.execute('create database peopledb')
1L
>>> curs.execute('use peopledb')
0L
>>> tblcmd = 'create table people (name char(30), job char(10), pay int(4))'
>>> curs.execute(tblcmd)
0L 添加數據:
Python代碼
>>> curs.execute('insert people values (%s, %s, %s)', ('Bob', 'dev', 5000))
1L
>>> curs.executemany('insert people values (%s, %s, %s)',
... [ ('Sue', 'mus', '70000'),
... ('Ann', 'mus', '60000')])
2L
>>> conn.commit( ) 執行查詢:
Python代碼
>>> curs.execute('select * from people')
6L
>>> curs.fetchall( )
(('Bob', 'dev', 5000L), ('Sue', 'mus', 70000L), ('Ann', 'mus', 60000L), ('Tom',
'mgr', 100000L)) 執行完數據庫操作記得斷開連接:
Python代碼
conn.close( ) # close, _ _del_ _ call rollback if changes not committed yet
如果數據結構不是很復雜,配合Python強大的列表解析能力,不用ORM框架也是很方便的;或者自己封裝對象映射也不是很難。
如果使用了Django框架,可以使用它自帶的ORM工具來操作數據庫。首先當然是編寫實體類(或者叫模型)了:
Python代碼
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField() Python的代碼已經很清楚了,類對應表,成員變量對應表的列,列屬性由models.XXXField(…)定義。如果實體類沒有顯式定義主鍵,Django會默認加上一句:
Python代碼
id = models.AutoField(primary_key=True)
Django里可以這樣定義枚舉型數據:
Python代碼
class Person(models.Model):
GENDER_CHOICES = (
(u'M', u'Male'),
(u'F', u'Female'),
)
name = models.CharField(max_length=60)
gender = models.CharField(max_length=2, choices=GENDER_CHOICES) 對于關聯關系,在做列的映射定義時可以這么寫:
Python代碼
poll = models.ForeignKey(Poll) sites = models.ManyToManyField(Site) place = models.OneToOneField(Place")
在Django里定義關聯關系還有更多功能,詳細的還是看官方文檔吧~
Django的Model基類中已經定義了基本的數據庫操作,因為所有的實體類都是繼承自Model類,所以也就有了這些操作。例如新建并保存一個person只需要這么做:
Python代碼
>>> p = Person(name="Fred Flinstone", gender="M") >>> p.save()
Django會通過查詢對象的主鍵是否存在來決定該UPDATE還是INSERT,當然你也可以強制框架執行某種操作。如果你不滿意框架自帶的方法,可以重寫它:
Python代碼
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
do_something()
super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
do_something_else() 發現沒,Django里存取數據不需要那種session,最討厭Hibernate里的session了,總是報“Session Closed”錯誤……
Python還有一個獨立的ORM框架——SQLAlchemy。功能更強大,支持的數據庫也比Django自帶的ORM工具要多。它有兩種建立實體類的方法。
一種是分開定義,再將表定義和類定義映射起來。首先是建立表的定義:
Python代碼
>>> from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
>>> metadata = MetaData()
>>> users_table = Table('users', metadata,
... Column('id', Integer, Sequence('user_id_seq'), primary_key=True),
... Column('name', String(50)),
... Column('fullname', String(50)),
... Column('password', String(12))
... ) 接著定義實體類:
Python代碼
>>> class User(object): ... def __init__(self, name, fullname, password): ... self.name = name ... self.fullname = fullname ... self.password = password
這還沒完,還要把他們映射起來:
Python代碼
>>> from sqlalchemy.orm import mapper >>> mapper(User, users_table)
這樣的過程有點像Hibernate里將XML的Map文件和實體類的映射。Hibernate中還可以方便的直接用注釋在實體類中完成與表的映射,當然SQLAlchemy也有直接的方法:
Python代碼
>>> from sqlalchemy.ext.declarative import declarative_base >>> Base = declarative_base() >>> class User(Base): ... __tablename__ = 'users' ... ... id = Column(Integer, primary_key=True) ... name = Column(String) ... fullname = Column(String) ... password = Column(String)
作為一個獨立的ORM框架,實體類的存取當然就不會像Django那樣集成的那么完美了,SQLAlchemy里存取數據也是要Session的:
Python代碼
>>> from sqlalchemy.orm import sessionmaker >>> Session = sessionmaker(bind=engine)
這里的engine對象需要這樣建立:
Python代碼
>>> from sqlalchemy import create_engine
>>> engine = create_engine('<span style="font-family: monospace; white-space: normal; color: #333333; line-height: 20px;">dialect+driver://user:password@host/dbname[?key=value..]</span>', echo=True) 對于存取操作,如果是保存就這么寫:
Python代碼
>>> ed_user = User('ed', 'Ed Jones', 'edspassword')
>>> session.add(ed_user) 如果要查詢,就是類似的這種形式:
Python代碼
>>> our_user = session.query(User).filter_by(name='ed').first()
執行完一些數據操作,必要的時候要提交或是回滾:
Python代碼
>>> session.rollback() 或者 >>> session.commit()
SQLAlchemy框架還有一個衍生產品——Elixir,在SQLAlchemy的基礎上對其映射方式做了些封裝,使得實體類的定義有點類似Django中的定義方式。
話說Django的ORM與它的其他模塊結合的很緊密,不好單獨使用;SQLAlchemy雖然強大,但風格不太喜歡,所以下一步打算深入兩個ORM框架的代碼,看看他們是怎么實現的。一方面好抉擇用哪一個,另外也可以看看在自己的應用中能否自己做一個簡單的ORM。