You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter连接PostgreSQL报错:重新打开已关闭连接的解决方法

解决Flutter中PostgreSQL连接重复打开的错误

问题原因

你遇到的Attempting to reopen a closed connection错误,是因为**PostgreSQLConnection实例关闭后无法重新打开**。当前代码里的_connection是LoginPage初始化时创建的单实例,第一次登录后执行close()关闭了连接,第二次调用open()时就会触发该错误。

另外注意:原SQL语句缺少WHERE条件,会直接查询全表数据,导致登录验证逻辑完全失效,必须修正。

解决方案

方案1:每次登录创建新连接实例(推荐)

移除LoginPage中的_connection成员,在_login方法内每次创建新的连接实例,确保每次操作都是独立的连接:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:postgres/postgres.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: LoginPage(),
    );
  }
}

class LoginPage extends StatefulWidget {
  LoginPage({super.key});

  @override
  LoginPageState createState() => LoginPageState();
}

class LoginPageState extends State<LoginPage> {
  final TextEditingController _IDController = TextEditingController();
  final TextEditingController _passwdController = TextEditingController();

  Future<void> _login() async {
    final String ID = _IDController.text;
    final String passwd = _passwdController.text;

    // 每次登录创建新的连接实例
    final connection = PostgreSQLConnection(
      'localhost',
      5432,
      'TEST',
      username: 'mk',
      password: '',
    );

    try {
      await connection.open();

      // 修正SQL语句,添加WHERE条件实现登录验证
      final List<List<dynamic>> results = await connection.query(
        'SELECT * FROM table WHERE ID = @ID AND passwd = @passwd',
        substitutionValues: {
          'ID': ID,
          'passwd': passwd,
        },
      );

      if (results.isNotEmpty) {
        print('success');
      } else {
        print('fail');
      }
    } finally {
      await connection.close();
    }
  }

  // 补充完整build方法
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(controller: _IDController, hintText: 'ID'),
            TextField(controller: _passwdController, hintText: 'Password', obscureText: true),
            ElevatedButton(onPressed: _login, child: const Text('Login')),
          ],
        ),
      ),
    );
  }
}

方案2:检查连接状态,复用或重建连接

如果想复用连接,可以在打开前检查连接状态,若已关闭则重建实例:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:postgres/postgres.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: LoginPage(),
    );
  }
}

class LoginPage extends StatefulWidget {
  // 改为可重新赋值的连接变量
  late PostgreSQLConnection _connection;

  LoginPage({super.key}) {
    _initConnection();
  }

  void _initConnection() {
    _connection = PostgreSQLConnection(
      'localhost',
      5432,
      'TEST',
      username: 'mk',
      password: '',
    );
  }

  @override
  LoginPageState createState() => LoginPageState();
}

class LoginPageState extends State<LoginPage> {
  final TextEditingController _IDController = TextEditingController();
  final TextEditingController _passwdController = TextEditingController();

  Future<void> _login() async {
    final String ID = _IDController.text;
    final String passwd = _passwdController.text;

    try {
      // 若连接已关闭,重新初始化连接
      if (widget._connection.isClosed) {
        widget._initConnection();
      }
      await widget._connection.open();

      final List<List<dynamic>> results = await widget._connection.query(
        'SELECT * FROM table WHERE ID = @ID AND passwd = @passwd',
        substitutionValues: {
          'ID': ID,
          'passwd': passwd,
        },
      );

      if (results.isNotEmpty) {
        print('success');
      } else {
        print('fail');
      }
    } finally {
      // 若不需要复用连接,仍可关闭;若复用则注释此行
      // await widget._connection.close();
    }
  }

  // 补充完整build方法
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(controller: _IDController, hintText: 'ID'),
            TextField(controller: _passwdController, hintText: 'Password', obscureText: true),
            ElevatedButton(onPressed: _login, child: const Text('Login')),
          ],
        ),
      ),
    );
  }
}

关键说明

  • 方案1更适合登录这种短生命周期的操作,避免连接超时、状态异常等问题。
  • 必须修正SQL语句的WHERE条件,否则登录验证逻辑无法正常工作。

内容的提问来源于stack exchange,提问作者김민규

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 18:46:13