我不认为我正在关闭我的连接 - Java

时间:2018-01-02 16:11:39

标签: java mysql

我还是初学者,我设法将我的Java项目与Heroku的在线MySQL数据库联系起来。在他标记我的工作时,期望我的导师配置我的离线数据库似乎更好。

但是,我现在有太多的连接问题,而且我的程序性能非常慢。我想我已经正确地关闭了我的代码中的连接 - 但我相信有人可以指出我的错误:)

允许的最大连接数为10,以某种方式达到最大值。

public class DBConnect {

Connection dbConnection;
Statement stmt;
ResultSet rs; 

protected Connection connectToDatabase() {
    try {
        dbConnection=DriverManager.getConnection("jdbc:mysql://us-cdbr-iron-east-05.cleardb.net", "be0f2e99e68dbf", "ad1ed239");
    } catch (SQLException error) {
          System.err.println("Error connecting to database: "+ error.toString());
    }
    return dbConnection;
}

public void closeConnection(){
    try {
        if (null != dbConnection && !dbConnection.isClosed()) {
            dbConnection.close();
        }
    }
    catch (SQLException sqle)
    {
        System.out.println("Error closing connection: " + sqle.toString());
    }
}
}

我的数据库课程

public class TeamDB extends DBConnect {

Team t;

public TeamDB(){
}

public void saveTeam(String teamName, int GoalsScored){
    final String insertStmt = "INSERT INTO heroku_2b89816185313b9.TEAM (TEAMNAME, GOALSSCORED) VALUES (?,?)";
    try (Connection con = connectToDatabase()) {
        try (PreparedStatement pstmt =  con.prepareStatement(insertStmt)) {
            pstmt.setString(1,teamName);
            pstmt.setInt(2, GoalsScored);
            pstmt.executeUpdate();
        }  
    } catch (SQLException sqle){ 
            System.out.println("Exception when inserting Team record: " + sqle.toString());
        }

}

public void updateTeam(String teamName, int GoalsScored){
    final String loadStmt = "SELECT * FROM heroku_2b89816185313b9.TEAM WHERE TEAMNAME = '" + teamName + "'";
    try (Connection con = connectToDatabase()) {
        try (PreparedStatement pstmt = con.prepareStatement(loadStmt)) {
            rs = pstmt.executeQuery(loadStmt);
            rs.next();
            deleteTeam(teamName);
            saveTeam(rs.getString("TEAMNAME"), (GoalsScored+rs.getInt("GOALSSCORED")));
            rs.close();
        } 
    } catch(SQLException error) { 
        System.err.println("Error updating team: " + error.toString());
    } 
}

public void deleteTeam(String teamName){
    final String deleteStmt = "DELETE FROM heroku_2b89816185313b9.TEAM WHERE TEAMNAME = '" + teamName + "'";
    try (Connection con = connectToDatabase()) {
        try (PreparedStatement pstmt = con.prepareStatement(deleteStmt)){
            pstmt.executeUpdate(deleteStmt);
        } catch (SQLException error) {
            System.err.println("Error deleting team from database: " + error.toString());
        }
    } catch (SQLException error) {
        System.out.println("Error connecting to database"+error.toString());
    }

}

public ArrayList<String> viewTeams() throws SQLException{
    ArrayList<String> teamNames = new ArrayList<>();
    String viewTeams = "SELECT TEAMNAME FROM heroku_2b89816185313b9.TEAM";
    try (Connection con = connectToDatabase()){
        try (PreparedStatement pstmt = con.prepareStatement(viewTeams)) {
            rs = pstmt.executeQuery();            
            while (rs.next()) {
                String nms = rs.getString("TEAMNAME");
                teamNames.add(nms);
            }
            rs.close();
        }

    } catch (SQLException error) {
        System.err.println("Error viewing teams from database: " + error.toString());
    }
    return teamNames;
}


public ArrayList<TeamScore> sortLeagueTable() throws SQLException {
    ArrayList<TeamScore> teamData = new ArrayList<>();
    String viewTeams = "SELECT * FROM heroku_2b89816185313b9.TEAM ORDER BY GOALSSCORED DESC";
    try (Connection con = connectToDatabase()){
        try (PreparedStatement pstmt = con.prepareStatement(viewTeams)) {
            rs = pstmt.executeQuery();
            while (rs.next()) {
            TeamScore ts = new TeamScore(rs.getString("TEAMNAME"),rs.getInt("GOALSSCORED"));
            teamData.add(ts);
            }
        }
    } catch (SQLException error) {
        System.err.println("Error sorting league table: " + error.toString());
    } 
    return teamData;
}
}

我的TeamDB类处理团队查询

public class PlayerDB extends DBConnect {

Player p;

public PlayerDB(){
}

public void savePlayer(final String playerName,
        final int playerGoals, final int redCards,
        final int yellowCards, final int gamesAsCap,
        final int forward, final int center,
        final int back) {
        final String insertStmt = "INSERT INTO heroku_2b89816185313b9.PLAYER (playerName,"
                + " playerGoals, redCards, yellowCards, gamesAsCap, forward,"
                + " center, back) VALUES (?,?,?,?,?,?,?,?)";
        try (Connection con = connectToDatabase()) {
            try (PreparedStatement pstmt = con.prepareStatement(insertStmt)) {
                pstmt.setString(1, playerName);
                pstmt.setInt(2, playerGoals);
                pstmt.setInt(3, redCards);
                pstmt.setInt(4, yellowCards);
                pstmt.setInt(5, gamesAsCap);
                pstmt.setInt(6, forward);
                pstmt.setInt(7, center);
                pstmt.setInt(8, back);
                pstmt.executeUpdate();
            }
        } 
        catch (SQLException sqle){ 
            System.out.println("Exception when inserting Player record: " + sqle.toString());
        }
}

public Player updatePlayer(String pN, int goalsThis, Boolean isCap, String posPlayed, int redC, int yelC){
    final String loadStmt = "SELECT * FROM heroku_2b89816185313b9.PLAYER WHERE PLAYERNAME = '" + pN + "'";
    try (Connection con = connectToDatabase()) {
        try (PreparedStatement pstmt = con.prepareStatement(loadStmt)) {
            rs = pstmt.executeQuery(loadStmt);
            rs.next();
            deletePlayer(pN);
            p = new Player(pN, goalsThis, isCap, posPlayed, redC, yelC);
            p.playerName = rs.getString("PLAYERNAME");
            p.totPlayerGoals += rs.getInt("PLAYERGOALS");
            p.totYellowCards += rs.getInt("YELLOWCARDS");
            p.totRedCards += rs.getInt("REDCARDS");
            p.totGamesAsCap += rs.getInt("GAMESASCAP");
            p.positionNum[0] += rs.getInt("FORWARD");
            p.positionNum[1] += rs.getInt("CENTER");
            p.positionNum[2] += rs.getInt("BACK");
            rs.close();
        }           
    }
    catch(SQLException error)
    { 
        System.err.println("Error connecting to database: " + error.toString());
    }
    finally {
        p.savePlayer();
        return p;
    }    
}

public Player loadPlayer(String plrName){
    final String loadStmt = "SELECT * FROM heroku_2b89816185313b9.PLAYER WHERE PLAYERNAME = '" + plrName + "'";
    try (Connection con = connectToDatabase()) {
        try (PreparedStatement pstmt = con.prepareStatement(loadStmt)) {
            rs = pstmt.executeQuery(loadStmt);
            rs.next();
            p = new Player("",0,Boolean.FALSE,"",0,0);
            p.playerName = rs.getString("PLAYERNAME");
            p.totPlayerGoals = rs.getInt("PLAYERGOALS");
            p.totYellowCards = rs.getInt("YELLOWCARDS");
            p.totRedCards = rs.getInt("REDCARDS");
            p.totGamesAsCap = rs.getInt("GAMESASCAP");
            p.positionNum[0] = rs.getInt("FORWARD");
            p.positionNum[1] = rs.getInt("CENTER");
            p.positionNum[2] = rs.getInt("BACK");
            rs.close();
        }
    } catch(SQLException error) { 
        System.err.println("Error connecting to database: " + error.toString());
    } finally {
        return p;
    } 
}

public void deletePlayer(final String playerName){
    final String deleteStmt = "DELETE FROM heroku_2b89816185313b9.PLAYER WHERE PLAYERNAME = '" + playerName + "'";
    try (Connection con = connectToDatabase()) {
        try (PreparedStatement pstmt = con.prepareStatement(deleteStmt)) {
            pstmt.executeUpdate(deleteStmt);
        } catch (SQLException error) {
            System.err.println("Error deleting player from database: " + error.toString());
        }
    } catch (SQLException error) {
        System.out.println("Error connecting to database"+error.toString());
    }

}

public ArrayList viewPlayers(){
    ArrayList vp = new ArrayList();
    String viewPlayers = "SELECT * FROM heroku_2b89816185313b9.PLAYER";
    connectToDatabase();
    try (Connection con = connectToDatabase()) {
        try (PreparedStatement pstmt = con.prepareStatement(viewPlayers)) {
            rs = pstmt.executeQuery(viewPlayers); 
            while (rs.next()){
            vp.add((rs.getString("PLAYERNAME")));
            }
            rs.close();
        }
    } catch (SQLException error) {
        System.err.println("Error querying database for player names: " + error.toString());
    } finally {
        return vp;
    }       
}
}

我的PlayerDB类处理播放器查询。

非常感谢任何建议,

所有新年快乐

更新了代码所以现在实现了Try with Resource块,我仍然遇到同样的问题,实际上它现在更糟糕了:(。

3 个答案:

答案 0 :(得分:3)

您正在打开连接,不一定要关闭它们。除了使用连接池之外,您还可以在每个操作中创建一个新连接。

最好使用 try-with-resources 预处理语句(而不是将SQL字符串组合成碎片 - 转义单引号并阻止SQL注入)。

List<Product> list = new ArrayList<>();
try (Connection connection = openConnection()) {
    try (PreparedStatement preparedStatement = connection.prepareStatement(query)) {
        preparedStatement.setInt(1, appId);
        try (resultSet = preparedStatement.executeQuery()) {
            while (resultSet.next()) {
                Product item = getProductById(resultSet.getInt("prodId"));
                list.add(item);
            } 
            return list;
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

try-with-resources确保自动关闭,也支持Statement和ResultSet。

Class.forName不再需要找到一个驱动程序。

进一步检查

令人不安

我已经看到一个变量rs的ResultSet也是AutoClosable。也可以使用try-with-resources。我确实认为代码已经混淆了一些; rs不应该是一个字段,而应该是一个局部变量。否则,两种方法可能使用相同的rs用于不同目的。请参阅下面的代码示例。

提示 使用exception.getMessage()exception.getLocalizedMessage()(取决于语言)代替toString()

也许是一项改进

一般情况下,不一定在您需要所有字段时:而不是SELECT *更好地列出您需要的列,并通过索引(rs.getInt(1)等来获取它们上)。

仅限改善

更换

"jdbc:mysql://us-cdbr-iron-east-05.cleardb.net"

通过

"jdbc:mysql://us-cdbr-iron-east-05.cleardb.net/heroku_2b89816185313b9"

会缩短查询次数,因为heroku_2b89816185313b9.可以在其他地方删除。

仅限改善

public Player loadPlayer(String plrName) {
    final String loadStmt = "SELECT * FROM PLAYER WHERE PLAYERNAME = ?";
    try (Connection con = connectToDatabase()) {
        try (PreparedStatement pstmt = con.prepareStatement(loadStmt)) {
            pstmt.setString(1, plrName);
            try (ResultSet rs = pstmt.executeQuery(loadStmt)) {
                if (!rs.next()) {
                    throw new SQLException("Player does not exist: " + plrName);
                }
                Player p = new Player("",0,Boolean.FALSE,"",0,0);
                p.playerName = rs.getString("PLAYERNAME");
                p.totPlayerGoals = rs.getInt("PLAYERGOALS");
                p.totYellowCards = rs.getInt("YELLOWCARDS");
                p.totRedCards = rs.getInt("REDCARDS");
                p.totGamesAsCap = rs.getInt("GAMESASCAP");
                p.positionNum[0] = rs.getInt("FORWARD");
                p.positionNum[1] = rs.getInt("CENTER");
                p.positionNum[2] = rs.getInt("BACK");
                return p;
            }
        }
    } catch(SQLException error) { 
        System.err.println("Error connecting to database: " + error.getMessage());
        throw new IllegalStateException("Loading player", error);
    } 
}

return可以在最里面使用。在返回/中断/抛出时,将调用一个隐式的最终结束。

我自己不会捕获SQLException,而是将throws SQLException添加到方法标头中。这样可以安全地完成delete...(...); save...();。捕获只是在呼叫位置移动。在这里,我被迫抛出另一个(运行时)异常,因为当没有可加载的玩家时无法返回任何内容。 删除catch并添加throws SQLException会更好。

我没有看到的其他问题;仅仅rs是奇怪的,并且没有处理失败的rs.next()返回false。在数据问题上,比如mysql允许的字符集,SQL数据类型等,就会收到SQLExceptions。

答案 1 :(得分:2)

您的Connectionstatic,因此,如果您碰巧打开多个连接,只有当您拨打closeConnection时,最后创建的连接才会关闭,其他连接将保持活动状态。< / p>

考虑忘记static,并查看连接池,因为每次需要时都会创建一个新连接,但性能很差。

以下是创建两个连接的示例,但第一个连接永远不会关闭:

    public ArrayList viewPlayers(){

        ArrayList vp = new ArrayList();
        String viewPlayers = "SELECT * FROM heroku_2b89816185313b9.PLAYER";
        // here dbConnection becomes a new connection, say connection1
        connectToDatabase();

        // here you are creating a new connection, say connection2
        try (Connection con = connectToDatabase()) {
            try (PreparedStatement pstmt = con.prepareStatement(viewPlayers)) {
                rs = pstmt.executeQuery(viewPlayers); 
                while (rs.next()){
                vp.add((rs.getString("PLAYERNAME")));
                }
                rs.close();
            }
        } catch (SQLException error) {
            System.err.println("Error querying database for player names: " + error.toString());
        } finally {
            // try-with-resources is closing the connection2
            // but connection1 has never been closed
            return vp;
        }       
    }

答案 2 :(得分:0)

如果连接池对您来说太有问题,那么您应该将连接包装在“尝试使用资源”结构中,这样可以保证在完成连接后关闭。

请参阅https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

正如其他人所说,不要让你的连接静止。