我试图使用SQLAlchemy和psycopg async驱动程序更新数据库的时区。然而,时区在代码中没有反映为更改,即使在数据库中它看起来像是更改了,代码如下及其输出。
此时,数据库时区设置为欧洲/布加勒斯特,我想将其更改为欧洲/阿姆斯特丹。
import asyncio
from contextlib import asynccontextmanager
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql import text
from sqlalchemy.ext.asyncio import (
create_async_engine,
AsyncSession,
)
db_uri = "postgresql+psycopg://bigbrother:BigBrother0906!!@10.190.20.72:5432/bigbrother"
db_engine = create_async_engine(db_uri, max_overflow=1, pool_size=2)
@asynccontextmanager
async def db_session_manager(a_db_engine):
session = sessionmaker(a_db_engine, expire_on_commit=False, class_=AsyncSession)()
try:
yield session
await session.commit()
except Exception as ex:
await session.rollback()
raise ex
finally:
await session.close()
async def update_timezone():
async with db_session_manager(db_engine) as session:
await session.execute(
text(
"""
ALTER DATABASE "bigbrother"
SET timezone TO 'Europe/Amsterdam'
"""
)
)
async def get_timezone():
async with db_session_manager(db_engine) as session:
current_timezone = (
(
await session.execute(
text(
"""
SELECT
name, abbrev, utc_offset, is_dst
FROM pg_timezone_names
WHERE name = current_setting('TIMEZONE')
"""
)
)
)
.mappings()
.one()
)
print(current_timezone)
print("timezone before")
asyncio.run(get_timezone())
asyncio.run(update_timezone())
print("timezone after update")
asyncio.run(get_timezone())
字符串
这段代码提供了以下输出:
'name'之前的时区:'欧洲/布加勒斯特','v':'EEST','utc_offset':datetime.timedelta(seconds=10800),'is_dst':True}更新后的时区?'name':'欧洲/布加勒斯特','v':'EEST','utc_offset':datetime.timedelta(seconds=10800),'is_dst':真}
这个输出反映了引擎仍然看到旧的时区,但是如果我检查数据库属性,时区似乎改变了,这让我认为这与缓存有关。
如果我再次运行它,从而重新创建引擎,它将提供以下输出:
'name'之前的时区:'欧洲/阿姆斯特丹','v':'CEST','utc_offset':datetime.timedelta(seconds=7200),'is_dst':True}更新后的时区?'name':'欧洲/阿姆斯特丹','v':'CEST','utc_offset':datetime.timedelta(seconds=7200),'is_dst':真}
我想做的是在不重新创建引擎的情况下更改时区,或者从引擎中删除缓存,或者以某种方式刷新引擎,以便它看到我的修改。这意味着,如果当前的数据库时区是Europe/布加勒斯特,而想要的时区是Europe/Amsterdam,我希望我的代码提供以下输出:
'name'之前的时区:'欧洲/布加勒斯特','v':'EEST','utc_offset':datetime.timedelta(seconds=10800),'is_dst':True}更新后的时区?'name':'欧洲/阿姆斯特丹','v':'CEST','utc_offset':datetime.timedelta(seconds=7200),'is_dst':真}
我使用的版本:python==3.8.13 backports.zoneinfo==0.2.1 greenlet== 2.0.2 psycopg==3.1.9 python-dateutil==2.8.2 pytzdata==2020.1六==1.16.0 SQLAlchemy==2.0.19 typing_extensions==4.7.1
1条答案
按热度按时间yshpjwxd1#
这与sqlalchemistry无关,也与asyncio无关,postgresql就是这样工作的。即使在
psql
会话中执行此操作,也会得到相同的结果。下面是psql
示例会话,应该解释:字符串
正如您所看到的,执行
alter database <DB> set timezone
更改的是默认数据库参数,而不是当前的参数。创建新会话时,它使用这些默认值,因此新会话的timezone
值不同。最简单的修复方法是使用set
更改当前值,如下所示:型
所以你需要更新
update_timezone
函数并添加set timezone to 'Europe/Amsterdam'
,脚本的结果如下:型
然而,这是很可能不是你想要做的,因为这只会在一个连接中改变
timezone
(set timezone
),因为sqlalchemy
使用连接池,另一个连接(可能存在),仍然会有另一个timezone
的值。一种选择是只执行
set timezone to 'Europe/Amsterdam'
作为您执行的第一个SQL表达式,在这种情况下,所有连接都将从一开始就使用这个时区。另一种选择是在
db_uri
中提供时区:型
您可以使用此URL检查可用的选项。