java - 通过Thread关闭MySQL连接

标签 java mysql jdbc

我的代码有问题,我的程序使用线程从 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) 终止连接(如果您使用连接池,则将连接返回到池中)。

因此,无需将 PreparedStatementResultSet 作为类的成员字段(如代码中所示)。这些对象应该被快速实例化、利用和丢弃(一般来说)。

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() ) ;

runRunnable 的方法可能看起来像下面所示的不完整且未经测试的代码。

请注意此代码如何具有一对嵌套的 try-with-resources 语句,涵盖三个 AutoCloseable资源对象:ConnectionPreparedStatementResultSet。如果实例化,则无论您的代码是否成功完成,每个资源对象都将被关闭。资源按照与声明它们相反的顺序关闭。

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/

相关文章:

java - JDBC自动查询转的很慢

Java JDBC 执行批处理

java - 如何将 sqlite db 文件包含到 netbeans 中的 jar 中?

Java 枚举等于

mysql - 与组中最大日期关联的 ID

php - mysql_fetch_assoc 错误

PHP 多个带有分隔表的下拉框

java - 将一组列从一个表复制到另一个表

java - HTTP 状态 415 – 使用 Angular js 的 Spring MVC 中出现不支持的媒体类型错误

java - 如何使 Wicket 的 "AjaxLink"无状态?