sqlalchemy 介绍和使用示例

背景

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/

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值