sqlalchemyredis 多线程并发问题遇到下面的问题怎么办

解决Flask-SQLAlchemy中文乱码问题 - 为程序员服务
解决Flask-SQLAlchemy中文乱码问题
这两天在学习使用flask + SQLAlchemy 定制一个web查询页面的demo ,在测试时,发现查询到的结果显示乱码 。这里将解决方法记录下。
二、解决思路
1、flask 程序上定位
flask的文档中提到可以通过设置SQLALCHEMY_NATIVE_UNICODE来禁止使用SQLAlchemy默认的Unicode编码。有可能是SQLAlchemy默认的Unicode编码不是UTF-8,抱着这样的想法,在程序中指定了“SQLALCHEMY_NATIVE_UNICODE=False”,执行程序,报错。
flask中还提到“use_native_unicode”为目标编码来指定编码方式,尝试将“db = SQLAlchemy(app)”改为“db = SQLAlchemy(app, use_native_unicode=”utf8″)”。这回虽然没报错,但还是乱码。
2、mysql 上定位
突然想到有可能是建表的时候,没有指定字符集,使用的是数据库默认的字符集的导致的。继续找了一段时间的如何指定建表时使用字符集的方法,未果。
数据库该不会使用的不是UTF-8吧?抱着这个想法,进入数据库,输入“status”,在输出的信息上显示默认是latin-1。搞了半天,原来问题在这。
mysql& status
--------------
Ver 14.14 Distrib 5.1.73, for redhat-linux-gnu (x86_64) using readline 5.1
Connection id:
Current database:
Current user:
root@localhost
Not in use
Current pager:
Using outfile:
Using delimiter:
Server version:
5.1.73 Source distribution
Protocol version:
Connection:
Localhost via UNIX socket
Server characterset:
characterset:
Client characterset:
characterset:
UNIX socket:
/var/lib/mysql/mysql.sock
3、解决问题
即然找到了,问题就在mysql 的my.cnf 上增加相关配置,并重启mysql 服务:
# 进入mysql的配置文件目录
cd /etc/mysql/
# 编辑my.cnf配置文件
# 在文件中的[mysqld]下面增加一行内容
character_set_server = utf8
# 在[client]和[mysql]下面分别增加一行内容
default-character-set = utf8
# 保存。然后重启MySQL的服务,设置就生效了
service mysqld restart
注:需要注意的是,之前已经存在的数据,在上面修改过后,通过mysql select查询时会是乱码,需要重新导入。
最后上个图:
关注Linux运维技术及互联网的IT科技博客
原文地址:, 感谢原作者分享。
您可能感兴趣的代码中国领先的IT技术网站
51CTO旗下网站
Python数据库ORM工具sqlalchemy的学习笔记
SQLAlchemy是python的一个数据库ORM工具,提供了强大的对象模型间的转换,可以满足绝大多数数据库操作的需求,并且支持多种数据库引擎(sqlite,mysql,postgres, mongodb等),在这里记录基本用法和学习笔记。
作者:bomo来源:| 13:34
SQLAlchemy是python的一个数据库ORM工具,提供了强大的对象模型间的转换,可以满足绝大多数数据库操作的需求,并且支持多种数据库引擎(sqlite,mysql,postgres,
mongodb等),在这里记录基本用法和学习笔记。
通过pip安装
$&pip&install&SQLAlchemy&
首先是连接到数据库,SQLALchemy支持多个数据库引擎,不同的数据库引擎连接字符串不一样,常用的有
mysql://username:password@hostname/database&postgresql://username:password@hostname/database&sqlite:////absolute/path/to/database&sqlite:///c:/absolute/path/to/database&
更多连接字符串的介绍参见这里
下面是连接和使用sqlite数据库的例子
1. connection
使用传统的connection的方式连接和操作数据库
from&sqlalchemy&import&create_engine&&#&数据库连接字符串&DB_CONNECT_STRING&=&'sqlite:///:memory:'&&#&创建数据库引擎,echo为True,会打印所有的sql语句&engine&=&create_engine(DB_CONNECT_STRING,&echo=True)&&#&创建一个connection,这里的使用方式与python自带的sqlite的使用方式类似&with&engine.connect()&as&con:&&&&&#&执行sql语句,如果是增删改,则直接生效,不需要commit&&&&&rs&=&con.execute('SELECT&5')&&&&&data&=&rs.fetchone()[0]&&&&&print&&Data:&%s&&%&data&
与python自带的sqlite不同,这里不需要Cursor光标,执行sql语句不需要commit
2. connection事务
使用事务可以进行批量提交和回滚
from&sqlalchemy&import&create_engine&&#&数据库连接字符串&DB_CONNECT_STRING&=&'sqlite:////Users/zhengxiankai/Desktop/Document/db.sqlite'&engine&=&create_engine(DB_CONNECT_STRING,&echo=True)&&with&engine.connect()&as&connection:&&&&&trans&=&connection.begin()&&&&&try:&&&&&&&&&r1&=&connection.execute(&select&*&from&User&)&&&&&&&&&r2&=&connection.execute(&insert&into&User(name,&age)&values(?,&?)&,&'bomo',&24)&&&&&&&&&trans.commit()&&&&&except:&&&&&&&&&trans.rollback()&&&&&&&&&raise&&
3. session
connection是一般使用数据库的方式,sqlalchemy还提供了另一种操作数据库的方式,通过session对象,session可以记录和跟踪数据的改变,在适当的时候提交,并且支持强大的ORM的功能,下面是基本使用
from&sqlalchemy&import&create_engine&from&sqlalchemy.orm&import&sessionmaker&&#&数据库连接字符串&DB_CONNECT_STRING&=&'sqlite:////Users/zhengxiankai/Desktop/Document/db.sqlite'&&#&创建数据库引擎,echo为True,会打印所有的sql语句&engine&=&create_engine(DB_CONNECT_STRING,&echo=True)&&#&创建会话类&DB_Session&=&sessionmaker(bind=engine)&&#&创建会话对象&session&=&DB_Session()&&#&dosomething&with&session&&#&用完记得关闭,也可以用with&session.close()&&
上面创建了一个session对象,接下来可以操作数据库了,session也支持通过sql语句操作数据库
session.execute('select&*&from&User')&session.execute(&insert&into&User(name,&age)&values('bomo',&13)&)&session.execute(&insert&into&User(name,&age)&values(:name,&:age)&,&{'name':&'bomo',&'age':12})&&#&如果是增删改,需要commit&session.commit()&&
注意参数使用dict,并在sql语句中使用:key占位
上面简单介绍了sql的简单用法,既然是ORM框架,我们先定义两个模型类User和Role,sqlalchemy的模型类继承自一个由declarative_base()方法生成的类,我们先定义一个模块Models.py生成Base类
from&sqlalchemy.ext.declarative&import&declarative_base&&Base&=&declarative_base()&&
from&sqlalchemy&import&Column,&Integer,&String&from&Models&import&Base&&class&User(Base):&&&&&__tablename__&=&'User'&&&&&id&=&Column('id',&Integer,&primary_key=True,&autoincrement=True)&&&&&name&=&Column('name',&String(50))&&&&&age&=&Column('age',&Integer)&&
from&sqlalchemy&import&Column,&Integer,&String&from&Models&import&Base&&class&Role(Base):&&&&&__tablename__&=&'Role'&&&&&id&=&Column('id',&Integer,&primary_key=True,&autoincrement=True)&&&&&name&=&Column('name',&String(50))&&
从上面很容易看出来,这里的模型对应数据库中的表,模型支持的类型有Integer, String, Boolean, Date, DateTime,
Float,更多类型包括类型对应的Python的类型参见:这里
Column构造函数相关设置
name:名称
type_:列类型
autoincrement:自增
default:默认值
index:索引
nullable:可空
primary_key:外键
更多介绍参见这里
接下来通过session进行增删改查
from&sqlalchemy&import&create_engine&from&sqlalchemy.orm&import&sessionmaker&from&User&import&User&from&Role&import&Role&from&Models&import&Base&&DB_CONNECT_STRING&=&'sqlite:////Users/zhengxiankai/Desktop/Document/db.sqlite'&engine&=&create_engine(DB_CONNECT_STRING,&echo=True)&DB_Session&=&sessionmaker(bind=engine)&session&=&DB_Session()&&#&1.&创建表(如果表已经存在,则不会创建)&Base.metadata.create_all(engine)&&#&2.&插入数据&u&=&User(name&=&'tobi',&age&=&200)&r&=&Role(name&=&'user')&&#&2.1&使用add,如果已经存在,会报错&session.add(u)&session.add(r)&session.commit()&print&r.id&&#&3&修改数据&#&3.1&使用merge方法,如果存在则修改,如果不存在则插入&r.name&=&'admin'&session.merge(r)&&#&3.2&也可以通过这种方式修改&session.query(Role).filter(Role.id&==&1).update({'name':&'admin'})&&#&4.&删除数据&session.query(Role).filter(Role.id&==&1).delete()&&#&5.&查询数据&#&5.1&返回结果集的第二项&user&=&session.query(User).get(2)&&#&5.2&返回结果集中的第2-3项&users&=&session.query(User)[1:3]&&#&5.3&查询条件&user&=&session.query(User).filter(User.id&&&6).first()&&#&5.4&排序&users&=&session.query(User).order_by(User.name)&&#&5.5&降序(需要导入desc方法)&from&sqlalchemy&import&desc&users&=&session.query(User).order_by(desc(User.name))&&#&5.6&只查询部分属性&users&=&session.query(User.name).order_by(desc(User.name))&for&user&in&users:&&&&&print&user.name&&#&5.7&给结果集的列取别名&users&=&session.query(User.name.label('user_name')).all()&for&user&in&users:&&&&&print&user.user_name&&#&5.8&去重查询(需要导入distinct方法)&from&sqlalchemy&import&distinct&users&=&session.query(distinct(User.name).label('name')).all()&&#&5.9&统计查询&user_count&=&session.query(User.name).order_by(User.name).count()&age_avg&=&session.query(func.avg(User.age)).first()&age_sum&=&session.query(func.sum(User.age)).first()&&#&5.10&分组查询&users&=&session.query(func.count(User.name).label('count'),&User.age).group_by(User.age)&for&user&in&users:&&&&&print&'age:{0},&count:{1}'.format(user.age,&user.count)&&session.close()&
5. 多表关系
上面的所有操作都是基于单个表的操作,下面是多表以及关系的使用,我们修改上面两个表,添加外键关联(一对多和多对一)
from&sqlalchemy&import&Column,&Integer,&String&from&sqlalchemy&import&ForeignKey&from&sqlalchemy.orm&import&relationship&from&Models&import&Base&&class&User(Base):&&&&&__tablename__&=&'users'&&&&&id&=&Column('id',&Integer,&primary_key=True,&autoincrement=True)&&&&&name&=&Column('name',&String(50))&&&&&age&=&Column('age',&Integer)&&&&&&#&添加角色id外键(关联到Role表的id属性)&&&&&role_id&=&Column('role_id',&Integer,&ForeignKey('roles.id'))&&&&&#&添加同表外键&&&&&second_role_id&=&Column('second_role_id',&Integer,&ForeignKey('roles.id'))&&&&&&#&添加关系属性,关联到role_id外键上&&&&&role&=&relationship('Role',&foreign_keys='User.role_id',&backref='User_role_id')&&&&&#&添加关系属性,关联到second_role_id外键上&&&&&second_role&=&relationship('Role',&foreign_keys='User.second_role_id',&backref='User_second_role_id')&
from&sqlalchemy&import&Column,&Integer,&String&from&sqlalchemy.orm&import&relationship&from&Models&import&Base&&class&Role(Base):&&&&&__tablename__&=&'roles'&&&&&id&=&Column('id',&Integer,&primary_key=True,&autoincrement=True)&&&&&name&=&Column('name',&String(50))&&&&&&#&添加关系属性,关联到User.role_id属性上&&&&&users&=&relationship(&User&,&foreign_keys='User.role_id',&backref=&Role_users&)&&&&&#&添加关系属性,关联到User.second_role_id属性上&&&&&second_users&=&relationship(&User&,&foreign_keys='User.second_role_id',&backref=&Role_second_users&)&
这里有一点需要注意的是,设置外键的时候ForeignKey('roles.id')这里面使用的是表名和表列,在设置关联属性的时候relationship('Role',
foreign_keys='User.role_id',
backref='User_role_id'),这里的foreign_keys使用的时候类名和属性名
接下来就可以使用了
u&=&User(name='tobi',&age=200)&&r1&=&Role(name='admin')&r2&=&Role(name='user')&&u.role&=&r1&u.second_role&=&r2&&session.add(u)&session.commit()&&#&查询(对于外键关联的关系属性可以直接访问,在需要用到的时候session会到数据库查询)&roles&=&session.query(Role).all()&for&role&in&roles:&&&&&print&'role:{0}&users'&&&&&for&user&in&role.users:&&&&&&&&&print&'\t{0}'.format(user.name)&&&&&print&'role:{0}&second_users'&&&&&for&user&in&role.second_users:&&&&&&&&&print&'\t{0}'.format(user.name)&
上面表示的是一对多(多对一)的关系,还有一对一,多对多,如果要表示一对一的关系,在定义relationship的时候设置uselist为False(默认为True),如在Role中
class&Role(Base):&&&&&...&&&&&user&=&relationship(&User&,&uselist=False,&foreign_keys='User.role_id',&backref=&Role_user&)&&
6. 多表查询
多表查询通常使用join进行表连接,第一个参数为表名,第二个参数为条件,例如
users&=&db.session.query(User).join(Role,&Role.id&==&User.role_id)&&for&u&in&users:&&&&&print&u.name&&
join为内连接,还有左连接outerjoin,用法与join类似,右连接和全外链接在1.0版本上不支持,通常来说有这两个结合查询的方法基本够用了,1.1版本貌似添加了右连接和全外连接的支持,但是目前只是预览版
还可以直接查询多个表,如下
result&=&db.session.query(User,&Role).filter(User.role_id&=&Role.id)&#&这里选择的是两个表,使用元组获取数据&for&u,&r&in&result:&&&&&&&print&u.name&&
三、数据库迁移
sqlalchemy的数据库迁移/升级有两个库支持alembic和sqlalchemy-migrate
由于sqlalchemy-migrate在2011年发布了0.7.2版本后,就已经停止更新了,并且已经不维护了,也积累了很多bug,而alembic是较后来才出现,而且是sqlalchemy的作者开发的,有良好的社区支持,所以在这里只学习alembic这个库
alembic实现了类似git/svn的版本管理的控制,我们可以通过alembic维护每次升级数据库的版本
通过pip安装,pip会自动安装相关的依赖
$&pip&install&alembic&
安装完成后再项目根目录运行
yourproject/&&&&&alembic.ini&&&&&YOUR_ALEMBIC_DIR/&&&&&&&&&env.py&&&&&&&&&README&&&&&&&&&script.py.mako&&&&&&&&&versions/&&&&&&&&&&&&&e_add_account.py&&&&&&&&&&&&&2b1ae634e5cd_add_order_id.py&&&&&&&&&&&&&3adcc9a56557_rename_username_field.py&&
alembic.ini 提供了一些基本的配置
env.py 每次执行Alembic都会加载这个模块,主要提供项目Sqlalchemy Model 的连接
script.py.mako 迁移脚本生成模版
versions 存放生成的迁移脚本目录
默认情况下创建的是基于单个数据库的,如果需要支持多个数据库或其他,可以通过alembic list_templates查看支持的模板
$&alembic&list_templates&Available&templates:&&generic&-&Generic&single-database&configuration.&multidb&-&Rudimentary&multi-database&configuration.&pylons&-&Configuration&that&reads&from&a&Pylons&project&environment.&&Templates&are&used&via&the&'init'&command,&e.g.:&&&&alembic&init&&&
使用之前,需要配置一下链接字符串,打开alembic.ini文件,设置sqlalchemy.url连接字符串,例如
sqlalchemy.url&=&sqlite:////Users/zhengxiankai/Desktop/database.db&
其他参数可以参见官网说明:
4. 创建数据库版本
接下来我们创建一个数据库版本,并新建两个表
$&alembic&revision&-m&'create&table'&
创建一个版本(会在yourproject/YOUR_ALEMBIC_DIR/versions/文件夹中创建一个python文件1a8a0d799b33_create_table.py)
该python模块包含upgrade和downgrade两个方法,在这里添加一些新增表的逻辑
&&&create&table&&Revision&ID:&4fd533a56b34&Revises:&Create&Date:&&17:20:27.667100&&&&&&from&alembic&import&op&import&sqlalchemy&as&sa&&&#&revision&identifiers,&used&by&Alembic.&revision&=&'4fd533a56b34'&down_revision&=&None&branch_labels&=&None&depends_on&=&None&&def&upgrade():&&&&&#&添加表&&&&&op.create_table(&&&&&&&&&'account',&&&&&&&&&sa.Column('id',&sa.Integer,&primary_key=True),&&&&&&&&&sa.Column('name',&sa.String(50),&nullable=False),&&&&&&&&&sa.Column('description',&sa.Unicode(200)),&&&&&)&&&&&&#&添加列&&&&&#&op.add_column('account',&sa.Column('last_transaction_date',&sa.DateTime))&&&&def&downgrade():&&&&&#&删除表&&&&&op.drop_table('account')&&&&&&#&删除列&&&&&#&op.drop_column('account',&'last_transaction_date')&&
这里使用到了了op对象,关于op对象的更多API使用,参见这里
5. 升级数据库
刚刚实现了升级和降级的方法,通过下面命令升级数据库到最新版本
$&alembic&upgrade&head&
这时候可以看到数据库多了两个表alembic_version和account,alembic_version存放数据库版本
关于升级和降级的其他命令还有下面这些
#&升到最高版本&$&alembic&upgrade&head&&#&降到最初版本&$&alembic&downgrade&base&&#&升两级&$&alembic&upgrade&+2&&#&降一级&$&alembic&downgrade&-1&&#&升级到制定版本&$&alembic&upgrade&e93b8d488143&&#&查看当前版本&$&alembic&current&&#&查看历史版本详情&$&alembic&history&&&#&查看历史版本(-r参数)类似切片&$&alembic&history&-r1975ea:ae1027&$&alembic&history&-r-3:current&$&alembic&history&-r1975ea:&&
6. 通过元数据升级数据库
上面我们是通过API升级和降级,我们也可以直接通过元数据更新数据库,也就是自动生成升级代码,先定义两个Model(User,Role),这里我定义成三个文件
yourproject/&&&&&YOUR_ALEMBIC_DIR/&&&&&tutorial/Db&&&&&&&&&Models.py&&&&&&&&&User.py&&&&&&&&&Role.py&
代码就放在一起了
from&sqlalchemy.ext.declarative&import&declarative_base&from&sqlalchemy&import&Column,&Integer,&String&Base&=&declarative_base()&&class&User(Base):&&&&&__tablename__&=&'users'&&&&&&id&=&Column('id',&Integer,&primary_key=True,&autoincrement=True)&&&&&name&=&Column('name',&String)&&class&Role(Base):&&&&&__tablename__&=&'roles'&&&&&&id&=&Column('id',&Integer,&primary_key=True,&autoincrement=True)&&&&&name&=&Column('name',&String)&
在YOUR_ALEMBIC_DIR/env.py配置元数据
target_metadata&=&None&
import&os&import&sys&&#&这里需要添加相对路径到sys.path,否则会引用失败,尝试过使用相对路径,但各种不好使,还是使用这种方法靠谱些&sys.path.append(os.path.abspath(os.path.join(os.getcwd(),&&../yourproject/tutorial/Db&)))&&from&User&import&User&from&Role&import&Role&from&Models&import&Base&target_metadata&=&Base.metadata&&
os.path.join(os.getcwd()这个获取到的地址不是env.py的路径,而是根目录
在创建数据库版本的时候添加--autogenerate参数,就会从Base.metadata元数据中生成脚本
$&alembic&revision&&
这时候会在生成升级代码
&&&add&user&table&&Revision&ID:&97de1533584a&Revises:&c1&Create&Date:&&21:58:00.758410&&&&&&from&alembic&import&op&import&sqlalchemy&as&sa&&&#&revision&identifiers,&used&by&Alembic.&revision&=&'97de1533584a'&down_revision&=&'c1'&branch_labels&=&None&depends_on&=&None&&def&upgrade():&&&&&###&commands&auto&generated&by&Alembic&-&please&adjust!&###&&&&&op.create_table('roles',&&&&&sa.Column('id',&sa.Integer(),&nullable=False),&&&&&sa.Column('name',&sa.String(),&nullable=True),&&&&&sa.PrimaryKeyConstraint('id')&&&&&)&&&&&op.create_table('users',&&&&&sa.Column('id',&sa.Integer(),&nullable=False),&&&&&sa.Column('name',&sa.String(),&nullable=True),&&&&&sa.PrimaryKeyConstraint('id')&&&&&)&&&&&op.drop_table('account')&&&&&###&end&Alembic&commands&###&&&def&downgrade():&&&&&###&commands&auto&generated&by&Alembic&-&please&adjust!&###&&&&&op.create_table('account',&&&&&sa.Column('id',&sa.INTEGER(),&nullable=False),&&&&&sa.Column('name',&sa.VARCHAR(length=50),&nullable=False),&&&&&sa.Column('description',&sa.VARCHAR(length=200),&nullable=True),&&&&&sa.Column('last_transaction_date',&sa.DATETIME(),&nullable=True),&&&&&sa.PrimaryKeyConstraint('id')&&&&&)&&&&&op.drop_table('users')&&&&&op.drop_table('roles')&&&&&###&end&Alembic&commands&###&&
由于我没有定义account模型,会被识别为删除,如果删除了model的列的声明,则会被识别为删除列,自动生成的版本我们也可以自己修改,然后执行升级命令即可升级alembic
upgrade head
需要注意的是
Base.metadata声明的类必须以数据库中的一一对应,如果数据库中有的表,而在元数据中没有,会识别成删除表
revision创建版本之前执行之前需要升级到最新版本
配置Base之前,需要保证所有的Model都已经执行(即导入)过一次了,否则无法读取到,也就是需要把所有Model都import进来
数据库升级有风险,升级前最好先检查一遍upgrade函数,可以的话做好备份哈
四、常见问题
1. String长度问题
如果使用mysql数据库,String类型对应的是VARCHAR类型,需要指定长度,否则会报下面错误,而在sqlite不会出现
(in&table&'user',&column&'name'):&VARCHAR&requires&a&length&on&dialect&mysql&
TODO:如有其他问题欢迎留言
五、参考链接
最后安利一下自己的博客:【编辑推荐】【责任编辑: TEL:(010)】
大家都在看猜你喜欢
头条头条原创头条头条
24H热文一周话题本月最赞
讲师:5人学习过
讲师:2人学习过
讲师:2人学习过
精选博文论坛热帖下载排行
全书分为基础篇、高级篇和应用篇3个部分,共18章,有重点、分层次地讲解SQL Server 2005的基础知识、高级使用技巧和项目应用方法。第1~10...
订阅51CTO邮刊Flask-SQLAlchemy 配置问题 - 简书
Flask-SQLAlchemy 配置问题
参考 《 Flask Web 开发: 基于 Python 的 Web 应用开发实战》 时,使用 Flask-SQLAlchemy 数据库时产生的问题。
配置数据库后,启动工程, 命令行中会出现如下 Warning:
$\venv\lib\site-packages\flask_sqlalchemy\__init__.py:800: U
serWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be
disabled by default in the future.
Set it to True to suppress this warning.
warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and wi
ll be disabled by default in the future.
Set it to True to suppress this warnin
查看代码发现,程序对Flask-SQLAlchemy的配置如下:
app.config['SQLALCHEMY_DATABASE_URI'] =\
'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
根据最近版本的 Flask-SQLAlchemy 的配置设置(详情点):
SQLALCHEMY_TRACK_MODIFICATIONSIf set to True, Flask-SQLAlchemy will track modifications of objects and emit signals. The default is None, which enables tracking but issues a warning that it will be disabled by default in the future. This requires extra memory and should be disabled if not needed.
这里我们将新添一个设置, 将 SQLALCHEMY_TRACK_MODIFICATIONS 设置为 True。
另外,根据 Flask-SQLAlchemy 的
**Version 2.0Released on August 29th 2014, codename Bohrium
Changed how the builtin signals are subscribed to skip non Flask-SQLAlchemy sessions. This will also fix the attribute error about model changes not existing.
Added a way to control how signals for model modifications are tracked.
Made the SignallingSessiona public interface and added a hook for customizing session creation.
If the bind parameter is given to the signalling session it will no longer cause an error that a parameter is given twice.Added working table reflection support.
Enabled autoflush by default.
Consider SQLALCHEMY_COMMIT_ON_TEARDOWNharmful and remove from docs.
SQLALCHEMY_COMMIT_ON_TEARDOWN的配置已被移除,无需配置。
说明以上问题的产生与使用 Flask-SQLAlchemy 模块的版本相关,相关资料可以参考该模块的官方文档 。sqlalchemy 学习(二)scoped session_ASP.NET技巧_动态网站制作指南
sqlalchemy 学习(二)scoped session
来源:人气:58
设计的难点之一,是生命周期的管理问题。sqlalchemy提供了一个简单的session管理机制,即scoped session。它采用的注册模式。所谓的注册模式,简单来说,是指在整个程序运行的过程当中,只存在唯一的一个session对象。
创建scoped session的方法如下
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
session_factory = sessionmaker(bind=some_engine)
Session = scoped_session(session_factory)
scoped_session本质上也是一个方法,它首先通过session工厂创建session对象,然后对session对象进行相应的管理。
如果需要创建session对象,可执行下面的代码。
some_session = Session()
注意,由于scoped session采用的是注册模式,因此下面代码的session1和session2是一个相同的对象引用。
session1 = Session()
session2 = Session()
但是下面代码中的session1和session2是不同的对象引用。因为session2创建之前,session1已经被销毁。
session1 = Session()
session1.remove()
session2 = Session()
介绍到这里,我们知道scoped session本质上是一个全局变量。可是,如果直接把session定义成全局变量,在多线程的环境下,会造成线程同步的问题。为此,scoped session在默认情况下,采用的线程本地化存储方式。也就是说,每个线程的session对象是不同的。这样,不同线程对数据库的操作不会相互影响。
优质网站模板}

我要回帖

更多关于 java多线程安全问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信