Когда мое приложение теряет связь, как мне его восстановить?
У меня есть приложение, которое я подключаю к базе данных MySQL. Он теряет соединение в середине ночи, а затем отключает соединения null
, а JDBC не получает сообщений за X секунд.
Я вызываю getConnection()
, прежде чем делать что-либо, требующее связи с SQL-сервером.
Это мой метод getConnection()
:
private Connection getConnection() {
try {
if (connection != null) {
if (connection.isClosed() || !connection.isValid(10000)) {
this.initializeRamsesConnection();
}
} else {
this.initializeRamsesConnection();
}
} catch (Exception e) {
debug("Connection failed: " + e);
}
return connection;
}
В методе initializeRamsesConnection()
я помещаю пароль и т.д. в строку, а затем создаю соединение стандартным способом JDBC.
Затем я вызываю этот метод:
private Connection getConnectionFromConnectionString() {
Connection con = null;
String driver = "com.mysql.jdbc.Driver";
try {
Class.forName(driver);//jdbc sorcery
//if there is no connection string
if (getConnectionString() == null) {
HMIDatabaseAdapter.debug("No connection string");
}
//makes a string out of the values of db/host
String str = getConnectionString();
//if there is no driver
if (driver == null) {
debug("" + ": " + "No driver");
}
//Tries to make a connection from the connection string, username, and the password.
con = DriverManager.getConnection(str, username, password);
//if for some reason the connection is null
if (con == null) {
HMIDatabaseAdapter.debug("CONNECTION IS NULL, WHAT?");
}
} catch (Exception ex) {
HMIDatabaseAdapter.debug("getConnection() " + ex);
}
return con;
}
Что я могу изменить в любом из этих методов для размещения потерянного соединения?
Ответы
Ответ 1
Это неправильный способ получения соединения. Вы получаете соединение и назначаете его как экземпляр (или, что еще хуже, статический) для класса. В принципе, вы поддерживаете соединение открытым навсегда и повторно используете одно соединение для всех запросов. Это может закончиться катастрофой, если запросы выполняются разными потоками. Кроме того, когда он будет храниться слишком долго, DB вернет его, потому что он предполагает, что он мертв/просочился.
Вы должны приобрести и закрыть соединение в кратчайшей возможной области. То есть в том же блоке try
, где вы выполняете запрос. Что-то вроде этого:
public Entity find(Long id) throws SQLException {
Entity entity = null;
try (
Connection connection = dataSource.getConnection(); // This should return a NEW connection!
PreparedStatement statement = connection.prepareStatement(SQL_FIND);
) {
statement.setLong(1, id);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
if (resultSet.next()) {
entity = new Entity(
resultSet.getLong("id"),
resultSet.getString("name"),
resultSet.getInt("value")
);
}
}
}
return entity;
}
Если вы беспокоитесь о подключении производительности и хотите повторно использовать подключения, вы должны использовать пул соединений. Вы можете сделать это, но я категорически против этого, поскольку вы, кажется, новичок в этом. Просто используйте существующий пул соединений, например BoneCP, C3P0 или DBCP. Обратите внимание, что вы должны не изменять идиому JDBC, как показано в приведенном выше примере. Вы все равно должны приобретать и закрывать соединение в кратчайшей возможной области. Пул соединений сам по себе беспокоится о фактическом повторном использовании, тестировании и/или закрытии соединения.
См. также:
Ответ 2
Где в вашем коде есть ошибки при потере соединения? Вероятно, это будет лучшее место для начала.
Сверху моей головы (и, возможно, я ошибаюсь), соединения JDBC будут закрываться только при фактической фатальной ошибке, поэтому вы не будете знать, что они потерпели неудачу, пока вы не попытаетесь что-то сделать.
То, что я делал в прошлом, заключается в недействительности соединения в момент сбоя и повторной попытки.
Ответ 3
Возможно, это то, что вы ищете:
http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html
Для java см. autoReconnect:
http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html