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,提问作者김민규
相关产品推荐
相关产品推荐

