背景
1. 关于本文
项目中Python需要与mysql进行交互,很自然地想到了用sqlalchemy包。本文是我自己操作中的一些理解,用的是ORM方式进行操作,重在代码实践。
我认为不管学什么,最难的就是入门了!所以我只想写一点在工程上,可以把初学者领进门的东西!我相信人对某个知识点一旦有初步理解之后,剩下条条框框细节的学习,通过时间积累即可!因此,我把能忽略的尽量忽略,概念性地知识可以参照其他文章。
2. ORM概念
ORM(Object-Relational Mapping)就是在python中设定一个类,在mysql中定义一个表,把关系数据库的表结构映射到这个类上。
3. 操作前提
关于操作前提,这里就不介绍了。以下三点必须吧!!
1. 安装好Python
2. 安装好mysql
3. 安装好sqlalchemy包
代码
包括:配置模块、连接模块、模型模块、操作模块、测试模块
1. 配置模块: mysql_config
# -*- coding: utf-8 -*-
class Conf(object):
MYSQL = {
'host': '127.0.0.1', # 换成你自己的ip地址
'port': 3306, # 换成你自己的端口号,以下也一样
'username': 'bigdata',
'password': 'bigdata',
'database': 'logdb'
}
def get_config(section, option):
try:
config = Conf()
return getattr(config, section)[option]
except AttributeError:
print 'section {0} is not available!'.format(section)
except KeyError:
print 'option {0} is not available!'.format(option)
2. 连接模块: mysql_conn
# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.engine.url import URL
from sqlalchemy.orm import scoped_session, sessionmaker
import mysql_config as mc
# 数据库连接
conn_url = URL(
drivername='mysql',
username=mc.get_config('MYSQL', 'username'),
password=mc.get_config('MYSQL', 'password'),
host=mc.get_config('MYSQL', 'host'),
port=mc.get_config('MYSQL', 'port'),
database=mc.get_config('MYSQL', 'database'),
query={'charset': 'utf8'}
)
#返回一个数据库引擎,echo参数为true时,会显示每条执行的sql语句,生产环境下可关闭
engine = create_engine(conn_url, encoding='utf-8', echo=False)
"""
sessionmaker会生成一个数据库会话类,实例可当成一个数据库链接,同时记录了一些查询的数据,
并决定什么时候执行sql.scoped_session保证每个线程获得的session对象是唯一的.
"""
session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
3. 模型模块: mysql_models
# -*- coding: utf-8 -*-
from sqlalchemy import Integer, String, DateTime, Column
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime
from mysql_conn import session
# Model基类,创建了一个BaseModel类,这个类的子类可以自动与一个表关联
Base = declarative_base()
# 这样设置以后直接可以通过model类进行query查询,否则必须通过session进行查询。
Base.query = session.query_property()
class Log(Base):
'''
对应数据库中的表
'''
__tablename__ = 'log'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String(128), nullable=False)
insert_time = Column(DateTime, nullable=False, default=datetime.now())
update_time = Column(DateTime, nullable=False, default=datetime.now())
path = Column(String(128), nullable=False)
log_number = Column(Integer, nullable=False)
def getSelf(self):
return '['+str(self.id) + '-' + self.name + '-' + str(self.insert_time) + '-' + str(self.update_time) + '-' + self.path + '-' + str(self.log_number)+']'
4. 操作模块: mysql_dao
# -*- coding: utf-8 -*-
import mysql_conn as db
import mysql_models as m_models
from sqlalchemy import event
from sqlalchemy.schema import DDL
class MysqlDao(object):
def initDB(self):
'''
1. 用DDL方式,为unique键添加自动增长
2. 初始化数据库,找到BaseModel的所有子类,并在数据库中建立这些表,models里面的数据,bind绑定一个会话链接
'''
event.listen(
m_models.Log.__table__,
'after_create',
DDL("alter table log MODIFY id INT AUTO_INCREMENT;")
)
m_models.Base.metadata.create_all(bind=db.engine)
def insert(self, element):
'''
单条插入mysql数据库
'''
flag = False
try:
db.session.add(element)
db.session.commit()
flag = True
except Exception,e:
print e, '\nerror element:'+element.getSelf()+'\t插入数据库失败,请查看主键以及唯一键约束!'
db.session.rollback()
db.session.flush() # for resetting non-commited .add()
finally:
return flag
def insertBatch(self, element_list):
'''
批量插入数据库
'''
successNum = 0
failNum = 0
for element in element_list:
if self.insert(element):
successNum += 1
else:
failNum += 1
return successNum, failNum
def insertLogtBulk(self, element_list, batch_num, type):
'''
批量插入mysql数据库Log表,一次批量插入batch_num条数据
'''
mysql_batch_list = []
mysql_batch_num = batch_num
for element in element_list:
# 先检查在mysql中是否存在该条记录, 不存在则插入mysql
follow_item_exist = getattr(m_models, type).query.filter_by(id=element.id).first()
if not follow_item_exist:
mysql_batch_list.append(element)
mysql_batch_num -= 1
else:
print "数据库Log表,已经存在记录:", element.getSelf()
# 如果mysql_batch_num 自减到0,则提交到数据库
if not mysql_batch_num:
db.session.add_all(mysql_batch_list)
db.session.commit()
mysql_batch_num = batch_num
mysql_batch_list = []
db.session.add_all(mysql_batch_list)
db.session.commit()
5. 测试模块: mysql_test
# -*- coding: utf-8 -*-
from mysql_models import Log
from mysql_dao import MysqlDao
from datetime import datetime
if __name__ == "__main__":
log1 = Log(name="aa", insert_time=datetime.now(), update_time=datetime.now(), path='aa-path', log_number=10)
log2 = Log(name="bb", insert_time=datetime.now(), update_time=datetime.now(), path='bb-path', log_number=22)
element_list = [log1, log2]
mysql_dao = MysqlDao()
mysql_dao.initDB() # 测试initDB方法,初始化数据库
mysql_dao.insertLogtBulk(element_list, 20, "Log")
# print mysql_dao.insertBatch(element_list) # 测试插入方法
直接运行mysql_test即可。
6. 结果展示
mysql中log表内容
mysql中log表信息
代码说明
mysql_config: 记录mysql配置的文件,运行前必须配置。
mysql_conn: 连接模块,负责python和mysql之间的连接
mysql_models: 模型模块,在此可以添加多个模型,用于和数据库中多张表进行“对象关系映射”。一个类对应一张表。
mysql_dao: Python和mysql进行操作的模块,把增删改查操作都写到这个模块下,目前本文写了批量插入的两种实现方式。
mysql_test: 测试模块,最顶层的操作都放在这里即可。
模块之间的关系依赖如下图所示:
好吧!!其实我不是很满意~因为模块之间的耦合度还是太高了。身为程序员,应该想着把这图中代表依赖关系的线尽量减少。这个代码还会改进的~~
参考资料
官网:
http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html#common-filter-operators
其他:
http://www.jb51.net/article/49789.htm
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0014021031294178f993c85204e4d1b81ab032070641ce5000
http://www.dongwm.com/archives/sqlalchemyjiaochengyi/