我还是初学者,我设法将我的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块,我仍然遇到同样的问题,实际上它现在更糟糕了:(。
答案 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)
您的Connection
是static
,因此,如果您碰巧打开多个连接,只有当您拨打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
正如其他人所说,不要让你的连接静止。