2014-02-20 3 views
1

Я разрабатываю приложение Java, которое использует MySQL для записи и чтения некоторых данных. Через некоторое время (очень долгое время) мое соединение jdbc закрывается, я читал на многих форумах, и я все еще не могу сделать это навсегда.Требуется решение для параллелизма Java

Что я хочу сделать следующее следующее: После 5,6,24 часа (по-прежнему не знаю, сколько часов) я закрою соединение и снова подключусь. Проблема в том, что если другой поток пытается использовать это соединение для написания чего-либо, он не будет работать при исключении. Поэтому я хочу сделать следующее, если соединение jdbc перезапускает все потоки, которые должны использовать jdbc, до тех пор, пока соединение повторно не будет завершено. Также я не хочу блокировать поток, если другой поток использует это соединение, только если перезапускается. Также я боюсь тупиков :).

Я читал о параллельности Java и о том, как управлять им со многих форумов и до сих пор не знаю, что использовать и как его использовать.

Полезные форумы:

http://www.vogella.com/tutorials/JavaConcurrency/article.html

http://en.wikipedia.org/wiki/Java_concurrency

http://tutorials.jenkov.com/java-concurrency/index.html

Edit:

Для того, чтобы было более понятно, что я хочу сделать

J AVA база данных Класс:

public class Database { 

     //Locks 
     final Object readLock = new Object(); 
     final Object writeLock = new Object(); 
     final Object readWriteLock = new Object(); 
     boolean enableReadLock = false; 
     boolean enableWriteLock = false; 
     //Database parametars 
     String user; //DB username /корисник на базата 
     String password; //DB password /лозинка за базата 
     String dbname; //DB name/име на базата 
     String ip; //DB Server IP address/адреса на серверот каде е базата 
     Connection connection; //mysql connection/


     public Database(String user, String password, String dbname, String ip) throws ClassNotFoundException { 
      Class.forName("com.mysql.jdbc.Driver"); 
      this.user = user; 
      this.password = password; 
      this.dbname = dbname; 
      this.ip = ip; 
     } 


     public Database(String user, String password, String dbname) throws ClassNotFoundException { 
      Class.forName("com.mysql.jdbc.Driver"); 
      this.user = user; 
      this.password = password; 
      this.dbname = dbname; 
      this.ip = "localhost"; 
     } 


     public void setReadLock(boolean enable) { 
      enableReadLock = enable; 
     } 

     /** 
     * Enable or disable write lock 
     * 
     * @param enable true -> enable , false -> disable 
     */ 
     public void setWriteLock(boolean enable) { 
      enableWriteLock = enable; 
     } 

     /** 
     * Enable or disable read-write lock 
     * 
     * @param enable true -> enable , false -> disable 
     */ 
     public void setReadWriteLock(boolean enable) { 
      enableReadLock = enable; 
      enableWriteLock = enable; 
     } 

     public void reconnect() throws SQLException { 
      connection.close(); 
      connection = DriverManager.getConnection("jdbc:mysql://" + ip + ":3306/" + dbname, user, password); 
    } 

     public void connect() throws SQLException { 
      connection = DriverManager.getConnection("jdbc:mysql://" + ip + ":3306/" + dbname, user, password); 
     } 


     public void disconnect() throws SQLException { 
      connection.close(); 
     } 



     /** 
     * Test connection with mysql server 
     * 
     * @return (boolean) true -> OK, false -> NOK 
     */ 
     public boolean testConnection() { 
      String SQL = "SELECT 1"; 
      try { 
       PreparedStatement statement = connection.prepareStatement(SQL); 
       ResultSet rs = statement.executeQuery(); 
       while (rs.next()) { 
       } 
      } catch (SQLException ex) { 
       return false; 
      } catch (NullPointerException ex){ 
       return false; 
      } 
      return true; 
     } 


     public ArrayList<HashMap<String, String>> executeSelect(String SQL) throws SQLException { 
      if (enableReadLock && enableWriteLock) { //Доколку има read-write lock 
       synchronized (readWriteLock) { 
        return select(SQL); 
       } 
      } else { 
       if (enableReadLock) { //Доколку има read-lock 
        synchronized (readLock) { 
         return select(SQL); 
        } 
       } else { 
        return select(SQL); 
       } 
      } 
     } 


     private ArrayList<HashMap<String, String>> select(String SQL) throws SQLException { 
      ArrayList<HashMap<String, String>> results = new ArrayList<>(); 
      HashMap<String, String> row; 
      PreparedStatement statement = connection.prepareStatement(SQL); 
      ResultSet rs = statement.executeQuery(); 
      ResultSetMetaData rsmd = rs.getMetaData(); 
      int no_columns = rsmd.getColumnCount(); 
      while (rs.next()) { 
       row = new HashMap<>(); 
       for (int i = 1; i <= no_columns; i++) { 
        row.put(rsmd.getColumnName(i), rs.getString(i)); 
       } 
       results.add(row); 
      } 
      statement.close(); 
      rs.close(); 
      return results; 
     } 


     public long executeInsert(String SQL) throws SQLException { 
      if (enableReadLock && enableWriteLock) { 
       synchronized (readWriteLock) { 
        return insert(SQL); 
       } 
      } else { 
       if (enableWriteLock) { 
        synchronized (writeLock) { 
         return insert(SQL); 
        } 
       } else { 
        return insert(SQL); 
       } 
      } 
     } 


     private long insert(String SQL) throws SQLException { 
      long ID = -1; 
      PreparedStatement statement = connection.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS); 
      statement.executeUpdate(); 
      ResultSet rs = statement.getGeneratedKeys(); 
      if (rs.next()) { 
       ID = rs.getLong(1); 
      } 
      statement.close(); 
      return ID; 
     } 


     public int executeUpdate(String SQL) throws SQLException { 
      if (enableReadLock && enableWriteLock) { 
       synchronized (readWriteLock) { 
        return update(SQL); 
       } 
      } else { 
       if (enableWriteLock) { 
        synchronized (writeLock) { 
         return update(SQL); 
        } 
       } else { 
        return update(SQL); 
       } 
      } 
     } 


     private int update(String SQL) throws SQLException { 
      PreparedStatement statement = connection.prepareStatement(SQL); 
      int rez = statement.executeUpdate(SQL); 
      statement.close(); 
      return rez; 
     } 


     public int executeDelete(String SQL) throws SQLException { 
      if (enableReadLock || enableWriteLock) { 
       synchronized (readWriteLock) { 
        synchronized (readLock) { 
         synchronized (writeLock) { 
          return delete(SQL); 
         } 
        } 
       } 
      } else { 
       return delete(SQL); 
      } 
     } 


     private int delete(String SQL) throws SQLException { 
      PreparedStatement statement = connection.prepareStatement(SQL); 
      int rez = statement.executeUpdate(SQL); 
      statement.close(); 
      return rez; 
     } 
    } 

В методе RECONNECT я потребуется некоторый замок или что-то, что заставит всех, кто называют выбрать, обновление, вставку или удаление методов ждать (блок), пока переподключение не будет закончено.

ответ

1

Попробуйте это oracle jdbc multithreading tutorial. или просто пользователю Apache connection pool

Многопоточность улучшит вашу производительность, но есть пара вещей, которые вам нужно знать:

Для каждого потока требуется собственное соединение JDBC. Соединения не могут использоваться совместно между потоками, поскольку каждое соединение также является транзакцией. Загрузите данные в кусках и совершите время от времени, чтобы избежать накопления огромных столов отката/отмены. Вырезать задания на несколько рабочих единиц, где каждый блок выполняет одно задание. Разработать последнюю точку: На данный момент, вы есть задача, которая считывает файл, разбирает его, открывает соединение JDBC, делают некоторые вычисления, отправляют данные в базу данных и т.д.

Что вы должны сделать:

Один (!) Поток для чтения файла и создания «рабочих мест» из него. Каждая работа должна содержать небольшую, но не слишком маленькую «единицу работы». Вставьте эти в очередь. Следующий поток (и) ждет заданий в очереди и делает вычисления. Это может произойти, когда потоки на шаге # 1 ждут , чтобы медленный жесткий диск возвращал новые строки данных. Результат этот шаг преобразования переходит в следующую очередь. Один или несколько потоков для загружают данные через JDBC. Первый и последний потоки довольно медленный, потому что они связаны с I/O (жесткие диски медленные, а сетевые соединения еще хуже). Плюс вставка данных в базе данных является очень сложная задача (выделение пространства, обновления индексов, проверка внешних ключей)

Использования различных рабочих потоков дает много преимуществ:

Это легко проверить каждую нить отдельно. Поскольку они не делят данные, вам не нужна синхронизация. Очереди будут делать это для вас Вы можете быстро изменить количество потоков для каждого шага, чтобы настроить производительности

+0

Спасибо @ Rafik991, это изменит мою концепцию, для лучшей производительности я надеюсь. – AdrianES

+0

приветствуется :) – RMachnik

+0

Пожалуйста, отметьте этот ответ как принято заблаговременно! – RMachnik

1

Я думаю, что самое легкое решение - отметить все ваши методы, используя ресурс «соединение» с синхронизированным флагом. http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

Например:

Class YourClass 
{ 
    public synchronized boolean reconect(...) { ...} 
    public synchronized String getData (...) {...} 
} 

Это блокирует этот объект для помеченных методов, так что вы должны инкапсулировать соединение в малом классе, как это или просто заблокировать объект подключения: http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

Class YourClass 
{ 
    public boolean reconect(...) { 
    synchronized(con) 
    { 
    ... 
    } 
    } 

    public String getData (...) { 
    synchronized(con) 
    { 
    ... 
    } 
    } 
    private Connection con; 
} 

Данные синхронизированы зон никогда не будет r un в то же время.

EDIT: Учитывая вы хотите защитить переподключение против других БД операций, вы должны рассмотреть вопрос об использовании семафора: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html

Class YourClass 
{ 
    YourClass() { 
    sem = new Semaphore(1); 
    } 

    public boolean reconect(...) { 
    sem.acquire(); 
    ... 
    sem.release(); 
    } 

    public String getData (...) { 
    synchronized(sem) 
    { 
     if(sem.availablePermits()>0) sem.reducePermits(1); 
    } 
    ... 
    ... 
    synchronized(sem) 
    { 
     sem.release(); 
    } 
    } 
    private Connection con; 
    Semaphore sem; 
} 
+0

Это просто я согласен :) но если поток хочет использовать метод GetData() (в вашем случае), а другой поток использует его (а не метод повторного подключения), он будет ждать, пока другой поток не отпустит блокировку (синхронизирован). Поправьте меня, если я понял что-то не так. – AdrianES

+0

@AdrianES Вы правы, но я не думаю, что это такое плохое поведение в вашем коде. Если вы хотите избежать повторного подключения и «других методов» для запуска в одно и то же время, вы можете защитить Integer (счетчик) с помощью операций инкремента, декремента и получения (используя второй механизм, описанный выше), только разблокировать запросчик acquisituin, когда этот счетчик 0 ... как семафор –

+0

Можете ли вы изменить свой код и показать мне, как вы можете использовать этот счетчик? Я также думаю, что я должен объединить два механизма параллелизма, чтобы получить то, что мне нужно. – AdrianES

Смежные вопросы