2012-02-25 3 views
3

Я пишу сервлет, который обрабатывает каждый запрос, обращаясь и изменяя некоторые таблицы (таблицы) в базе данных. Я хочу, чтобы соединения с базой данных были потокобезопасными. Я не хочу использовать уже существующие библиотеки/рамки для этого (весна, спящий режим и т. Д.).Java-соединения, связанные с безопасностью базы данных

Я знаю, что могу использовать ThreadLocal Java для этого следующим образом:

public class DatabaseRegistry { //assume it's a singleton 


private Properties prop = new Properties(); 
    public static final ThreadLocal<Connection> threadConnection = new ThreadLocal<Connection>(); 

    private Connection connect() throws SQLException { 
     try { 
      // This will load the MySQL driver, each DB has its own driver 
      Class.forName("com.mysql.jdbc.Driver"); 
      // Setup the connection with the DB 
      Connection connection = DriverManager 
        .getConnection("jdbc:mysql://" + prop.getProperty("hostname") + "/" + prop.getProperty("database") + "?" 
          + "user=" + prop.getProperty("username") + "&password=" + prop.getProperty("password")); 
      return connection; 
     } catch (SQLException e) {   
      throw e; 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } 

     return null; 

    } 

    public Connection getConnection() throws SQLException { 

     if(threadConnection.get() == null) { 
      Connection connection = connect(); 
      threadConnection.set(connection); 
      return threadConnection.get(); 
     } else 
      return threadConnection.get(); 
    } 

    private void freeConnection(Connection connection) throws SQLException { 
     connection.close(); 
     threadConnection.remove(); 
    } 
} 

Каждый раз, когда вы звоните GetConnection, новое соединение добавляется в ThreadLocal объект, а затем удаляется, когда вы освобождаете соединение() ,

Правильно ли это делается или должен ли DatabaseRegistry распространять класс ThreadLocal? Или есть еще лучший способ сделать это, чтобы все потоки соединений были безопасными?

Благодаря

+0

http://stackoverflow.com/questions/1209693/is-mysql-connector-jdbc-thread-safe –

+0

Я думаю, что это не очень хорошая практика. используйте пул соединений, он будет оставаться основным размером доступных подключений. Если вы используете ThreadLocal, каждый запрос будет собственным одним подключением, если ваш веб-сервер является блоком, соединение не будет запускаться вовремя. –

ответ

2

Я не думаю, что создание соединений с базами данных потокобезопасными является обычной практикой. Обычно то, что вы хотите, или:

  • Serialize доступ к некоторой части вашего сервлета, так что не более чем один сервлет выполнения кода в то время (бывший реализующий интерфейс SingleThreadModel).
  • Блокировка конкретной таблицы/таблицы/строки, чтобы вы могли работать с определенными кортежами (путем изменения уровня изоляции базы данных).
  • Использование оптимистической блокировки для обнаружения измененных строк в таблице (с использованием некоторого ссылочного атрибута таблицы, чтобы проверить, совпадает ли текущая версия с той, которая находится в таблице).

AFAIK, типичное использование ThreadLocal - это сохранение уникального соединения с базой данных для каждого потока, так что одно и то же соединение может использоваться различными способами в вашей бизнес-логике без необходимости передавать его как параметр каждый раз. Поскольку обычная реализация контейнера сервлетов использует поток для полного HTTP-запроса, тогда два разных запроса гарантируют использование двух разных соединений с базой данных.

+0

Ваш последний комментарий здесь. Я использую соединение по одному запросу. Каждый запрос может проходить через многие вызовы функций, требующих подключения. Например, я буду использовать идентификатор, переданный в URL-адресе, чтобы найти объект домена в базе данных через класс Finder. Затем я отредактирую объект и обновляю его в базе данных через какой-либо другой класс. Хотя я каждый раз закрываю свои результирующие наборы, я хочу, чтобы соединение было таким же. –

+0

Я все еще думаю, что это изобретает колесо. Если вы собираетесь запускать сервлет в контейнере (например, Tomcat), используйте JNDI для поиска источника данных и настройте источник данных для объединения соединений для вас. Есть много примеров. – dbrin

+0

Не то, что sql DriverManager делает, когда вы делаете getConnection(); –

0

Я не знаю, почему вы хотите, чтобы ваши соединения DB быть поточно. Большая часть времени установления соединения с базой данных является самой длинной частью транзакции. Обычно соединения повторно используются между запросами и пулами открытых подключений управляются (через фреймворки или, более типично, серверы приложений).

Если вы беспокоитесь о параллельных изменениях в одних и те же таблицы, вы можете захотеть взглянуть на синхронизированных методах: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

+1

-1, используя синхронизацию Java для защиты транзакций базы данных от столкновения, является ** ужасной ** идеей –

+0

Я бы не делал этого в обычном приложении, но похоже, что это какой-то небольшой проект, где он хочет не использовать фреймворки и не хочет управлять пулом соединений внутри. В этом случае это не плохая идея.Да, вы собираетесь ждать других запросов, но это делает грязную работу. – dbrin

+0

Выполнение этого «правильного пути» на самом деле не намного сложнее, и это учит ужасным привычкам. Он также оставляет огромное количество кодовых долгов, что делает невозможным расширение сферы применения приложения по дороге. –

2

Я знаю, что вы сказали, что не хотите использовать библиотеки, чтобы сделать это, но если вы сделаете это, вы будете лучше. Выберите стандартный пул соединений (C3P0, DBCP или что-то еще), и вы станете счастливее, чем если будете испечь свои собственные. Почему вы не можете использовать библиотеку для этого?

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