vusalg
@vusalg
Студент программист, второй курс

Лучше хранить результаты запроса в оперативной памяти, или каждый раз заново делать запрос к БД?

Добрый день!
В связи с отсутствием опыта, столкнулся со следующей проблемой: не знаю, как работать с данными из БД. Оставлять их во временной памяти, или освобождать и заново делать запрос к БД, когда возникнет необходимость в этих данных?
Пишу курсовую работу по БД. Использую Java, JDBC, PostgreSQL + JavaFX для графического интерфейса.
Существует сущность "Поставщик", которая имеет свой "Каталог" поставляемых товаров(связь 1:M).
На данный момент сделано так:
Когда программе надо вывести на экран список поставщиков, вызывается метод класса синглетон следующего вида:
public List<Supplier> getSupplierList() {
        if (null == supplierList) {
                supplierList = SupplierTransaction.loadAllSuppliers();
        }
        return supplierList;
    }

После этого данные о поставщиках хранятся до конца работы программы.
Когда необходимо вывести на экран каталог поставщика, используется следующая функция класса Supplier("Поставщик"):

public List<Catalog> getCatalog() {
        if (null == catalog) {
            phoneList = SupplierTransaction.getSupplierCatalog(id);
        }
        return catalog;
    }


Таким образом загрузка данных из базы данных происходит лишь единожды. С одной стороны это хорошо: при повторном обращении мы получаем данные быстрее, но с другой стороны, количество памяти, которую занимает программа с каждым разом растет.

Я привел лишь два примера, подобная реализация присутствует и в остальных частях программы.
Как поступить лучше? Каждый раз делать заново запросы? Оставить как есть? Или же как то скомбинировать эти две реализации?

Спасибо!
  • Вопрос задан
  • 1336 просмотров
Решения вопроса 2
gbg
@gbg
Любые ответы на любые вопросы
Зависит от многих условий. Однако, учтите, что:
1. Запрос к базе дороже по ресурсам, чем собственная память. Памяти у вас на хосте обычно гигабайты, плюс локальный SWAP. Частые же запросы к базе создают на нее нагрузку и конкурируют с другими запросами.
2. Доступ к собственной памяти во много-много-много раз быстрее доступа по сети.

Отсюда вывод - кэширование необходимо и вы все делаете правильно.

Для того, чтобы не съедать ВСЮ память, нужно ограничиться определенным (настраиваемым!) объемом, при выходе за который самые старые данные (к которым давно не было обращений) из кэша удалять.

Чтобы не получить ситуацию, когда в базе данные поменялись, а вы об этом ничего не знаете, воспользуйтесь pg_notify
Ответ написан
Комментировать
@red-barbarian
для начала, есть части системы
Вьюхи
Контроллеры
Бизнеслогика (какая-никакая)
База данных.
По теме: жесткая связь бизнес логики и базы данных всегда чревато. Желательно разделить их прослойкой. Например неким репозиторием. Объект(ы) который будет давать те данные которые нужны.

Далее. Для вьюх в FX нужны ObservableList. Это листы и Observable. Т.е. с наименьшими затратами по работе. Мы будем работать с листами в памяти. Такую модель и строим.
В прикидку приложение fx занимает 40мб. Ну база для примера столько же. Вполне нормально.

Далее. Если база меняется. Мы меняем только репозиторий и то что относиться к базе. Логика и вьюхи не меняется.
Если база настолько огромная что не помещается. То мы делаем свой класс с интерфейсом interface ObservableList extends java.util.List, Observable. Который будет динамически лазить в базу.
Или меняем представление так, что бы работать с кусками данных, а не с целыми таблицами.

Т.е. прослойка позволяет отложить вопрос об эффективности использовании памяти на потом. С минимальными затратами.

Касаемо вопроса как читать, как писать. Если арм не многопользовательский, то чтение часто и не нужно. если работают много человек, то критические места нужно перечитывать. (например данные перед редактированием обязательно) ну и блокировку какую-то ставить про редактировании.
запись желательно сразу. большой нагрузки это не даст. но данные будут в сохранности. Если процессы, и нагрузка большая, нужно думать конкретно. Опять же если система будет на деле тормозить, а не в теории.
Примерно так.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@d-stream
Готовые решения - не подаю, но...
Для курсовой - без разницы.
Для реальных решений - все конечно зависит от специфики, но как моментик: если БД - это нечто распределенное, да и приложение живет в виде множества экземпляров, то при промежуточном хранении/кэшировании данных в памяти экземпляра приложения - может оказаться источником проблем.
Ибо в остальных экземплярах - этих данных еще не будет.

Ну и с учетом, что механизмы БД так или иначе но кэшируют - все вышеописанное может оказаться осмысленным только для очень специфических случаев.
Ответ написан
Комментировать
@Che_Bu_Rashka
Немного из другой области (Java EE), но вдруг пригодиться
public static List<Order> getOrders() throws SQLException, ... {
  List<Order> result = new ArrayList<>();  
  InitialContext initContext = new InitialContext();
  DataSource ds = (DataSource) initContext.lookup("jdbc/ИМЯ_РЕСУРСА");
  try (Connection conn = ds.getConnection()) {
      Statement stm = conn.createStatement();
      ResultSet res = stm.executeQuery(" SELECT * FROM  `orders` бла-бла-бла ;");
      //кешируем запрос
      CachedRowSet crs = new com.sun.rowset.CachedRowSetImpl();
      crs.populate(res);
      //работаем с ним
      if (crs.size() > 0) {
          crs.first();
          do {
                String id = crs.getString("id");
                String number = crs.getString("number");
                //формирование результ.Объекта
                result.add(new Order(id, number));
          } while (crs.next());
          countRows = result.size();  //сохраним колво
      }
   } //try
  return result;
}

После ресурсы подключения к БД автоматически закрываются.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы