Java 调用数据库时,应用程序处于冻结状态

Java 调用数据库时,应用程序处于冻结状态,java,mysql,multithreading,swing,freeze,Java,Mysql,Multithreading,Swing,Freeze,我在Java的ComponentAdapter中实现了很多东西。由于它从数据库加载数据并在JTable中显示,所以我将其添加到另一个线程中。我将向您展示这样的ComponentAdapter private class DisplayInitialRevenue_Thread implements Runnable { @Override public void run() { displayInitialRe

我在Java的
ComponentAdapter
中实现了很多东西。由于它从数据库加载数据并在
JTable
中显示,所以我将其添加到另一个线程中。我将向您展示这样的
ComponentAdapter

private class DisplayInitialRevenue_Thread implements Runnable
     {

        @Override
        public void run() 
        {
            displayInitialRevenue_Method();
        }

     }

     private void displayInitialRevenue_Method()
     {
        //Get the dates from the combo
        String selectedCouple = revenueYearCombo.getSelectedItem().toString();

        if(selectedCouple.equals("Select Year"))
        {
            return;
        }

        String[] split = selectedCouple.split("/");


         //Related to DB
         double totalamountInvested;



             //Get data from the database
             dbConnector = new DBHandler();
             dbConnector.makeConnection();

             DefaultTableModel model = (DefaultTableModel) initialRevenueTable.getModel();
             model.setRowCount(0);



             ResultSet selectAllDetails = dbConnector.selectAllDetails("SQL CODE HERE ");

             try
             {
                 if(selectAllDetails.isBeforeFirst()==false)
                 {
                     JOptionPane.showMessageDialog(null,"This table is empty");
                 }
                 else
                 {
                     while(selectAllDetails.next())
                     {
                         String clientName = selectAllDetails.getString("Client Name");
                         String providerName = selectAllDetails.getString("Provider Name");
                         Double amountInvested = selectAllDetails.getDouble("Invest_Amount");


                        //Get Other Data


                         //Update the table
                         Object[]row = {dateS,clientName,providerName,amountInvested};

                         model.addRow(row);

                         //Get the total
                         amountInvested = amountInvested+amountInvested;

                     }

                     //Add the sum
                     Object[]blankRow = {null,null,null,null};
                     model.addRow(blankRow);

                      Object[]row = {dateS,clientName,providerName,amountInvested};
                 }
             }
             catch(SQLException sql)
             {
                 JOptionPane.showMessageDialog(null,sql.getLocalizedMessage());
             }
     }
并且,可以通过3种方式调用上述线程。这是通过
ItemListener
附加到
JComboBox
ActionListener
附加到
JMenu
ComponentListener
实现的

组件侦听器

private class DisplayInitialRevenue extends ComponentAdapter
     {
         public void componentShown(ComponentEvent e) 
         {
             formMemorizer = FormMemorizer.Initial_Revenue;
             //displayInitialRevenue_Method();

             DisplayInitialRevenue_Thread t = new DisplayInitialRevenue_Thread();
             t.run();
         }


     }
private class RevenueYearComboAction implements ItemListener
     {

        @Override
        public void itemStateChanged(ItemEvent e) 
        {
            if(e.getStateChange() == ItemEvent.SELECTED)
            {
                int selection = formMemorizer;

                if(selection==-1)
                {
                    return;
                }
                else if(selection==FormMemorizer.Initial_Revenue)
                {
                    //displayInitialRevenue_Method();
                    DisplayInitialRevenue_Thread t = new DisplayInitialRevenue_Thread();
                    t.run();
                }
        }
}
ItemListener

private class DisplayInitialRevenue extends ComponentAdapter
     {
         public void componentShown(ComponentEvent e) 
         {
             formMemorizer = FormMemorizer.Initial_Revenue;
             //displayInitialRevenue_Method();

             DisplayInitialRevenue_Thread t = new DisplayInitialRevenue_Thread();
             t.run();
         }


     }
private class RevenueYearComboAction implements ItemListener
     {

        @Override
        public void itemStateChanged(ItemEvent e) 
        {
            if(e.getStateChange() == ItemEvent.SELECTED)
            {
                int selection = formMemorizer;

                if(selection==-1)
                {
                    return;
                }
                else if(selection==FormMemorizer.Initial_Revenue)
                {
                    //displayInitialRevenue_Method();
                    DisplayInitialRevenue_Thread t = new DisplayInitialRevenue_Thread();
                    t.run();
                }
        }
}
我有很多这样的方法从数据库中获取数据,向JTables提供数据,从GUI中获取数据并保存在数据库中

现在我的问题是,每当数据库调用发生时,所有这些都会冻结。我以为是bcs的线程问题,所以我做了上面的
DisplayInitialRevenue\u线程
来调用
DisplayInitialRevenue\u方法()
。然后我只调用了与调用此方法相关的区域,但它有时仍然冻结!我的其他数据库方法不在单独的线程中,但这是一个方法,所以为什么甚至调用“only”这个方法都会导致冻结?它在一根线里

顺便说一句,我使用的是Java 8,使用的是MySQL服务器版本:5.6.16-MySQL社区服务器(GPL),它随XAMPP一起提供。

调用
t.start()
来启动一个新的
线程,调用
Thread#run
除了在同一线程上下文中调用
Thread
run
方法外,什么都不做

话虽如此,Swing不是线程安全的,Swing要求对UI的所有更新都是在事件调度线程的上下文中进行的。代替使用<代码>线程< /代码>,您应该考虑使用<代码> SaveWorks,它允许您在后台线程中执行长时间运行的任务,但它提供了易于使用的<代码>发布< //>代码>进程> <代码>方法,并在完成时调用<代码>完成< /代码>,在EDT的上下文中为您执行


有关更多详细信息,请参见

请查看它冻结的位置,是否使用了一些JProfiler,如何使用,从何处输出,但说明谈论阻止EDT,:-)Oracle教程-事件调度线程,我的建议是不要在生产代码中使用SwingWorker,投票也一样结束broad@mKorbel:在下面的一个答案中,答案是
使用SwingWorker
@mKorbel:我无法指出任何地方,冻结只会“有时”发生,而且会“在任何时候”调用DB。这意味着,有很多表单需要编辑、更新和查看数据库中的记录,使用任何此类表单都可能导致“有时”冻结这些记录。@mKorbel
t.run()
.“请给我更多建议”-不要做你正在做的事,使用
SwingWorker
。您可能希望有一个通读版本,它将使人们更容易阅读您的代码,您也更容易阅读其他代码:-)不要使用SwingWorker for JDBC,它是为enjoy@mKorbel为什么?通过一些调整(附加通知),我发现它实际上相当有用;)-添加一个
ExecutorService
,它会大大降低痛苦阈值…@MadProgrammer:想象一下我正在使用
t.start()
移动。有些人告诉我“不要使用其他线程更新GUI”?@sniper所有对UI的更新都需要与EDT的上下文同步执行,如果你不想使用
SwingWorker
,你需要使用
SwingUtilities.invokeLater
,这将突出我推荐
SwingWorker
的原因