我的代码有问题,我的程序使用线程从 MySQL DB 中填充 JTable,程序工作正常,但出现此错误
//错误,com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:数据源拒绝建立连接,来自服务器的消息:“连接太多” 错误java.lang.NullPointerException//
我认为我需要关闭连接,或者可能不使用线程来填充 JTable,我的想法是在不使用 JButton 事件的情况下填充表,您对此有什么建议吗?
public class VentanaAdministrador extends javax.swing.JFrame{
public static final String URL = "jdbc:mysql://localhost:3306/floreria?autoReconnet=true&useSSL=false";
public static final String Usuario = "root";
public static final String Contraseña = "";
PreparedStatement ps;
ResultSet rs;
public Connection getConnection(){
Connection conexion = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conexion = (Connection) DriverManager.getConnection(URL,Usuario,Contraseña);
}catch(Exception ex){
System.err.println("Error, "+ex);
}
return conexion;
}
///////////////////////////////////////////////
Thread llenado = new Thread(){
public void run(){
DefaultTableModel modeloTabla = new DefaultTableModel();
TablaVentanaAsignar.setModel(modeloTabla);
PreparedStatement ps = null;
ResultSet rs = null;
try{
VentanaAdministrador con = new VentanaAdministrador();
Connection VentanaAdministrador = con.getConnection();
ps = VentanaAdministrador.prepareStatement("select NumeroEmpleado,Nombre,Punto_de_venta,TiempoTrabajo from empleados where Puesto=?");
ps.setString(1, "Diseñador");
rs = ps.executeQuery();
modeloTabla.addColumn("No. Empleado");
modeloTabla.addColumn("Nombre");
modeloTabla.addColumn("Sucursal");
modeloTabla.addColumn("Tiempo trabajado");
while(rs.next()){
Object fila[] = new Object[4];
fila[0] = rs.getObject(1);
fila[1] = rs.getObject(2);
fila[2] = rs.getObject(3);
fila[3] = rs.getObject(4);
modeloTabla.addRow(fila);
}
}catch(Exception ex){
System.err.println("Error "+ex);
}
}
};
public VentanaAdministrador() {
initComponents();
llenado.start();
}
最佳答案
通常,在数据库工作中最好专注于尽可能快速、直接地执行以下操作:
- (a) 连接到数据库,
- (b) 执行查询,
- (c) 检索数据,并且
- (d) 终止连接(如果您使用连接池,则将连接返回到池中)。
因此,无需将 PreparedStatement
和 ResultSet
作为类的成员字段(如代码中所示)。这些对象应该被快速实例化、利用和丢弃(一般来说)。
Separate您的数据库工作来自您的 GUI工作。与数据库交互可能需要一段时间,因此在后台线程上运行。完成后,使用 GUI 中适当的访问点要求它使用新数据更新其小部件 - 但在其自己的 GUI 线程中更新自身。 永远不要从另一个线程访问 GUI 小部件。无论您是否使用 JavaFX/OpenJFX , Swing , SWT , Vaadin Flow ,或Android ,每个 GUI 框架都有一个钩子(Hook),用于要求 GUI 在 GUI 自己的线程上更新其小部件。
在现代 Java 中,我们很少需要直接处理 Thread
类。对于并发工作,请使用 Java 5 中添加的 Executors 框架。
如果您使用DataSource
,您将在开发、测试和部署方面获得最大的灵活性。接口(interface)包含连接信息,而不仅仅是代码中看到的字符串。通常是JDBC driver提供DataSource
的基本实现。例如,Connector/J driver provides com.mysql.cj.jdbc.MysqlDataSource
类。
private DataSource prepareDataSource() {
MysqlDataSource ds = new com.mysql.cj.jdbc.MysqlDataSource();
ds.setServerName( "1.2.3.4" );
ds.setPortNumber( 5432 );
ds.setUser( "scott" );
ds.setPassword( "tiger") ;
ds.setDatabaseName( "invoicing" );
… Set all your relevant properties …
return ds ;
}
将此 DataSource
保留在应用程序中方便的位置,以便任何需要数据库连接的代码都可以使用。
还要随身携带 ExecutorService
的实现用于您的后台线程工作。使用Executors
实用程序类可以方便地获取实例。请务必在应用程序退出之前最终关闭执行程序服务,否则其后备线程池可能会像僵尸一样无限期地继续运行。
ExecutorService executorService = Executors.newFixedThreadPool( 3 ) ;
或者,将来当 Project Loom技术到来:
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
使用try-with-resources执行 JDBC 工作时的语法。它以有用的方式简化您的代码,自动关闭您的数据库资源。
将您的数据库工作定义为实现 Runnable
的任务对象(或Callable
)接口(interface)。向您的执行器服务提交一个实例。
/// Code in your GUI detects need to load data.
/// … Fetch the `ExecutorService` from wherever you stored it.
executorService.submit( new DatabaseWorkRunnable() ) ;
run
该 Runnable
的方法可能看起来像下面所示的不完整且未经测试的代码。
请注意此代码如何具有一对嵌套的 try-with-resources 语句,涵盖三个 AutoCloseable
资源对象:Connection
、PreparedStatement
和 ResultSet
。如果实例化,则无论您的代码是否成功完成,每个资源对象都将被关闭。资源按照与声明它们相反的顺序关闭。
DataSource
对象不是资源,并且永远不会“打开”。所以它永远不会关闭。 DataSource
仅保存用于打开数据库连接的信息。
String sql = "SELECT … ;";
try (
Connection conn = dataSource.getConnection() ;
PreparedStatement ps = conn.prepareStatement( sql ) ;
)
{
… Make `PreparedStatement::set…` calls here.
try (
ResultSet rs = ps.executeQuery() ;
)
{
if ( rs.next() )
{
LocalDate ld = rs.getObject( 1 , LocalDate.class );
… Retrieve your data , add to collection to be delivered to GUI later.
}
}
}
catch ( SQLException e )
{
e.printStackTrace();
}
// At this point, all three `Connection`, `PreparedStatement`, and `ResultSet` objects are closed automatically whether your code ran successfully or whether an exception/error was thrown.
… Use your GUI framework’s hook to ask the GUI to update its table widget with the fresh data in collection.
所有这些都已在 Stack Overflow 上多次介绍过。搜索以了解更多信息并查看许多示例。
关于java - 通过Thread关闭MySQL连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67497126/