前回に引き続いて、データ保存周りのおさらいです。
その他のおさらい事項にについては、以下ご参照ください。
[ざっくりPythonのおさらい その1。基本文法など]
https://qiita.com/48hands/items/31b7ac2b49addbb8658c
[ざっくりPythonのおさらい その2。おもにデータ保存]
https://qiita.com/48hands/items/ab86b7463268e669d216
[ざっくりPythonのおさらい その3。Numpy, Pandas]
https://qiita.com/48hands/items/b1a71000533e129b27f2
PythonからRDBを扱う
事前にmysql-connector-python
, sqlalchemy
, pymysql
をパッケージインストールしておく。
pip install mysql-connector-python sqlalchemy pymysql
ORMを使わない実装例
SQLite3
import sqlite3
# コネクション生成 ファイルに永続化したい場合
conn = sqlite3.connect('my_sqlite.db')
# コネクション生成 メモリ上で完結させる場合はこっちを使う。
# conn = sqlite3.connect(':memory:')
# カーソルの生成
cursor = conn.cursor()
# テーブルの作成
sql = """
CREATE TABLE IF NOT EXISTS persons(
id INTEGER PRIMARY KEY AUTOINCREMENT
,name STRING
)
"""
cursor.execute(sql)
conn.commit()
# データのINSERT
cursor.execute("INSERT INTO persons(name) VALUES('Hanako')")
cursor.execute("INSERT INTO persons(name) VALUES('Taro')")
cursor.execute("INSERT INTO persons(name) VALUES('Yuichi')")
cursor.execute("INSERT INTO persons(name) VALUES('Makio')")
conn.commit()
# データのSELECT
sql = "SELECT * from persons"
cursor.execute(sql)
# カーソルに結果が入っているので受け取る
# fetchall()メソッドを使う。
result = cursor.fetchall()
for user_id, name in result:
print(user_id, name)
# コネクションのクローズ
conn.close()
MySQL
ほとんどSQLiteと同じ。
import mysql.connector
# コネクションの設定
conn = mysql.connector.connect(host='127.0.0.1', port=3306, user='root',
# password='password',
# database='my_db'
)
# カーソルの生成
cursor = conn.cursor()
# データベース作成
cursor.execute('CREATE DATABASE IF NOT EXISTS my_db')
# テーブル作成
cursor.execute('CREATE TABLE IF NOT EXISTS my_db.persons('
'id int NOT NULL AUTO_INCREMENT,'
'name varchar(20) NOT NULL,'
'PRIMARY KEY(id)'
')')
# データのINSERT
for i in range(10):
cursor.execute(
'INSERT INTO my_db.persons(name) values("Robot-{}")'.format(str(i + 1)))
# コミット
conn.commit()
# データのSELECT
cursor.execute('SELECT * FROM my_db.persons')
for user_id, name in cursor.fetchall():
print(user_id, name)
# カーソルのクローズ
cursor.close()
# コネクションクローズ
conn.close()
SQLAlchemyを使った実装
データベースをSQLiteのメモリに設定する場合は以下。
personsテーブルを作成してPersonオブジェクトとして扱えるようにしている。
import sqlalchemy
import sqlalchemy.ext.declarative
import sqlalchemy.orm
# sqliteを使ってメモリで完結させる。
# echoをTrueにすると、実際に発行したSQLを確認できる
engine = sqlalchemy.create_engine('sqlite:///:memory:', echo=True)
# おまじない
Base = sqlalchemy.ext.declarative.declarative_base()
# Personモデルの定義
class Person(Base):
__tablename__ = 'persons'
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True,
autoincrement=True)
name = sqlalchemy.Column(sqlalchemy.String(20))
# これを実行するとメモリ上にpersonsテーブルが作成される。
Base.metadata.create_all(engine)
# セッションの作成
Session = sqlalchemy.orm.sessionmaker(bind=engine)
session = Session()
# データの登録
person_list = [Person(name='Hanako'), Person(name='Taro'), Person(name='Makio')]
for p in person_list:
# addメソッドを使って登録する
session.add(p)
session.commit()
# データを取得してnameを変更してupdateする。
p1 = session.query(Person).filter_by(name='Taro').first()
p1.name = 'Mike'
session.add(p1)
session.commit()
# データを削除する
p1 = session.query(Person).filter_by(name='Hanako').first()
session.delete(p1)
session.commit()
# 一覧を取得する
persons = session.query(Person).all()
for person in persons:
print(person.id, person.name)
データベースをSQLiteのファイルに永続化する場合はengine
を以下のように設定する。
engine = sqlalchemy.create_engine('sqlite:///dev_db_sqlalchemy', echo=True)
データベースをMySQLにしたい場合は、以下のように設定する。
# mysql+pymysqlを指定する
url = 'mysql+pymysql://username:password@127.0.0.1/my_db'
engine = sqlalchemy.create_engine(url, echo=True)
PythonのDBMを扱う
DBMはPythonの標準ライブラリ。
簡単にキャッシュの保存などを使いたい場合に利用するらしい。
import dbm
with dbm.open('cache', 'c') as db:
# 文字列をキャッシュとして保存する
db['key1'] = 'value1'
db['key2'] = 'value2'
# NOTE: 数値はそのまま保存するとエラーになる。文字列のみ対応している。
# db['key3'] = 123
with dbm.open('cache', 'r') as db:
print(db.get('key1')) # b'value1'となり、バイナリ型になって表示される
print(db.get('key2').decode('utf-8')) # utf-8でデコードするとvalue2として表示される
b'value1'
value2
PythonからMemchachedを扱う
Memchachedは、データをメモリ上に保存しておいてデーベースへのアクセスの前に参照してデータベースにアクセスする回数を減らしたりするために使ったりするソフトウェア。
[Memcheched]
http://memcached.org/
Memchachedのインストール
# Linuxの場合
wget https://www.memcached.org/files/memcached-1.5.10.tar.gz
tar -zxvf memcached-1.5.10.tar.gz
cd memcached-1.5.10
./configure && make && make test && sudo make install
# Macの場合はbrew installでできる。
brew install memcached
brew services start memcached
# python-memchacheパッケージをインストールしておく
pip install python-memcached
Pythonから扱うためのコードは以下。
import memcache
# memcacheのクライアント設定
db = memcache.Client(['127.0.0.1:11211'])
# キーバリューの形式でセットする。
db.set('key1', 'value1')
db.set('key2', 'value2')
# データの取得
print(db.get('key1'))
保持する時間を設定できる。
以下のようにtime
に値をセットする。
import time
import memcache
# memcacheのクライアント設定
db = memcache.Client(['127.0.0.1:11211'])
# キーバリューの形式でセットする。
db.set('key1', 'value1', time=1)
# データの取得
print(db.get('key1'))
# sleepする
time.sleep(2)
# データ取得できないことを確認する。
# 値が取れない場合はNoneが返却される
print(db.get('key1'))
実行すると、以下のようになる。
value1
None
RDBとMemcacheの併用
準備として、SQLiteにデータを入れておく。
import sqlite3
cursor.execute('CREATE TABLE IF NOT EXISTS persons'
'(id INTEGER PRIMARY KEY AUTOINCREMENT, name STRING)')
cursor.execute('INSERT INTO persons(name) VALUES("Makio")')
conn.commit()
conn.close()
この状態でMemchacheから値が取れなかった場合に、DBアクセスする。
import sqlite3
import memcache
# memcacheのクライアント設定
mem = memcache.Client(['127.0.0.1:11211'])
# SQLiteのコネクション、カーソル設定
conn = sqlite3.connect('test_sqlite_memcached.db')
cursor = conn.cursor()
def get_person_id(name):
"""
nameからidを返却するメソッド
"""
# Memcachedからidがとれればそのまま返却
# DBにアクセスしない。
person_id = mem.get(name)
if person_id:
return person_id
# 以下はMemchachedにデータがない場合
# DBに対して検索処理
sql= 'SELECT * FROM persons WHERE name = "{}"'.format(name)
cursor.execute(sql)
person = cursor.fetchone()
if not person:
raise Exception('No person data')
person_id, name = person # アンパッキング
# 60秒以内だったらMemchacheから値を参照できるように
# Memchachedに値を設定しておく。
mem.set(name, person_id, time=60)
return person_id
print(get_person_id("Makio"))
Pickleを使ったオブジェクトの保存
Pythonのデータをそのまま保存するライブラリ
import pickle
class Person(object):
def __init__(self, name):
self.name = name
obj = {
'key1': [1,2,3,4,5],
'key2': ['dev', 'prod', 'test'],
'key3': Person('Makio')
}
# データの保存処理。
# バイナリ形式でオブジェクトを保存する。
with open('obj.pickle', 'wb') as f:
pickle.dump(obj, f)
# pickleファイルからデータを読み込む。
with open('obj.pickle', 'rb') as f:
read_obj = pickle.load(f)
# 読込できたか確認する。
print(read_obj)
print(read_obj['key1'])
print(read_obj['key2'])
print(read_obj['key3'].name)
実行結果。
{'key1': [1, 2, 3, 4, 5], 'key2': ['dev', 'prod', 'test'], 'key3': <__main__.Person object at 0x10e328588>}
[1, 2, 3, 4, 5]
['dev', 'prod', 'test']
Makio