Primary Key (первичный ключ) в базах данных относится к категории ограничений (constraints). Это специальное ограничение, которое накладывается на столбец или группу столбцов таблицы, чтобы однозначно идентифицировать каждую строку (запись) в таблице.
Значение первичного ключа должно быть уникальным для каждой строки. Это исключает дублирование записей.
Столбец (или столбцы), определённый как Primary Key, не допускает значения NULL, так как NULL не может однозначно идентифицировать строку.
Таблица может иметь только один первичный ключ, но он может состоять из одного столбца (простой ключ) или нескольких (составной ключ).
Для однозначной идентификации записей в таблице.
Для создания связей между таблицами в реляционных базах данных (внешние ключи ссылаются на первичный ключ другой таблицы).
Для ускорения поиска и манипуляций с данными за счёт создания индекса на столбец первичного ключа.
Простой первичный ключ
CREATE TABLE Users (
user_id INT PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100)
);
Составной первичный ключ
CREATE TABLE Orders (
order_id INT,
product_id INT,
PRIMARY KEY (order_id, product_id)
);
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥2
- Атомарность — операция либо выполняется целиком, либо не выполняется вовсе. Это неделимая единица работы.
- Консистентность — после выполнения операции, данные остаются в допустимом, согласованном состоянии.
Пример: перевод денег между счетами — списание и зачисление должны произойти вместе (атомарность), и общий баланс не должен нарушиться (консистентность).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥5💊1
Веб-приложение на Java – это серверное приложение, которое обрабатывает HTTP-запросы и отправляет ответы клиенту.
Установка зависимостей (Maven)
Создайте
pom.xml и добавьте<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.2</version> <!-- Используйте актуальную версию -->
</dependency>
</dependencies>
Создание основного класса (точка входа)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyWebApp {
public static void main(String[] args) {
SpringApplication.run(MyWebApp.class, args);
}
}
Создание контроллера (обработка HTTP-запросов)**
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class MyController {
@GetMapping("/hello")
public String sayHello() {
return "Привет, это веб-приложение на Java!";
}
}
Теперь при открытии
http://localhost:8080/api/hello сервер вернёт: Привет, это веб-приложение на Java!
Если приложение рендерит страницы на сервере, используйте Thymeleaf.
Добавьте зависимость в
pom.xml<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Создайте HTML-шаблон (
src/main/resources/templates/index.html)<!DOCTYPE html>
<html>
<head>
<noscript>Главная страница</noscript>
</head>
<body>
<h1>Привет, <span th:text="${name}"></span>!</h1>
</body>
</html>
Создайте контроллер для отображения страницы
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class WebController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("name", "Гость");
return "index"; // Возвращает "index.html"
}
}
Добавьте зависимости в
pom.xml<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
Настройте
application.properties (подключение к БД)spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=postgres
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=update
Создайте сущность (таблицу в БД)
import jakarta.persistence.*;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Геттеры и сеттеры
}
Создайте
Repository для работы с БДimport org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
Контроллер для работы с БД
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping
public List<User> getUsers() {
return userRepository.findAll();
}
@PostMapping
public User addUser(@RequestBody User user) {
return userRepository.save(user);
}
}
Запустите приложение:
mvn spring-boot:run
Проверьте API через браузер или Postman
http://localhost:8080/users
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Локальный класс — это класс, определённый внутри метода или блока кода. Его особенности:
- Видим и доступен только внутри области, где объявлен.
- Может обращаться к финальным или эффективно финальным переменным метода.
- Часто используется для вспомогательной логики, ограниченной контекстом метода.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3
Пул строк в Java не является пустым при старте JAR файла. Он изначально содержит несколько предопределенных строковых литералов, которые JVM использует для своей внутренней работы, а также строковые литералы, используемые в загруженных классах и стандартных библиотеках.
JVM и стандартные библиотеки Java используют различные строковые литералы для своей работы. Эти строки добавляются в пул строк при запуске JVM. Примеры таких строк включают имена основных классов и пакетов (например,
"java/lang/Object", "java/lang/String").Когда классы загружаются JVM, все строковые литералы, используемые в этих классах, добавляются в пул строк. Это включает строки, используемые в JAR файле, а также строки из стандартных библиотек Java, которые загружаются при старте.
Для демонстрации этого можно написать простой код, который проверяет, присутствуют ли определенные строки в пуле строк при старте программы.
public class StringPoolDemo {
public static void main(String[] args) {
// Проверка стандартных строк, которые могут быть в пуле строк
String str1 = "java";
String str2 = "lang";
String str3 = "Object";
// Вывод строк
System.out.println("str1: " + str1);
System.out.println("str2: " + str2);
System.out.println("str3: " + str3);
// Проверка строк в пуле строк
System.out.println("Is 'java' in pool: " + (str1 == "java"));
System.out.println("Is 'lang' in pool: " + (str2 == "lang"));
System.out.println("Is 'Object' in pool: " + (str3 == "Object"));
}
}При запуске JVM загружаются системные классы, такие как
java.lang.Object, java.lang.String, java.lang.System, и другие. Строковые литералы, используемые в этих классах, добавляются в пул строк.Когда JVM загружает пользовательские классы из JAR файла, все строковые литералы в этих классах также добавляются в пул строк.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🤔1
Только при равномерном распределении хешей — да, O(1).
Если ключи имеют коллизии, и корзины переполнены — время может увеличиться до O(log n) (в случае использования TreeNodes) или O(n) (в старых версиях).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Конструкция
finally в Java используется для гарантированного выполнения кода, независимо от того, произошло исключение или нет. Обычно применяется для освобождения ресурсов, таких как закрытие файлов, соединений с базой данных или потоков. try {
// Код, который может выбросить исключение
} catch (Exception e) {
// Обработка исключения
} finally {
// Этот блок выполнится всегда
}Пример
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("file.txt");
System.out.println(fileInputStream.read());
} catch (IOException e) {
System.out.println("Ошибка: " + e.getMessage());
} finally {
if (fileInputStream != null) {
fileInputStream.close(); // Всегда закрываем файл
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
TCP — это протокол с установлением соединения, обеспечивающий надежную доставку данных. UDP — это протокол без соединения, работающий быстрее, но без гарантий доставки или порядка следования пакетов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥1
В тестировании разница между Stub и Mock заключается в их предназначении и способе использования.
Stub – это простейший объект-заглушка, который возвращает заранее заданные данные. Он не проверяет, какие методы были вызваны, а просто отвечает на запросы.
class UserRepositoryStub implements UserRepository {
@Override
public User findById(Long id) {
return new User(id, "Иван"); // Просто возвращает статичные данные
}
}Mock – это объект, который имитирует поведение реального объекта и позволяет проверять вызовы методов (сколько раз был вызван, с какими аргументами и т. д.).
UserRepository userRepository = mock(UserRepository.class);
when(userRepository.findById(1L)).thenReturn(new User(1L, "Иван"));
User user = userRepository.findById(1L);
verify(userRepository, times(1)).findById(1L); // Проверяем, что метод был вызван 1 раз
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Полный синтаксис SELECT включает:
SELECT [DISTINCT] поля FROM таблицы [JOIN] [WHERE условия] [GROUP BY] [HAVING] [ORDER BY] [LIMIT/OFFSET].
Это мощный оператор, который позволяет извлекать, фильтровать, сортировать и агрегировать данные.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥4
Garbage Collector (GC) в Java начинает сборку мусора, когда объекты в памяти больше не используются и не имеют активных ссылок.
GC понимает, что объект можно удалить, если на него больше не ссылается ни одна переменная или он стал недостижимым.
class Demo {
int value;
}
public class Main {
public static void main(String[] args) {
Demo obj = new Demo(); // Создан объект в памяти (Heap)
obj = null; // Теперь на него нет ссылки → GC его удалит
}
}Если в куче (Heap) осталось мало свободной памяти, JVM может запустить GC.
GC в Java автоматический, и его запуск зависит от алгоритма сборщика мусора. Некоторые из них:
Serial GC (для маленьких программ)
Parallel GC (по умолчанию в Java 8)
G1 GC (по умолчанию в Java 11+)
ZGC, Shenandoah GC (для высоконагруженных систем)
Устарело, потому что не умеет работать с циклическими ссылками.
Основной метод, который использует GC в Java.
GC начинает с корневых объектов (GC Roots) и проверяет, какие объекты достижимы.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
- Ослабляет связанность кода (low coupling);
- Повышает тестируемость кода (легко внедрять моки);
- Упрощает сопровождение и масштабирование приложений.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍1
Когда вы переопределяете методы
equals() и hashCode(), важно соблюдать контракт, иначе объект может вести себя некорректно в коллекциях (HashMap, HashSet и др.). Метод
equals() определяет, когда два объекта равны. Рефлексивность –
x.equals(x) всегда true. Симметричность –
x.equals(y) == y.equals(x). Транзитивность – если
x.equals(y) и y.equals(z), то x.equals(z). Согласованность – многократные вызовы
x.equals(y) дают один и тот же результат. Сравнение с
null всегда false – x.equals(null) == false. class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // Проверка на одинаковые ссылки
if (obj == null || getClass() != obj.getClass()) return false; // Проверка типа
Person person = (Person) obj;
return age == person.age && name.equals(person.name); // Сравнение полей
}
}Метод
hashCode() возвращает числовой хеш-код объекта. Он должен соответствовать equals()! Если
x.equals(y) == true, то x.hashCode() == y.hashCode(). Если
x.hashCode() != y.hashCode(), то x.equals(y) == false (но обратное не всегда верно). Хеш-код должен оставаться неизменным, если объект не изменяется.
@Override
public int hashCode() {
return Objects.hash(name, age);
}
В коллекциях, таких как
HashSet, HashMap, HashTable, объекты хранятся по хеш-коду. Что будет, если
equals() переопределён, но hashCode() – нет? Set<Person> people = new HashSet<>();
people.add(new Person("Иван", 25));
people.add(new Person("Иван", 25)); // Ожидаем, что не добавится
System.out.println(people.size()); // ❌ Будет 2, а не 1, если `hashCode()` отсутствует!
Правильный вариант (
equals() + hashCode()) class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥2
Среди основных протоколов: TCP, UDP, FTP, HTTP, HTTPS, SMTP, POP3, IMAP, SSH и другие.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥2🤔1
Шардирование – это метод горизонтального разделения базы данных на несколько частей (шардов) для повышения производительности и масштабируемости.
Данные делятся по диапазону значений (например,
ID 1–1000, 1001–2000). Данные распределяются с помощью хеш-функции.
int shardNumber = userId % numberOfShards;
Данные разделяются по географическому признаку (например, Европа, Азия, США). Минимальная задержка (пользователь получает данные ближе к себе)
Некоторые регионы могут перегружаться.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
В Java напрямую нельзя узнать, удерживает ли поток монитор объекта. Можно использовать средства профилирования (например, VisualVM, jstack) или синхронизацию состояния вручную.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍3
Это два интерфейса в JDBC, которые используются для выполнения SQL-запросов к базе данных. Основные различия между ними касаются производительности, безопасности и удобства использования.
Statement используется для выполнения простых SQL-запросов. Запросы формируются и передаются в базу данных в виде строки. Подходит для простых запросов. Не оптимизирован для повторного выполнения. Каждый раз, когда запрос передается в базу данных, он компилируется и выполняется заново. Уязвим к SQL-инъекциям. Поскольку запрос формируется путем конкатенации строк, злоумышленники могут внедрять вредоносный SQL-код.
Statement stmt = connection.createStatement();
String query = "SELECT * FROM employees WHERE department = 'HR'";
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println("ID: " + id + ", Name: " + name);
}
stmt.close();
PreparedStatement используется для выполнения предварительно скомпилированных SQL-запросов. Это позволяет повысить производительность и безопасность. Оптимизирован для повторного выполнения. Запрос компилируется только один раз, а затем может многократно выполняться с разными параметрами, что повышает производительность. Защита от SQL-инъекций. Использует параметризованные запросы, которые помогают избежать уязвимостей, связанных с SQL-инъекциями. Удобство работы с параметрами. Позволяет устанавливать значения параметров с использованием методов setInt(), setString() и других.
String query = "SELECT * FROM employees WHERE department = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, "HR");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println("ID: " + id + ", Name: " + name);
}
pstmt.close();
Statement: Каждый запрос компилируется заново, что снижает производительность при многократном выполнении одного и того же запроса.PreparedStatement: Запрос компилируется один раз и может многократно выполняться с разными параметрами, что повышает производительность.Statement: Уязвим к SQL-инъекциям, поскольку запросы формируются путем конкатенации строк.PreparedStatement: Использует параметризованные запросы, что защищает от SQL-инъекций.Statement: Подходит для простых, одноразовых запросов.PreparedStatement: Удобен для многократного выполнения запросов с разными параметрами.Оба интерфейса могут выполнять запросы типа
SELECT, INSERT, UPDATE, DELETE, но PreparedStatement более удобен для запросов с параметрами.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
TreeSet основан на Red-Black Tree (красно-чёрное дерево) — это самобалансирующееся двоичное дерево поиска, обеспечивающее логарифмическую сложность операций.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥1
Функциональный интерфейс —это интерфейс, который содержит только один абстрактный метод. Это позволяет использовать лямбда-выражения для создания его анонимных реализаций, делая код более лаконичным и читаемым. Функциональные интерфейсы являются основой для лямбда-выражений и методов ссылок, начиная с версии 8.
Примером этого может служить интерфейс
java.util.function.Predicate<T> который принимает объект типа T и возвращает значение типа boolean. Вот пример использования:Predicate<String> isNotEmpty = s -> !s.isEmpty();
System.out.println(isNotEmpty.test("Hello")); // Выведет true
System.out.println(isNotEmpty.test("")); // Выведет falseЧтобы явно указать, что интерфейс предназначен для использования как функциональный, используется аннотация
@FunctionalInterface. Эта аннотация не обязательна (компилятор может определить функциональный интерфейс и без неё), но она помогает в документировании кода и обеспечивает проверку времени компиляции, гарантируя, что интерфейс содержит только один абстрактный метод.@FunctionalInterface
public interface SimpleFunction {
int apply(int value);
}
// Использование
SimpleFunction triple = value -> value * 3;
System.out.println(triple.apply(5)); // Выведет 15Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Нет, понижать нельзя. При переопределении метода в наследнике доступность можно только сохранять или повышать, но не ограничивать.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥4
HQL (Hibernate Query Language) – это язык запросов, используемый в Hibernate (фреймворке для работы с базами данных в Java), который похож на SQL, но оперирует не таблицами и столбцами, а объектами и их свойствами.
Когда мы работаем с базами данных в Hibernate, мы используем объектно-реляционное отображение (ORM), где каждая таблица представляется как класс, а строки – как объекты. Однако иногда нам нужно делать запросы к базе данных, например:
Получить список объектов, соответствующих определённому критерию
Отфильтровать, отсортировать или объединить данные
Выполнить массовое обновление или удаление
Можно, конечно, использовать чистый SQL, но тогда мы потеряем преимущества ORM, такие как переносимость кода между разными базами данных. HQL решает эту проблему, позволяя писать запросы в объектных терминах, а Hibernate сам преобразует их в правильный SQL для конкретной базы данных.
HQL очень похож на SQL, но вместо таблиц и столбцов мы используем имена классов и их полей.
Допустим, у нас есть класс User, связанный с таблицей users:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age;
// Геттеры и сеттеры
}
Теперь напишем HQL-запрос, чтобы получить всех пользователей старше 18 ле
String hql = "FROM User WHERE age > 18";
List<User> users = session.createQuery(hql, User.class).getResultList();
Выборка только имен пользователей
String hql = "SELECT u.name FROM User u";
List<String> names = session.createQuery(hql, String.class).getResultList();
Запрос с параметрами (предотвращает SQL-инъекции)
String hql = "FROM User WHERE name = :name";
Query<User> query = session.createQuery(hql, User.class);
query.setParameter("name", "Иван");
List<User> users = query.getResultList();
HQL автоматически адаптируется под MySQL, PostgreSQL, Oracle и другие базы.
вместо таблиц и столбцов мы работаем с сущностями (классами Java).
использование параметров (
setParameter()) предотвращает SQL-инъекции. поддержка JOIN, GROUP BY, ORDER BY и других SQL-конструкций.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1