多用户通过ODBC访问应用致Access数据库损坏问题排查
问题描述
多用户通过各自电脑上的Web界面应用,访问共享驱动器中的MS Access .accdb文件。应用采用Flask+pyodbc+SQLAlchemy架构,通过ODBC驱动运行。系统稳定服务10-15名用户达1年半,暑期休假两周后,Access文件频繁损坏,后端返回「无法识别数据库文件」错误。
核心代码片段
数据库连接配置
# db_models engine = create_engine("access+pyodbc://login:pwd@MSACCESS") base = declarative_base() Session = sessionmaker(bind=engine) session = Session()
会话复用逻辑
会话生命周期设为12小时,所有查询复用同一个会话:
from db_models import session, Calls calls_data = session.query(Calls).order_by(Calls.id.desc()).filter(*queries).all()
已排查的现象与操作
- 2名及以上用户向同一张表添加记录时,数据库损坏;单用户操作无异常,疑似多用户提交记录时冲突使用同一主键。
- 故障前:用户新增记录后,其他用户刷新页面即可看到新数据;故障后:其他用户无法获取更新,仅能看到旧数据。
- 查询前执行
session.close(),其他用户可获取最新数据,但多用户新增记录时数据库仍会损坏。 - Access锁定文件中主机名后存在大量Null,格式示例:
HTUPPP16780 ADMIN NULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULL - 执行压缩修复、删除锁定文件无效。
- 手动新建数据库并复制表结构与数据,修改ODBC链接指向新库,问题依旧。
- 回退到之前100%稳定的旧版本应用,无效。
- 会话执行
commit()后数据会更新,用户可获取最新内容;提交前无数据更新。
解决方案建议
废弃全局长生命周期会话,改用请求级会话
SQLAlchemy的全局会话在多用户并发场景下会导致状态混乱,尤其是Access这种文件型数据库,不支持高并发长连接。每个Flask请求创建独立会话,请求结束后关闭:# 修改db_models,不再创建全局session def get_session(): session = Session() try: yield session finally: session.close() # 在Flask路由中使用 @app.route('/get_calls') def get_calls(): with next(get_session()) as session: calls_data = session.query(Calls).order_by(Calls.id.desc()).filter(*queries).all() # 处理数据并返回确保新增记录时主键的唯一性
- 检查Access表的主键是否设置为自动编号(AutoNumber),若为手动赋值,必须保证多用户场景下的唯一性(比如用UUID或时间戳+用户标识组合)。
- 新增记录后立即执行
session.commit(),避免会话缓存的主键值被其他请求复用。
优化Access数据库的并发配置
- 打开Access数据库,进入「文件」>「选项」>「客户端设置」,调整高级选项中的「默认打开模式」为「共享」,「记录锁定」设为「编辑记录时锁定」,减少文件级锁定概率。
- 确保共享驱动器的权限设置正确,所有用户拥有读/写权限,且没有文件被系统或第三方工具锁定。
排查网络与共享驱动器稳定性
暑期休假后可能存在共享驱动器的网络波动、权限变更或存储故障,导致Access文件写入时出现损坏:- 测试共享驱动器的读写速度与稳定性,排除网络丢包问题。
- 检查服务器系统日志,看是否有文件系统错误或权限变更记录。
避免长时间占用数据库连接
每个数据库操作完成后立即提交并关闭会话,不要让会话长时间保持打开状态,减少Access锁定文件的异常生成。
内容的提问来源于stack exchange,提问作者ceytnot
相关产品推荐
相关产品推荐

