#! /usr/bin/env python3

# -*- coding:utf-8 -*-

#use SQLAlchemy

#ORM:Object-Relational Mapping ,把关系数据库的结构映射到对象上,SQLAlchemy是Python中有名的ORM框架

#导入sqlalchemy

from sqlalchemy import Column,String,create_engine

from sqlalchemy.orm import sessionmaker

from sqlalchemy.ext.declarative import declarative_base

#创建对象的基类:

Base=declarative_base()  #这个语句创建了一个Base类,这个类的子类可以自动与一个表关联

#定义创建表的函数

def init_db():

Base.metadata.create_all(engine) #该语句会找到base的所有子类,并在数据库中创建这些表,drop_all则是删除这些表

#定义删除表的函数

def drop_db():

Base.metadata.drop_all(engine)

#定义User表对象:

class User2(Base):

#表名:

__tablename__='user2'

#表结构:

id=Column(String(20),primary_key=True)

name=Column(String(20))

#初始化数据库连接:

DB_CONNECT_STRING='mysql+pymysql://rduser:1qaz@WSX@172.18.28.110:3306/test?charset=utf8'

#'mysql+pymysql'指定了使用mysql-python来连接  数据库名test和连接时使用的字符集charset=utf8可以省略。

engine=create_engine(DB_CONNECT_STRING,echo=True)

#create_engine()会返回一个数据库引擎,echo参数为True时,会显示每条执行的sql语句,生产环境下可关闭。

#创建DBSession类型:

DBSession=sessionmaker(bind=engine)

#sessionmaker()会生成一个数据库会话类。这个类的实例可以当成一个数据库连接,它同时还记录了一些查询的数据,并决定什么时候执行sql语句。

session=DBSession()

#init_db()

#以上代码完成SQLAlchemy 的初始化和具体每个表的class定义。如果有多个表就继续定义其他class,例School:

'''

class School(Base):

__tablename__='school'

id=...

name=...

'''

#create_engine()用来初始化数据库连接。SQLAlchemy用一个字符串表示连接信息:

# ‘数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名’

#根据需要替换掉用户名、口令等信息即可

#由于有了ORM,我们向数据库表中添加一行记录,可以视为添加一个User对象:

#创建session对象:

session=DBSession()

#创建新User对象,添加新记录:

new_user=User2(id='1',name='Glace')

#添加到session:

session.add(new_user)  #写入数据

user=User2(id='3',name='Smith')

session.add(user)

#提交即保存到数据库:

session.commit()

#关闭session:

session.close()

#可见,关键是获取session,然后把对象添加到session,最后提交并关闭。DBSession对象可视为当前数据库连接。

#有了ORM,查询出来的可以不再是tuple,而是User对象,sqlalchemy提供的查询接口如下:

#创建Session:

session=DBSession()

#创建DBSession类型:Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行:

print(session.query(User2).filter(User2.id=='5').one())

print(session.execute('select * from User2 where id=:id',{'id':7}).first())

#打印类型和对象的name属性:

print('type:',type(User2))

print('name:',User2.name)

#关闭Session:

session.close()

#type: <class 'sqlalchemy.ext.declarative.api.DeclarativeMeta'>

#name: User2.name

#可见,ORM就是把数据库表的行与相应的对象建立关联,互相转换。

#由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应的,ORM矿建也可以提供两个对象之间的一对多、多对多等功能。

#例如,如果一个User拥有多个Book,就可以定义一对多的关系:

'''

class User(Base):

__tablename__ = 'user'

id = Column(String(20), primary_key=True)

name = Column(String(20))

# 一对多:

books = relationship('Book')

class Book(Base):

__tablename__ = 'book'

id = Column(String(20), primary_key=True)

name = Column(String(20))

# “多”的一方的book表是通过外键关联到user表的:

user_id = Column(String(20), ForeignKey('user.id'))

'''

#当我们查询一个User对象时,该对象的books属性将返回一个包含若干个Book对象的list

#ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。

http://docs.sqlalchemy.org/en/devel/

sqlalchemy通过被用作ORM框架,也可以当作普通的数据库接口使用,内带数据库连接池

from sqlalchemy import create_engine

conf="dialect+driver://username:password@host:port/database"    dialect表示数据的名字,diver表式连接数据库使用的模块名

example="mysql+pymysql://user:mima@192.168.2.251:3306/mydatabase?charset=utf8"           mysql

engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/mydatabase')                                                postgresql

engine = create_engine('oracle://scott:tiger@127.0.0.1:1521/sidname')                                                                     oracle

engine = create_engine('mssql+pymssql://scott:tiger@hostname:port/dbname')                                                        sql server

engine = create_engine('sqlite:///foo.db')                                                                                                                     sqlite

engine=create_engine(conf,echo=True)      #echo是sqlalchemy内部的日志输出开关,默认为false

engine是一个数据库连接管理器, 创建engine时,实际上就创建了一个连接池pool和会话语法dialect

http://docs.sqlalchemy.org/en/devel/core/engines.html,sqlalchemy自带了很多数据连接引擎,个别需要安装相应模块,详见Dialectshttp://docs.sqlalchemy.org/en/devel/dialects/index.html

通过create_engine被创建时并没有实际连接数据库(表现为惰性连接),只有当engine。execute()或engine。connect()被首次执行时,才会创建实际的数据库连接。

创建个性化连接

def connect():
    return psycopg.connect(user='scott',host='localhost')

db=create_engine('postgresql://',creator=connect)

conn=engine.connect()

results=conn.execute('select username from users')  #ins可以是通过sqlalchemy创建的orm对象,也可以是sql语句

for row in results:
    print(username',row['username'])

conn.close()

这个conn是一个connection实例,为实际DBAPI连接的代理对象

results是代理结果实例,同DBAPI的cursor相联系,拥有大多cursor的特性。

当代理结果中的所有返回的rows被取出后,cursor就自动关闭了,例对于一个update操作不会返回row,cursor就会立刻关闭。

直接使用conn.execute(),是自动提交commit模式.即隐式提交

显式创建事务

conn=engine.connect()

trains=conn.begin()

try:

  results=conn.execute()

  r1=conn.execute(table.insert(),col1=7,col2='this is some data')

trans.commit()

except:

trans.rollback()

 raise

也可写作

with engine.begin() as connection:

r1=conn.execute(table.insert(),col1=7,col2='this is some data')

 r2=conn.execute()

with connection.begin() as trans:
r1 = connection.execute(table1.select())
connection.execute(table1.insert(), col1=7, col2='this is some data')

r1.fetchall() 调用完一次后,再次调用就会返回一个空列表

r1.fetchmany()

r1.fetchone()

r1.lastrowid

r1.rowcount执行update或delete时返回的受影响行数

r1.close()关闭cursor

conn.close()

Pooling连接池

https://docs.sqlalchemy.org/en/latest/core/pooling.html

连接池是一个用于维护数据库 的 长时间连接,高效复用,对并发连接数 进行管理的标准技术

可以在创建engine时就传入参数进行自定义

engine=create_engine('postgresql://me@localhost/mydb',pool_size=20,max_overflow=0)

当engine执行connect()或execute()时,就会向连接池获取一个连接,连接池的默认模式为QueuePool,根据需要创建连接的模式。

QueuePool的默认连接数是5,最大连接数是10. 应该保持一个数据库一个engine,而不是为每次连接创建一个engine

所有的sqlalchemy连接池都不会预先创建连接,直到第一次被使用。

使用不同的pool模式,通过poolclass:

from sqlalchemy.pool importQueuePool

engine=create_engine('sqlite://file.db',poolclass=QueuePool)

禁用连接池,使用NullPool

engine=create_engine('postgresql+pscopg2://scott:tiger@localhost/test',poolclass=NullPool)

所有的pool类接收一个creator参数,用于创建一个新连接。 create_engine()接收这个参数,用来连接数据库

import sqlalchemy.pool as pool

import psycopg2

def getconn():

c=psycopg2.connect(username='ed',host='127.0.0.1',dbname='test')

return c

engine=create_engine('postgresql+psycopg2://',creator=getconn)

单独使用pool

mypool=pool.QueuePool(getconn,max_overflow=10,pool_size=5)

cursor=conn.cursor()

cursor.execute('select foo')

conn.close()

调用完conn.close()这个连接就被关闭,返还回连接池

 连接池事件Pool Event 

连接池支持一个事件接口用于处理上一个连接,基于每一个新的连接

关闭连接的处理

连接池可以刷新所有的单个连接,和它的连接设置,将池中之前的连接设置为无效。

比较适合用于数据库重启后导致之前池中所有连接失效时连接池的连接回收。有两者方法来实现它:

悲观处理关闭(每有一个新的的连接就发出一个简单的连接测试比例select 1,一旦该次结果返回异常,就认为连接断开了,这个连接会立即被回收,该连接之前的所哟连接也会被标记为无效,都会在使用之前被回收)

engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)

乐观处理的方式之一  设置连接池的回收时长
e=create_engine("mysql://scott:tiger@localhost/test",pool_recycle=3600)
这样会使所有超过3600秒的连接被设置为无效连接并被替换。标记为无效的操作只在检查的过程的发生,而不是在每一个已被检查过的连接。
pool_recycle是连接池自带的功能,依赖于一个engine是否在被使用。
这个设置适用于MySQL,MySQL会在间隔一个固定时间后自动关闭连接

在多进程中使用连接池

http://docs.sqlalchemy.org/en/devel/core/pooling.html

通常不建议在子进程中单独创建engine.

既不是在子进程中创建新的engine,也不是使用一个已存在的engine,而是调用engine.dispose(),在子进程开始connection之前。该方法会移除连接池中所有已存在的连接,重新创建所有的连接。写作如下:

TCP connections are represented as file descriptors, which usually work across process boundaries, meaning this will cause concurrent access to the file descriptor on behalf of two or more entirely independent Python interpreter states.

这意味这当前的到这个文件的连接代表这两个或者更多的完全独立的python接口状态,(可能是说,这个数据库的连接也代表了其他进程里的连接)

方法之一就是在 子进程创建连接之前调用 engine.dispose() 方法,dispose()是用于清除其他子进程中的连接,使在该进程的连接不影响其他的进程中的连接

engine=create_engine('...')

def run_in_process():
    engine.dispose()

with eng.connect() as conn:

    conn.execute('...')

p=Process(tartget=run_in_process)

另一种方式是设置连接池的事件,让其他的连接在这个子进程里自动失效,这种方式可能更合适

from sqlalchemy import event

from sqlalchemy import exc

import os

eng=create_engine('..')

@event.listens_for(engine,"connect")

def connect(dbapi_connection,connection_record):

  connection_record.info['pid']=os.getpid()

@event.listens_for(engine,"checkout")

def checkout(dbapi_connection,connection_record,connection_proxy):

  pid=os.getpid()

  if connection_record.info['pid']!=pid:

    connection_record.connection=connection_proxy.connection=None

    raise exc.DisconnectionError(

       "Connection record belongs to pid %s,"

       "attempting to check out in pid %s"%(connection_record.info['pid'],pid))

将sqlalchemy内置log部分加入日志,echo=True只是用于控制台的输出。

import logging

logging.basicConfig()

logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)

sqlalchemy 简介的更多相关文章

  1. SQLAlchemy简介

    一.SQLAlchemy简介 SQLAlchemy是Python SQL工具包和对象关系映射器,是python中最著名的ORM(Object Relationship Mapping)框架,它简化了应 ...

  2. ORM SQLAlchemy 简介

    对象关系映射(Object Relational Mapping,简称ORM使用DB-API访问数据库,需要懂 SQL 语言,能够写 SQL 语句,如果不想懂 SQL,又想使用关系型数据库,可以使用 ...

  3. python数据库操作之pymysql模块和sqlalchemy模块(项目必备)

    pymysql pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同. 1.下载安装 pip3 install pymysql 2.操作数据库 (1).执行sql #! ...

  4. SQLAlchemy 教程 —— 基础入门篇

    SQLAlchemy 教程 -- 基础入门篇 一.课程简介 1.1 实验内容 本课程带领大家使用 SQLAlchemy 连接 MySQL 数据库,创建一个博客应用所需要的数据表,并介绍了使用 SQLA ...

  5. Flask简介,安装,demo,快速入门

    1.Flask简介 Flask是一个相对于Django而言轻量级的Web框架. 和Django大包大揽不同,Flask建立于一系列的开源软件包之上,这其中 最主要的是WSGI应用开发库Werkzeug ...

  6. Python SQLAlchemy 模块

    SQLAlchemy 简介: SQLAlchemy 是用于实现 ORM(Object Relational Mapping,对象关系映射)的一个模块,即把数据库的表结构映射到对象上在 Python 中 ...

  7. SQLAlchemy和Flask-SQLAlchemy

    一.ORM 与 SQLAlchemy 简介 ORM 全称 Object Relational Mapping, 翻译过来叫对象关系映射.简单的说,ORM 将数据库中的表与面向对象语言中的类建立了一种对 ...

  8. SQLAlchemy 简单笔记

    ORM 江湖##### 曾几何时,程序员因为惧怕SQL而在开发的时候小心翼翼的写着sql,心中总是少不了恐慌,万一不小心sql语句出错,搞坏了数据库怎么办?又或者为了获取一些数据,什么内外左右连接,函 ...

  9. 偏于SQL语句的 sqlAlchemy 增删改查操作

    ORM 江湖 曾几何时,程序员因为惧怕SQL而在开发的时候小心翼翼的写着sql,心中总是少不了恐慌,万一不小心sql语句出错,搞坏了数据库怎么办?又或者为了获取一些数据,什么内外左右连接,函数存储过程 ...

随机推荐

  1. python基础和进阶思维导图(转)

  2. composer修改中文镜像

    composer config -g repo.packagist composer https://packagist.phpcomposer.com

  3. eQTL | Expression quantitative trait loci | 数量性状位点 | 表达数量性状基因座

    一篇通俗的文章:eQTL Expression quantitative trait loci (eQTLs) are genomic loci that explain all or a fract ...

  4. 荧光原位杂交技术 RNA-FiSH (fluorescence in situ hybridization)

    通俗理解:带有荧光标记的DNA探针可以用于检测活体内特定基因的表达情况,活体成像. 荧光原位杂交方法是一种物理图谱绘制方法,使用荧光素标记探针,以检测探针和分裂中期的染色体或分裂间期的染色质的杂交.荧 ...

  5. 有序广播和标准广播 --Android开发

    一.标准广播和有序广播也很容易理解的. 标准广播: (1)通过sendBroadcast()方法发送 (2)通过异步方式发送,广播接收者的执行顺序是不明确的 有序广播: (1)通过sendOrderB ...

  6. Vue.js示例:文本编辑器。使用_.debounce()反抖动函数

    Markdown编辑器 https://cn.vuejs.org/v2/examples/index.html 新知识: Underscore.js库 用于弥补标准库,方便了JavaScript的编程 ...

  7. yii框架中使用gii的用法

    首先在config文件中的 main-local.php中添加一句 'allowedIPs' => ['*'],如下图所示:

  8. 正睿 2018 提高组十连测 Day4 T3 碳

    记'1'为+1,'0'为-1; 可以发现 pre[i],suf[i]分别为前/后缀和 a[i]=max(pre[l.....i]); b[i]=max(suf[i+1....r]); ans=max( ...

  9. 非常可乐 HDU - 1495

    大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多.但see ...

  10. dijkstra优化

    1, 桶优化最短路, 时间复杂度$O(m+n)$, 空间$O(C)$, $C$为最短路长度 const int N = 1e6+10; int n, m; struct _ {int to,w;}; ...