我还是初学者,我已经设法将我的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());
}
}
}
我的DB类
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;
}
}
Myteamdb类处理团队查询
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类处理Player查询。
非常感谢任何建议,
祝大家新年快乐
更新的代码所以现在实现Try with Resource块,我仍然有同样的问题,实际上现在更糟糕了:(。
您正在打开连接,不一定要关闭它们。除了使用连接池之外,您还可以在每个操作中创建新连接。
最好使用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
可以在最里面使用。在返回/中断/抛出时,将调用隐式final来执行close。
我自己没有捕获SQLException,但是将throws SQLException
添加到方法头。这允许delete...(...); save...();
以安全的方式完成。捕获只是在呼叫位置移动。在这里,我被迫抛出另一个(运行时)异常,因为当没有可加载的玩家时无法返回任何内容。删除捕获并添加throws SQLException
会更好。
我没看到的其他问题;只是rs
是奇怪的,并没有处理失败的rs.next()
返回虚假。在数据问题上,例如mysql允许的字符集,SQL数据类型等,人们会收到SQLExceptions。
你的Connection
是static
,所以如果你碰巧打开多个连接,只有你打电话给closeConnection
时才会关闭最后创建的连接,其他连接将保持活着状态。
考虑忘记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;
}
}
如果连接池对您来说太有问题,那么您应该将连接包装在“尝试使用资源”结构中,这将保证在您完成它们时关闭。
见https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
正如其他人所说,不要让你的连接静止。