Java using JDBC - Too many connections?

2020-03-04 07:25发布

问题:

I am writing a stock replenishment system for a bar as my final year project. I can retrieve information from a MYSQL database and I can scroll through one result at a time.

I'm trying to change the results depending on a selected category. I've managed to use a combo box to acheive this but I get the following error when moving between categories:

Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"

The code for the two separate files are as follows:

  • The SQL queries in RetrieveStockQuery

    public JComboBox getComboBox() throws SQLException {
      con = SQLConnect.getConnection();
      combo = new JComboBox();
      combo.removeAllItems();
      try {
        stat = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE );
        rs = stat.executeQuery("SELECT categoryName FROM Category");
    
        while (rs.next()) {
          combo.addItem(rs.getString("categoryName"));
          categoryName = rs.getString("categoryName"); 
        }
      }
      catch (SQLException sqle) {
        System.out.println(sqle);
        stat.close();
        con.close();
      }
      return combo;
    }
    
    //----------------------------------------------------------------
    
    public void retrieveStock() throws SQLException { 
    
      con = SQLConnect.getConnection();
      stockGUI = new ViewStockGUI(); // I THINK THIS IS WHAT IS CAUSING THE ERROR   
    
      String viewStock = "SELECT * FROM Stock where categoryName = '" + "'" + stockGUI.selected + "'";
      System.out.println(viewStock);
    
      try {
        stat = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE );
        rs = stat.executeQuery(viewStock);
    
        while(rs.next()){
          stockID = rs.getInt("stockID");
          stockName = rs.getString("stockName");
          stockDescription = rs.getString("stockDescription");
          stockPrice = rs.getFloat("stockPrice");
          stockQuantity = rs.getInt("stockQuantity");
          categoryName = rs.getString("categoryName");  
    
          ID = Integer.toString(stockID);
          price = Float.toString(stockPrice);
          quantity = Double.toString(stockQuantity);
          stat.close();
          con.close();
    
          System.out.println( "Stock ID: " + stockID + " Stock Name: " + stockName + " Stock Description: " + stockDescription + " Stock Price: " + stockPrice + " Stock Quantity:" + stockQuantity + " Category: " + categoryName);
        }    
      }  
      catch (SQLException err) {
        System.out.println(err.getMessage());   
      }
    }
    
  • My ViewStockGUI class

      public class ViewStockGUI extends JPanel {
    
        private static final long serialVersionUID = 1L;
        final JFrame viewFrame;
        ViewStockQuery stockQuery;
        ViewStockQuery stockName;
        JComboBox comboGUI;
        String selected;
        JComboBox combo;
    
        public ViewStockGUI() throws SQLException {
    
          final ViewStockQuery stock = new ViewStockQuery();
    
          comboGUI = stock.getComboBox();
          stock.retrieveStock();
          viewFrame = new JFrame("View Stock");
    
          JPanel p = new JPanel();
          p.setBorder (new TitledBorder(new LineBorder(Color.black, 1, true)));
          p.setPreferredSize(new Dimension(500,400));
    
          JPanel p2 = new JPanel();
          p2.setBorder (new TitledBorder(new LineBorder(Color.black, 1, true)));
          p2.setPreferredSize(new Dimension(500, 50));
    
          JPanel p3 = new JPanel();
          JPanel p4 = new JPanel();
          JPanel p5 = new JPanel();
          JPanel p6 = new JPanel();
    
          Box box = Box.createVerticalBox();        
          Box box2 = Box.createHorizontalBox();
          Box box3 = Box.createHorizontalBox();
          Box box4 = Box.createHorizontalBox();
    
          final JTextField textfieldStockName;
          final JTextField textfieldStockID;
          final JTextField textfieldStockDescription;
          final JTextField textfieldStockPrice;
          final JTextField textfieldStockQuantity;
          final JTextField textfieldStockCategory;
    
          final JLabel stockName = new JLabel("Name:");
          JLabel stockID = new JLabel("ID:");
          JLabel stockDescription = new JLabel("Description:");
          JLabel stockPrice = new JLabel("Price:");
          JLabel stockQuantity = new JLabel("Quantity:");
          JLabel categoryName = new JLabel("Category:");
    
          box.add(Box.createVerticalGlue());
          box.add(stockName);
          box.add(textfieldStockName = new JTextField(""));
          textfieldStockName.setText(stock.getStockName());
          textfieldStockName.setEditable(false);
    
          box.add(stockID);
          box.add(textfieldStockID = new JTextField(""));
          textfieldStockID.setText(stock.getStockID());
          textfieldStockID.setEditable(false);
    
          box.add(stockDescription);
          box.add(textfieldStockDescription = new JTextField(""));
          textfieldStockDescription.setText(stock.getStockDescription());
          textfieldStockDescription.setEditable(false);
    
          box.add(stockPrice);
          box.add(textfieldStockPrice = new JTextField(""));
          textfieldStockPrice.setText(stock.getStockPrice());
          textfieldStockPrice.setEditable(false);
    
          box.add(stockQuantity);
          box.add(textfieldStockQuantity = new JTextField(""));
          textfieldStockQuantity.setText(stock.getStockQuantity());
          textfieldStockQuantity.setEditable(false);
    
          box.add(categoryName);
          box.add(textfieldStockCategory = new JTextField(""));
          textfieldStockCategory.setText(stock.getStockCategory());
          textfieldStockCategory.setEditable(false);
          box.add(Box.createVerticalGlue());
    
          JButton next = new JButton("Next");
          next.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              stock.doNext();
              textfieldStockName.setText(stock.getStockName());
              textfieldStockID.setText(stock.getStockID());
              textfieldStockDescription.setText(stock.getStockDescription());
              textfieldStockPrice.setText(stock.getStockPrice());
              textfieldStockQuantity.setText(stock.getStockQuantity());
              textfieldStockCategory.setText(stock.getStockCategory());
            }
          }); 
    
          JButton previous = new JButton("Previous");
          previous.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              stock.doPrevious();
              textfieldStockName.setText(stock.getStockName());
              textfieldStockID.setText(stock.getStockID());
              textfieldStockDescription.setText(stock.getStockDescription());
              textfieldStockPrice.setText(stock.getStockPrice());
              textfieldStockQuantity.setText(stock.getStockQuantity());
              textfieldStockCategory.setText(stock.getStockCategory());
            }
          }); 
    
          final Counter counter = new Counter();
          final JLabel text = new JLabel(counter.getValue1());
    
          JButton plus = new JButton("+");
          plus.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              counter.increment();
              text.setText(counter.getValue1());
            }
          }); 
    
        JButton minus = new JButton("-");
        minus.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            counter.decrease();
            text.setText(counter.getValue1());
          }  
        });
    
        JButton update = new JButton("Update");
        update.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            try {
              stock.updateStock(counter.getValue1());
            } 
            catch (SQLException e1) {
              e1.printStackTrace();
            }
            finally { // doesn't update yet; will work on this later
              textfieldStockQuantity.setText(stock.getStockQuantity());
            }
          }
        }); 
    
        comboGUI.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            try {
              combo = (JComboBox) e.getSource();
              selected = (String)combo.getSelectedItem();
              textfieldStockName.setText(stock.getStockName());
              textfieldStockID.setText(stock.getStockID());
              textfieldStockDescription.setText(stock.getStockDescription());
              textfieldStockPrice.setText(stock.getStockPrice());
              textfieldStockQuantity.setText(stock.getStockQuantity());
              textfieldStockCategory.setText(stock.getStockCategory());
              stockQuery.con.close();
            }
            catch (SQLException e1) {
              e1.printStackTrace();
            }
          }
        }); 
    
    
        box.add(comboGUI);      
        box2.add(previous);
        box2.add(next);
        box3.add(minus);
        box3.add(text);
        box3.add(plus);
        box4.add(update);
    
        p.add(box2);
        p.add(box);
        p.add(box3);
        p.add(box4);
    
        this.add(p, BorderLayout.SOUTH);
      }
    }
    

If anyone can help it would be appreciated.

回答1:

You get this exception when you have too many open connections.
This is configurable but in your case the problem is in your code.

The code you posted is weird (the least).
You either don't close the connection unless you get an SQLException or you close it during processing of a result set!

In any case you should refactor your code to close connections and result set etc as soon as you are finished.
Example:

try { 

     stat = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE ); 
     rs = stat.executeQuery("SELECT categoryName FROM Category"); 

  while (rs.next()) { 
      combo.addItem(rs.getString("categoryName")); 
      categoryName = rs.getString("categoryName");  


  } 
} catch (SQLException sqle) { 
  System.out.println(sqle);   
} 
finally{
 if(stat != null) stat.close(); 
 if(con != null)  con.close(); 
}

By putting the close in a finally you are sure that the connection is closed either in correct flow or in exception (I have omitted try-catch for clarity).

So modify the code this way to close the connections.

For better performance you should look into connection pooling



回答2:

I think I see the problem in your code. Your code is extremely strange but here's what I think is happening:

In your ViewStockQuery class, you have the retrieveStock() method. This method then creates an instance of your GUI class, ViewStockGUI. Apart from this being bad practice, it leads to a problem here because in the constructor of the ViewStockGUI, which you called in the retrieveStock() method in this line:

stockGUI = new ViewStockGUI();

you then again call retrieveStock() with this line:

final ViewStockQuery stock = new ViewStockQuery();

comboGUI = stock.getComboBox();
stock.retrieveStock();

This leads to a recursive issue as your ViewStockGUI() constructor calls the retrieveStock() method which creates a connection and again calls the ViewStockGUI() constructor which will again call the retrieveStock() method that hasn't closed the connection and tries to open a different connection. Hope you get the picture.

A way to solve it is to clean up your code. Don't call the constructor in retrieveStock(). Find a different way to pass the selected category for your query.

Edit:

Write you ViewStockQuery like so:

private String mSelected;

public ViewStockQuery(String selectedCategory) {
    mSelected = selectedCategory;
}

...

public void retrieveStock() throws SQLException { 

    con = SQLConnect.getConnection();


    String viewStock = "SELECT * FROM Stock where categoryName = '" + "'" + mSelected + "'";
    System.out.println(viewStock);


     try {
...

Then write your ViewStockGUI in such a way that when a category has been selected, that is when you create the ViewStockQuery and pass in the selected string.

Edit:

Like I said before, there are quite a lot of things you will eventually need to change in your code. But, for the purpose of this issue, what you could do is in your ViewStockGUI, do:

String selected = (String)combo.getSelectedItem();
final ViewStockQuery stock = new ViewStockQuery(selected);

The first line collects the selected category from your combobox and the second line creates an instance of ViewStockQuery and passes the selected to the constructor. This will then initialize mSelected as you see in the constructor I put above for ViewStockQuery.



回答3:

If you want to use JDBC (rather than JPA), then I recommend to either use JdbcTemplate from Spring or the Automatic Resource Management (ARM) of Java SE 7. (I haven't tried JDBC with ARM yet, but it should work.)

Basically, you need to close Closeables in the finally blocks of a try-catch clause.



标签: java mysql jdbc