Функции кеширования в Java?

У меня есть проект Spring / Java, в котором я думаю о кэшировании некоторых функций, которые обращаются к базам данных и другим сервисам отдыха. Я не уверен, в какой момент следует кэшировать определенный поток. Например, если у меня есть следующие функции:

public List<String> getSchools()
{
     //call db to get names
}

public List<String> getCourses(String school)
{
    //rest call to get courses for a school
}

public List<String> getTeachers(String course)
{
    //call db to get teacher names for a course
}

/*Uses above three functions together*/
public List<String> getAllTeachers()
{
      List<String> schools = getSchools();
      List<String> courses = new ArrayList<String>();
      List<String> teachers = new ArrayList<String>();

      for(String s : schools)
          courses.addAll( getCourses( s ) );
      for(String c : courses)
         teachers.addAll( getTeachers( s ) );

     return teachers;
}

Какие методы я должен кэшировать? Должен ли я кэшировать функцию, которая вызывает другие 3 ресурсоемкие функции, или я должен кэшировать три функции по отдельности? Что обычно считается хорошей практикой?

Вы не можете использовать addAll(), потому что у вас будут дублирующиеся записи, если один учитель ведет более одного курса. То же самое и с курсами (getCourses()), если они имеют одинаковое название в разных школах.

Alan Deep 17.04.2018 03:39

Возможно, вы захотите использовать вместо этого HashSet или TreeSet.

Alan Deep 17.04.2018 03:41

@AlanDeep Вы правы ... но я просто набрал это в качестве примера. Меня больше всего беспокоит то, где использовать абстракцию кеширования Spring ....

oneCoderToRuleThemAll 17.04.2018 03:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
2 592
2

Ответы 2

Кэширование обычно используется с данными, которые не часто меняются.
Таким образом, решение о том, следует ли кэшировать результаты отдельных методов или getAllTeachers(), зависит от того, как часто меняются данные, относящиеся к учителям / курсам / школе.

Я бы предложил кэшировать результаты отдельной функции (чем другая, которая вызывает 3 метода) и иметь временной интервал, после которого, когда выполняется вызов этой отдельной функции, она отбрасывает старые данные и повторно инициализирует себя с помощью последние данные из db.
Например, если временной интервал составляет 10 минут, то через каждые 10 минут вызов этих функций будет возвращать последние данные.

    private Map<String,Integer> funcCalls;
    private Map<String,List<String>> funcResultCache;
    long timeGap= 600000;//10 mins
    public List<String> getSchools()
    {
       if (funcCalls.get("getSchools")-currentTimeInMills >=timeGap) {
       //call db to get names
       } else {
          funcResultCache.get("getSchools");
       }
    }


Одним из недостатков этого подхода является то, что пользователи могут получить устаревшие данные, если данные будут изменены на 2nd минуте, но это отразится только через 10 минут.
Промежуток времени можно сократить, чтобы уменьшить этот побочный эффект.

Есть еще один способ, возможно, немного громоздкий. Предполагая, что вызовы базы данных собираются получить огромное количество данных, тогда
1) Иметь триггеры в таблицах для операторов типа DML (создание / обновление / удаление), которые будут записывать время в миллисекундах в другую таблицу (скажем, trans_tbl).
2) Сначала сохраните данные trans_tbl.
3) Перед каждым вызовом DB для получения фактических данных проверяйте trans_tbl и проверяйте, больше ли полученное ранее время, чем у вас есть. Если «да» сохранить последнее время, а затем запустить запрос для получения данных из БД. Кешируйте результаты и возвращайте то же самое.

Еще один аспект, который вы можете изучить, - это проверить, может ли база данных, которую вы используете, кэшировать запросы «выбора». Если «да», то это будет более простой подход, потому что никаких изменений кода не требуется, достаточно просто настроить вашу БД для кеширования выбранных запросов.

Что касается этот пример, я бы никогда не стал рассматривать кеширование, потому что данные меняются нечасто.

Однако я бы сделал следующее: В первый раз, когда я запускаю программу, она должна получить все, что ей нужно, и поместить некоторую переменную с именем (changed) в базу данных и присвоить ей значение 0. На стороне сервера, когда я что-то вставляю, обновляю или удаляю, я меняю этот changed. значение 1. В следующий раз, когда я запускаю приложение, оно получит значение changed, если оно равно 1, тогда оно получит «новую» информацию из БД, а затем вернет ей значение 0. Если значение changed уже было 0, оно будет просто использовать результаты кеширования.

Учтите, что ваш вопрос сложный. Потому что, если вы загружаете в память только учителей, школы и курсы и хотите получить, например, список учеников, которые только что выпали из курса (это просто пример), вам решать, загружать ли учеников. в памяти или сохранить в базе данных.

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

Последнее: чтобы избежать состояния гонки, вы можете рассмотреть возможность обновления значения до нуля внутри запроса выбора. Не ждите, пока вы закончите свою работу, потому что вы хотите рассмотреть других пользователей, использующих приложение. Убедитесь, что значение changed находится в таблице, а не в файле, имея InnoDB в качестве механизма хранения, потому что InnoDB блокируется по строке, а не по таблице.

Другие вопросы по теме