尝试在短时间内连续第二次运行 SQL 查询时 Java 挂起

Posted

技术标签:

【中文标题】尝试在短时间内连续第二次运行 SQL 查询时 Java 挂起【英文标题】:Java hanging when trying to run an SQL Query for the second time in short succession 【发布时间】:2016-03-24 10:42:47 【问题描述】:

问题:

我有一些代码连接到数据库,检查是否根据条件找到记录,如果找到记录,则返回 3 并生成一条消息让用户说已经存在这些记录细节。如果记录不存在,则执行插入查询以创建记录。

问题是选择查询在短时间连续第二次执行时,当结果是找到记录时似乎挂起(返回 3,向用户生成消息) - 因为它没有进展通过代码,没有报错,程序上的GUI无响应(无法点击任何其他对象,也无法响应关闭窗口)。 Netbeans 仍然运行良好,我可以通过它停止程序的运行。

测试:

A) 如果我在第一次成功执行后在同一个数据库上运行另一个查询,但在不同的表上,代码会正确执行,但返回尝试再次执行原始查询会导致它挂起。

B) 执行代码并且不返回任何结果不会导致它挂起。 (见下面的代码)

C) 扫描了关于 SE 的其他类似问题,但似乎找不到任何解决我的问题的方法。

使用的资源: ucanaccess-2.0.9.3,Netbeans IDE 8.1,JDK 1.8(由于与公司旧版本的兼容性问题,编译为 1.6),公司网络上的 MS Access 数据库

代码:

public int insertAddPeriod(String strProjectNumber, String strYear, String strPeriod)
    System.out.println("Checking to see if record already exists: " + strProjectNumber + ", Year: " + strYear + ", Period: " + strPeriod);
    String strSQLString = null;

    try

        strSQLString = "SELECT Program_No, Year, Period FROM tblCost WHERE Program_No = ? AND Year = ? AND Period = ?";

        //SETTING PREPARED STATEMENT
        PreparedStatement preStatement = con.prepareStatement(strSQLString, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);

        //SETTING FIRST CONDITION OF PREPARED STATEMENT IE ?                    
        preStatement.setString(1, strProjectNumber); 
        preStatement.setString(2, strYear); 
        preStatement.setString(3, strPeriod);  

        ResultSet rs = preStatement.executeQuery();

        if(rs.next()) 
            //CLOSES CONNECTIONS
            rs.close();
            preStatement.close();               

            System.out.println("Check Complete; Period Already Exists");
            return 3;
        
        else
            System.out.println("Check complete; No Previous Period");
            System.out.println("Inserting record: " + strProjectNumber + ", Year: " + strYear + ", Period: " + strPeriod);               
            strSQLString = null;
            try

                strSQLString = "INSERT INTO tblCost (Program_No, Year, Period) VALUES (?, ?, ?) ";

                //SETTING PREPARED STATEMENT
                PreparedStatement preStatement1 = con.prepareStatement(strSQLString, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);

                //SETTING FIRST CONDITION OF PREPARED STATEMENT IE ?                    
                preStatement1.setString(1, strProjectNumber); 
                preStatement1.setString(2, strYear); 
                preStatement1.setString(3, strPeriod);  

                //EXECUTE QUERY
                preStatement1.executeUpdate();

                //CLOSES CONNECTIONS
                preStatement1.close();

                System.out.println("Insert Complete");

                return 1;
            catch(Exception ex)
                strEXMessage=ex.getMessage();
                System.out.println(strEXMessage);
                return 2;
                     
           

    catch(Exception ex)
        strEXMessage=ex.getMessage();
        System.out.println(strEXMessage);
        System.out.println("Check error; Unable to check for previous period");
        return 2;
    


private void AddPeriod()        
    //Create Connection
    Database db = new Database();
    int r = 0;
    try 
        r = db.CreateConnection();
     catch (SQLException ex) 
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
     catch (ClassNotFoundException ex) 
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    
    //CONNECTION COMPLETE
    if(r==1)
        int q = 0;
        q = db.insertAddPeriod((String)cbProjectNumber.getSelectedItem(),(String)cbCostYear.getSelectedItem(),(String)cbCostPeriod.getSelectedItem());
        if(q==1)                             
            System.out.println("Record");
            JOptionPane.showMessageDialog(null,"Record added for the period: " + (String)cbCostPeriod.getSelectedItem(),"Complete",JOptionPane.WARNING_MESSAGE);                
        
        if(q==2)
            System.out.println("Error");
            JOptionPane.showMessageDialog(null,"There was an error processing the insert query","Error",JOptionPane.WARNING_MESSAGE);
        
        if(q==3)
            System.out.println("Missing");
            JOptionPane.showMessageDialog(null,"Record already exists for the selected period","Error",JOptionPane.WARNING_MESSAGE);
        
    

    //CONNECTION ERROR
    if(r==2)
        System.out.println("Error");
        JOptionPane.showMessageDialog(null,"No connection made","Error",JOptionPane.WARNING_MESSAGE);
    
    //CONNECTION RETURNS EMPTY
    if(r==3)
        System.out.println("No Records");
        JOptionPane.showMessageDialog(null,"No records found in table","Missing Records",JOptionPane.WARNING_MESSAGE);
    


    public int CreateConnection() throws SQLException, ClassNotFoundException
    try
        con = DriverManager.getConnection(strDBCon,strDBUser,strDBPass);
        System.out.println("Connection Passed");

        return 1;
    catch(SQLException ex)
        strEXMessage=ex.getMessage();
        System.out.println("Connection Failed: " + ex);
        return 2;
    
 

public int CloseConnection()
    try
        con.close();
        System.out.println("Connection Closed by User");
        return 1;
    catch(SQLException ex)
        strEXMessage=ex.getMessage();
        return 2;
    
 

请忽略不整洁(除非这是原因),目前清理它是一个 WIP。

【问题讨论】:

你是如何获取和释放连接的 @Rahul krestanos 解决方案对我来说非常有效,但作为参考,我用我的连接和发布代码编辑了帖子。 【参考方案1】:

这种情况下程序无响应通常是由于数据库的行锁,由于插入、更新、删除尚未提交。

正如我在您的代码中看到的,您没有提交准备好的语句。 您是否将自动提交设置为 true ? 如果没有,请在执行更新后使用 con.commit() 尝试它,并且该方法的第二次调用应该可以正常工作。

【讨论】:

以上是关于尝试在短时间内连续第二次运行 SQL 查询时 Java 挂起的主要内容,如果未能解决你的问题,请参考以下文章

为啥 MySQL 查询在我第二次运行时更快?

hibernate 一级缓存,二级缓存,查询缓存

Google BigQuery 对奇怪尝试的不完整查询回复

jsp提交后,短时间内没切换页面,则样才能禁止用户连续点击提交按钮。。。

DELETE QUERY 第一次运行缓慢,但第二次(对于相同条件)运行快速 - 如何在第一次运行时使查询快速运行?

Firebase Firestore get() 快照在第二次查询时冻结