简体   繁体   English

使用JDBC的Java - 连接太多了?

[英]Java using JDBC - Too many connections?

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. 我可以从MYSQL数据库中检索信息,我可以一次滚动一个结果。

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" 线程“main”中的异常com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:数据源拒绝建立连接,来自服务器的消息:“连接太多”

The code for the two separate files are as follows: 两个单独文件的代码如下:

  • The SQL queries in RetrieveStockQuery RetrieveStockQuery的SQL查询

     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 我的ViewStockGUI课程

      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. 如果有人可以提供帮助,将不胜感激。

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! 您要么不关闭连接,除非您得到SQLException或在处理结果集期间关闭它!

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). 通过将关闭置于finally您可以确保连接以正确的流程或异常关闭(为清楚起见,我省略了try-catch )。

So modify the code this way to close the connections. 因此,通过这种方式修改代码以关闭连接。

For better performance you should look into connection pooling 为了获得更好的性能,您应该研究连接池

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. ViewStockQuery类中,您有retrieveStock()方法。 This method then creates an instance of your GUI class, ViewStockGUI . 然后,此方法创建GUI类的实例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: 除了这是不好的做法之外,它会导致一个问题,因为在ViewStockGUI的构造函数中,您在此行的retrieveStock()方法中调用了它:

stockGUI = new ViewStockGUI();

you then again call retrieveStock() with this line: 然后再用这一行调用retrieveStock()

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. 这会导致递归问题,因为ViewStockGUI()构造函数调用retrieveStock()方法创建连接并再次调用ViewStockGUI()构造函数,该构造函数将再次调用未关闭连接并尝试打开的retrieveStock()方法不同的联系。 Hope you get the picture. 希望你能得到这张照片。

A way to solve it is to clean up your code. 解决它的方法是清理代码。 Don't call the constructor in retrieveStock() . 不要在retrieveStock()调用构造函数。 Find a different way to pass the selected category for your query. 查找为您的查询传递所选类别的其他方法。

Edit: 编辑:

Write you ViewStockQuery like so: 像你这样写ViewStockQuery

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. 然后编写ViewStockGUI ,以便在选择类别时,即创建ViewStockQuery并传入所选字符串。

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: 但是,出于本期的目的,您可以在ViewStockGUI中执行以下操作:

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. 第一行从组合框中收集选定的类别,第二行创建ViewStockQuery的实例,并将选定的ViewStockQuery传递给构造函数。 This will then initialize mSelected as you see in the constructor I put above for ViewStockQuery . 然后,这将初始化mSelected,就像我在上面为ViewStockQuery提出的构造函数中看到的ViewStockQuery

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.) 如果你想使用JDBC(而不是JPA),那么我建议使用Spring的JdbcTemplate或Java SE 7的自动资源管理(ARM)。(我还没有尝试使用JDBC的JDBC,但它应该可以工作。 )

Basically, you need to close Closeables in the finally blocks of a try-catch clause. 基本上,您需要在try-catch子句的finally块中关闭Closeables。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM