部署在Heroku的Flask应用SQLite数据库数据过段时间自动丢失如何解决
问题原因
Heroku平台的dyno实例使用临时文件系统,所有存储在实例本地的文件,仅在实例运行期间有效。当应用闲置超过30分钟、部署更新、平台自动调度实例时,dyno都会重启,重启后本地文件会被重置为你部署代码时的初始状态。
你当前使用SQLite作为数据库,所有数据都存储在本地的.db文件中,新写入的数据仅保存在当前运行的dyno临时存储里,重启后自然会丢失,这就是你间隔1小时访问数据消失的核心原因。SQLite本身不适合在Heroku这类无状态PaaS平台上做持久化存储。
解决方案
推荐使用Heroku官方提供的PostgreSQL数据库服务,免费层足够支撑小型项目使用,具体适配步骤如下:
- 进入你的Heroku应用后台,在「Resources」页的Add-ons搜索框中搜索
Heroku Postgres,选择免费的Hobby Dev套餐添加即可,添加后平台会自动生成名为DATABASE_URL的环境变量,存储数据库连接地址。 - 如果你要保留原有的多库绑定配置,可再添加两个Heroku Postgres实例,分别对应anime和movie库,添加后你可以在应用的「Settings」-「Config Vars」页自定义两个环境变量名,比如
ANIME_DATABASE_URL和MOVIE_DATABASE_URL,分别对应两个新库的连接地址。 - 修改你的Flask数据库配置代码,改为读取环境变量,兼顾本地开发和线上部署的使用需求:
import os # 兼容高版本SQLAlchemy对PostgreSQL连接前缀的要求 def get_db_url(env_key, default): url = os.getenv(env_key, default) return url.replace("postgres://", "postgresql://") app.config['SQLALCHEMY_DATABASE_URI'] = get_db_url('DATABASE_URL', 'sqlite:///categories.db') app.config['SQLALCHEMY_BINDS'] = { 'anime': get_db_url('ANIME_DATABASE_URL', 'sqlite:///anime.db'), 'movie': get_db_url('MOVIE_DATABASE_URL', 'sqlite:///movies.db') } app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False Bootstrap(app) db = SQLAlchemy(app)
- 代码修改后重新部署到Heroku,部署完成后进入Heroku应用的控制台,执行
flask shell进入交互环境,运行db.create_all()完成所有表结构的初始化,之后写入的数据都会存储在外置的PostgreSQL中,不会再因为dyno重启丢失。
如果你不需要分三个库存储,也可以直接把三类数据合并到同一个PostgreSQL实例的不同表中,无需额外配置多个数据库实例,维护成本更低。
内容的提问来源于stack exchange,提问作者Ankur Rawat
相关产品推荐
相关产品推荐

