Назад к вопросам
Senior
3
Прочитайте код и подсветите ошибки @Component public class AuthorSearchService { @Autowired private AuthorsRepository authorsRepository; @Autowired private StatisticsRepository statisticsRepository; private AlertRestClient arc = new AlertRestClient(); // В query может быть как полностью ФИО, так и часть имени, например "Вадим Панов" или "панов" @Transactional public List<Author> search(String query) { List<Author> authors = authorsRepository.findByNameContainingIgnoreCase(query); Statistics s = statisticsRepository.findById(query).orElse(null); if (s == null) s = new Statistics(query); s.setNumbers(s.getNumbers() + 1); statisticsRepository.save(s); if (s.getNumbers() > 1000 && authors.size() > 1000) { System.out.println("too popular search with too much data, sending an alert..."); arc.send(query, s.getNumbers(), authors.size()); } return authors; } } @Entity @Data public class Author { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "author") private List<Book> books; public Author(String name) { this.name = name; } }
Компании, где спрашивали
ТБанк
Ответ от нейросети
sobes.tech AI
В представленном коде есть несколько проблем и потенциальных улучшений:
-
Инициализация AlertRestClient
AlertRestClient arc = new AlertRestClient();создаётся вручную, а не через Spring. Лучше внедрять через@Autowiredили конструктор, чтобы использовать преимущества DI и облегчить тестирование.
-
Отсутствие конструктора без параметров в Author
- В JPA сущности должен быть публичный или защищённый конструктор без параметров. В классе
Authorесть только конструктор с параметромname, что может привести к ошибкам при загрузке из базы.
- В JPA сущности должен быть публичный или защищённый конструктор без параметров. В классе
-
Потенциальная проблема с транзакционностью и конкурентностью
- Метод
searchпомечен@Transactional, но при обновлении статистики:Если несколько потоков одновременно выполняют этот код с одним и тем жеStatistics s = statisticsRepository.findById(query).orElse(null); if (s == null) s = new Statistics(query); s.setNumbers(s.getNumbers() + 1); statisticsRepository.save(s);query, может возникнуть состояние гонки, и счётчикnumbersбудет некорректным. Лучше использовать атомарные операции или блокировки.
- Метод
-
Использование
findById(query)для Statistics- Предполагается, что
query— это строка, аfindByIdобычно ищет по первичному ключу. Еслиqueryне является ID, это может быть ошибкой. Нужно проверить, чтоStatisticsдействительно используетqueryкак ID.
- Предполагается, что
-
Отсутствие проверки на null у
authors- Метод
findByNameContainingIgnoreCaseдолжен возвращать список, но если вдруг вернёт null, последующие вызовы вызовут NPE. Лучше использовать Optional или проверять на null.
- Метод
-
Логирование через System.out.println
- Для продакшн-кода лучше использовать логгер (например, SLF4J), а не
System.out.println.
- Для продакшн-кода лучше использовать логгер (например, SLF4J), а не
-
Отсутствие аннотации @NoArgsConstructor в Author
- Если используется Lombok, стоит добавить
@NoArgsConstructorдля JPA.
- Если используется Lombok, стоит добавить
Пример исправления и улучшения инициализации AlertRestClient:
@Component
public class AuthorSearchService {
@Autowired
private AuthorsRepository authorsRepository;
@Autowired
private StatisticsRepository statisticsRepository;
@Autowired
private AlertRestClient arc;
@Transactional
public List<Author> search(String query) {
List<Author> authors = authorsRepository.findByNameContainingIgnoreCase(query);
Statistics s = statisticsRepository.findById(query).orElse(null);
if (s == null) s = new Statistics(query);
s.setNumbers(s.getNumbers() + 1);
statisticsRepository.save(s);
if (s.getNumbers() > 1000 && authors.size() > 1000) {
// Использовать логгер
System.out.println("too popular search with too much data, sending an alert...");
arc.send(query, s.getNumbers(), authors.size());
}
return authors;
}
}
@Entity
@Data
@NoArgsConstructor
public class Author {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "author")
private List<Book> books;
public Author(String name) {
this.name = name;
}
}
Также стоит рассмотреть использование оптимистической блокировки или атомарных запросов для обновления статистики.