기술나눔

스레드 풀 작업 데이터베이스에 스레드 안전 문제가 있습니다.

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

목차

1. 소개

2. 질문

3. 솔루션

3.1. 방법 1: 데이터베이스 제약

3.2. 방법 2: 잠금을 사용하여 스레드를 제한합니다.

4. 요약


1. 소개

현재 요구 사항은 다음과 같습니다. 데이터를 처리하고 데이터베이스에 데이터를 저장합니다. 저장 프로세스 중에 데이터가 데이터베이스에 저장되었는지 여부를 먼저 쿼리합니다. 처리할 데이터가 너무 크기 때문에 스레드 풀이 필요합니다. 동시 처리에 사용됩니다.

2. 질문

위의 방법을 사용하여 로직을 작성할 경우 스레드 안전 문제가 발생합니다. 확인 중에 삽입(데이터베이스 쿼리 데이터 불일치 문제)하여 데이터가 반복적으로 삽입됩니다. 따라서 데이터 중복 문제를 제한할 수 있는 수단을 채택할 필요가 있다.

3. 솔루션

3.1. 방법 1: 데이터베이스 제약

데이터베이스의 필드를 고유 인덱스로 설계합니다. 쿼리 중에 해당 데이터 레코드가 발견되지 않더라도(실제로는 데이터베이스에 이미 존재함) 삽입 중에 중복 필드 오류 예외가 보고되어 데이터 레코드 삽입이 실패하게 됩니다. 중복 제거 문제를 해결합니다.

3.2. 방법 2: 잠금을 사용하여 스레드를 제한합니다.

실제 비즈니스 시나리오를 기반으로 적절한 잠금 전략을 선택하세요. 낙관적 잠금은 쓰기 충돌이 적은 시나리오에 적합하고 비관적 잠금은 쓰기 충돌이 많은 시나리오에 적합합니다.

스레드 동기화: 다음과 같은 동기화 메커니즘을 사용합니다.ReentrantLocksynchronized 등을 사용하여 하나의 스레드만 동시에 쿼리 및 삽입 작업을 수행할 수 있도록 합니다. 다음은 스레드 동기화 메커니즘과 코드 표시 디자인을 사용합니다.

mybatis 인터페이스 코드:

  1. import org.apache.ibatis.annotations.*;
  2. public interface UserMapper {
  3. @Select("SELECT COUNT(*) FROM user WHERE username = #{username}")
  4. int countByUsername(@Param("username") String username);
  5. @Insert("INSERT INTO user (username, password, email) VALUES (#{username}, #{password}, #{email})")
  6. @Options(useGeneratedKeys = true, keyProperty = "id")
  7. int insertUser(User user);
  8. }

서비스 클래스 코드를 생성합니다.

  1. import org.apache.ibatis.session.SqlSession;
  2. import org.apache.ibatis.session.SqlSessionFactory;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. public class UserService {
  6. private final ExecutorService executorService;
  7. private final SqlSessionFactory sqlSessionFactory;
  8. public UserService(SqlSessionFactory sqlSessionFactory) {
  9. this.sqlSessionFactory = sqlSessionFactory;
  10. // 创建固定大小的线程池
  11. this.executorService = Executors.newFixedThreadPool(10);
  12. }
  13. public void addUser(User user) {
  14. executorService.submit(() -> {
  15. try (SqlSession session = sqlSessionFactory.openSession()) {
  16. UserMapper userMapper = session.getMapper(UserMapper.class);
  17. synchronized (UserService.class) {
  18. // 在同步块内执行查询和插入操作
  19. if (userMapper.countByUsername(user.getUsername()) == 0) {
  20. userMapper.insertUser(user);
  21. session.commit(); // 提交事务
  22. }
  23. }
  24. }
  25. });
  26. }
  27. }

위의 내용은 작은 경우일 뿐이며 실제 사용 시나리오는 필요에 따라 다릅니다.위 코드를 설명하세요.UserService.class 하나의 스레드만 동시에 쿼리 및 삽입 작업을 수행할 수 있도록 보장하는 잠금 개체입니다. 이렇게 하면 동시성 문제를 피할 수 있지만 특히 동시성이 높은 시나리오에서는 성능 병목 현상이 발생할 수 있습니다. 성능을 최적화하려면 보다 세분화된 잠금이나 데이터베이스 수준 잠금(비관적 잠금 등) 사용을 고려할 수 있습니다.

4. 요약

스레드 풀 작업 데이터베이스의 논리는 요구 사항에 따라 설계되었지만 전체 프로세스에서 스레드 안전 문제가 있으므로 두 가지 해결 방법을 간략하게 소개합니다. ① 데이터베이스 테이블에 고유 인덱스 필드 설정 ② 잠금을 사용하여 스레드 동기화 보장. 사용할 때는 실제 시나리오에 맞게 조정하세요. 프로세스는 비교적 광범위하게 작성되었으며 두 가지 방법만 소개합니다. 깊이 있게 이해하려면 더 공부해야 합니다. 물론, 저의 소소한 팁을 통해 여러분의 혼란에 작은 답을 드릴 수 있기를 바라겠습니다.


공부할 때 잠이 오는 이유는 바로 그곳에서 꿈이 시작되기 때문입니다.
ଘ(੭ˊᵕˋ)੭ (행복) ଘ(੭ˊᵕˋ)੭ (행복) ଘ(੭ˊᵕˋ)੭ (행복) ଘ(੭ˊᵕˋ)੭ (행복) ଘ(੭ˊᵕˋ)੭ (행복)
------코드를 쓰지 않으면 눈에 띄지 않는 류샤오