Avatar
πŸ˜‰

Organizations

  • Java μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ‹€ν–‰ν•  λ•Œ -Xmx512mκ³Ό -XX:MaxRAM=512mλŠ” λͺ¨λ‘ μ΅œλŒ€ λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰μ„ μ œν•œν•˜λŠ” μ˜΅μ…˜μ΄μ§€λ§Œ, λ™μž‘ 방식에 차이가 μžˆμŠ΅λ‹ˆλ‹€.

    1. -Xmx512m

    • νž™(Heap) λ©”λͺ¨λ¦¬μ˜ μ΅œλŒ€ 크기λ₯Ό 512MB둜 μ„€μ •ν•©λ‹ˆλ‹€.
    • 예제:
      java -Xmx512m -jar myapp.jar
      
    • 이 섀정은 Java νž™ λ©”λͺ¨λ¦¬λ§Œ μ œν•œν•˜λ©°, 전체 ν”„λ‘œμ„ΈμŠ€μ˜ λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰μ„ μ œν•œν•˜λŠ” 것은 μ•„λ‹™λ‹ˆλ‹€.
    • 즉, νž™ μ™Έμ˜ λ©”λͺ¨λ¦¬(λ©”νƒ€μŠ€νŽ˜μ΄μŠ€, μŠ€νƒ, λ„€μ΄ν‹°λΈŒ λ©”λͺ¨λ¦¬ λ“±)λŠ” λ”°λ‘œ μ œν•œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

    2. -XX:MaxRAM=512m

    • JVM이 μ‚¬μš©ν•  수 μžˆλŠ” 전체 λ©”λͺ¨λ¦¬(νž™ + λ©”νƒ€μŠ€νŽ˜μ΄μŠ€ + 기타 λ„€μ΄ν‹°λΈŒ λ©”λͺ¨λ¦¬) λ₯Ό 512MB둜 μ œν•œν•©λ‹ˆλ‹€.
    • 예제:
      java -XX:MaxRAM=512m -jar myapp.jar
      
    • -XX:MaxRAM을 μ„€μ •ν•˜λ©΄ -Xmx의 기본값이 λ‹¬λΌμ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.
      • 일반적으둜 -Xmx의 기본값은 MaxRAM κ°’μ˜ 25~50% μ •λ„λ‘œ μ„€μ •λ©λ‹ˆλ‹€(JVM 버전에 따라 닀름).
    • 이 섀정은 μ»¨ν…Œμ΄λ„ˆ ν™˜κ²½(Docker, Kubernetes) μ—μ„œ JVM이 μ‚¬μš©ν•  수 μžˆλŠ” λ©”λͺ¨λ¦¬λ₯Ό μ œμ–΄ν•˜λŠ” 데 μœ μš©ν•©λ‹ˆλ‹€.

    차이점 μš”μ•½

    μ˜΅μ…˜ λŒ€μƒ μ„€λͺ…
    -Xmx512m νž™(Heap) λ©”λͺ¨λ¦¬ νž™ λ©”λͺ¨λ¦¬μ˜ μ΅œλŒ€ 크기만 μ œν•œ
    -XX:MaxRAM=512m 전체 JVM λ©”λͺ¨λ¦¬ νž™ + λ©”νƒ€μŠ€νŽ˜μ΄μŠ€ + λ„€μ΄ν‹°λΈŒ λ©”λͺ¨λ¦¬λ₯Ό ν¬ν•¨ν•œ JVM 전체 λ©”λͺ¨λ¦¬ μ œν•œ

    ν•¨κ»˜ μ‚¬μš©ν•˜λ©΄?

    두 μ˜΅μ…˜μ„ ν•¨κ»˜ μ‚¬μš©ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

    Created Wed, 26 Mar 2025 11:26:45 +0900
  • Javaμ—μ„œ λ°μ΄ν„°λ² μ΄μŠ€μ˜ SELECT 쿼리에 λŒ€ν•΄ Lockκ³Ό Unlock을 μ‚¬μš©ν•˜λŠ” 방법은 λ°μ΄ν„°λ² μ΄μŠ€ μ‹œμŠ€ν…œκ³Ό 쿼리의 섀정에 따라 λ‹¬λΌμ§‘λ‹ˆλ‹€. 일반적으둜 SELECT μžμ²΄λŠ” λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μž κΈˆμ„ μœ λ°œν•˜μ§€ μ•Šμ§€λ§Œ, νŠΈλžœμž­μ…˜μ΄λ‚˜ 쿼리 힌트λ₯Ό μ‚¬μš©ν•˜μ—¬ 잠금 λ™μž‘μ„ μ œμ–΄ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ•„λž˜μ— λͺ‡ κ°€μ§€ 방법을 μ„€λͺ…ν•©λ‹ˆλ‹€.


    1. νŠΈλžœμž­μ…˜μ„ μ‚¬μš©ν•œ Lock μ œμ–΄

    νŠΈλžœμž­μ…˜μ„ 톡해 SELECT 문이 μ‹€ν–‰ 쀑인 λ™μ•ˆ λ‹€λ₯Έ μž‘μ—…μ΄ 데이터에 μ ‘κ·Όν•˜μ§€ λͺ»ν•˜λ„둝 μž κΈˆμ„ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    예제 μ½”λ“œ:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    public class DatabaseLockExample {
        public static void main(String[] args) {
            String url = "jdbc:mysql://localhost:3306/your_database";
            String user = "your_username";
            String password = "your_password";
    
            try (Connection connection = DriverManager.getConnection(url, user, password)) {
                // Auto-commit λΉ„ν™œμ„±ν™”
                connection.setAutoCommit(false);
    
                // SELECT ... FOR UPDATE (ν–‰ 잠금 μ„€μ •)
                String sql = "SELECT * FROM your_table WHERE id = ? FOR UPDATE";
                try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                    preparedStatement.setInt(1, 1); // ID κ°’ 바인딩
                    ResultSet resultSet = preparedStatement.executeQuery();
    
                    while (resultSet.next()) {
                        System.out.println("Data: " + resultSet.getString("your_column"));
                    }
    
                    // μž‘μ—… ν›„ 컀밋
                    connection.commit();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    μ„€λͺ…:

    • FOR UPDATEλŠ” ν•΄λ‹Ή 행을 잠그고, λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ΄ μˆ˜μ •ν•˜μ§€ λͺ»ν•˜λ„둝 ν•©λ‹ˆλ‹€.
    • νŠΈλžœμž­μ…˜μ„ μ»€λ°‹ν•˜κ±°λ‚˜ λ‘€λ°±ν•˜λ©΄ 잠금이 ν•΄μ œλ©λ‹ˆλ‹€.

    2. 쿼리 힌트λ₯Ό μ‚¬μš©ν•œ Lock μ œμ–΄

    λ°μ΄ν„°λ² μ΄μŠ€μ— 따라 SELECT 쿼리에 힌트λ₯Ό μΆ”κ°€ν•˜μ—¬ 잠금 λ™μž‘μ„ μ§€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, MySQLμ—μ„œ LOCK IN SHARE MODE λ˜λŠ” FOR UPDATEλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    Created Wed, 26 Mar 2025 11:25:45 +0900
  • Spring Boot JPAμ—μ„œ @Transactional μ‚¬μš©λ²•

    Spring Boot JPAμ—μ„œ @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ€ νŠΈλžœμž­μ…˜ λ²”μœ„ λ‚΄μ—μ„œ λ°μ΄ν„°λ² μ΄μŠ€ μž‘μ—…μ„ μ‹€ν–‰ν•˜κ³ , μ‹€νŒ¨ μ‹œ λ‘€λ°±ν•˜λŠ” κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” μ€‘μš”ν•œ μš”μ†Œμž…λ‹ˆλ‹€.


    1. @Transactional κΈ°λ³Έ μ‚¬μš©λ²•

    Spring의 @Transactional을 μ‚¬μš©ν•˜λ©΄ ν•˜λ‚˜μ˜ λ©”μ„œλ“œμ—μ„œ μ—¬λŸ¬ 개의 JPA μž‘μ—…(쑰회, μ €μž₯, μˆ˜μ •, μ‚­μ œ λ“±)을 μˆ˜ν–‰ν•  λ•Œ νŠΈλžœμž­μ…˜μ„ μžλ™μœΌλ‘œ 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.

    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class MemberService {
        private final MemberRepository memberRepository;
    
        public MemberService(MemberRepository memberRepository) {
            this.memberRepository = memberRepository;
        }
    
        @Transactional
        public void updateMember(Long id, String name) {
            Member member = memberRepository.findById(id)
                    .orElseThrow(() -> new IllegalArgumentException("Member not found"));
    
            member.setName(name);  // JPA μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ˜ν•΄ μžλ™μœΌλ‘œ μ—…λ°μ΄νŠΈλ¨
        }
    }
    
    • @Transactional을 μ‚¬μš©ν•˜λ©΄, λ©”μ„œλ“œ μ‹€ν–‰ 쀑 μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ 둀백되며, μ„±κ³΅ν•˜λ©΄ μžλ™μœΌλ‘œ μ»€λ°‹λ©λ‹ˆλ‹€.
    • member.setName(name);을 ν˜ΈμΆœν•˜λ©΄ JPA의 λ³€κ²½ 감지(dirty checking) 덕뢄에 save()λ₯Ό λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœν•˜μ§€ μ•Šμ•„λ„ μ—…λ°μ΄νŠΈλ©λ‹ˆλ‹€.

    2. 읽기 μ „μš© νŠΈλžœμž­μ…˜ (@Transactional(readOnly = true))

    readOnly = trueλ₯Ό μ„€μ •ν•˜λ©΄ μ„±λŠ₯ μ΅œμ ν™”λ₯Ό ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    Created Wed, 26 Mar 2025 11:21:45 +0900
  • Spring Boot JPAμ—μ„œ @Transactional μ˜΅μ…˜ 정리

    Spring Boot JPAμ—μ„œ @Transactional은 νŠΈλžœμž­μ…˜ 처리λ₯Ό μœ„ν•΄ μ‚¬μš©ν•˜λŠ” 맀우 μ€‘μš”ν•œ μ–΄λ…Έν…Œμ΄μ…˜μ΄μ—μš”. λ°μ΄ν„°λ² μ΄μŠ€μ˜ 일관성과 무결성을 μœ μ§€ν•˜κΈ° μœ„ν•΄ μ—¬λŸ¬ μž‘μ—…μ„ ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ λ¬Άμ–΄ μ‹€ν–‰ν•  λ•Œ μ‚¬μš©ν•˜μ£ . μ•„λž˜μ— μ‚¬μš©λ²•μ„ μ •λ¦¬ν•΄λ³Όκ²Œμš”.


    πŸ“Œ κΈ°λ³Έ μ‚¬μš©λ²•

    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class MemberService {
    
        @Transactional
        public void joinMember(Member member) {
            memberRepository.save(member);
            // μ˜ˆμ™Έ λ°œμƒ μ‹œ 전체 νŠΈλžœμž­μ…˜ λ‘€λ°±
        }
    }
    
    • @Transactional을 λ©”μ„œλ“œμ— 뢙이면 ν•΄λ‹Ή λ©”μ„œλ“œ μ•ˆμ˜ μž‘μ—…μ΄ ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ μ²˜λ¦¬λΌμš”.
    • λŸ°νƒ€μž„ 쀑 μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ μžλ™μœΌλ‘œ λ‘€λ°±λΌμš”. (기본적으둜 unchecked exception일 λ•Œλ§Œ λ‘€λ°±)

    πŸ“Œ 클래슀 λ ˆλ²¨μ— μ‚¬μš©

    @Transactional
    @Service
    public class MemberService {
        public void method1() {
            // νŠΈλžœμž­μ…˜ 적용됨
        }
    
        public void method2() {
            // νŠΈλžœμž­μ…˜ 적용됨
        }
    }
    
    • 클래슀 전체에 νŠΈλžœμž­μ…˜μ„ κ±Έ 수 μžˆμ–΄μš”. 단, λ©”μ„œλ“œμ— κ°œλ³„μ μœΌλ‘œ μ„€μ •λœ 게 μš°μ„  μ μš©λ©λ‹ˆλ‹€.

    πŸ“Œ rollbackFor μ˜΅μ…˜

    기본적으둜 RuntimeExceptionκ³Ό κ·Έ ν•˜μœ„ 클래슀만 λ‘€λ°± λŒ€μƒμœΌλ‘œ κ°„μ£ΌλΌμš”. λ§Œμ•½ 체크 μ˜ˆμ™Έ(Exception)도 λ‘€λ°±ν•˜κ³  μ‹Άλ‹€λ©΄:

    Created Wed, 26 Mar 2025 11:15:45 +0900
  • Javaμ—μ„œ Redisλ₯Ό μ‚¬μš©ν•  λ•Œ CRUD Repository와 RedisTemplate은 각각 λ‹€λ₯Έ μˆ˜μ€€μ˜ 좔상화λ₯Ό μ œκ³΅ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€. μ£Όμš” 차이점은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:


    βœ… 1. CRUD Repository (Spring Data Redis)

    RedisRepository, CrudRepository, PagingAndSortingRepository λ“±κ³Ό 같이 Spring Dataκ°€ μ œκ³΅ν•˜λŠ” Repository μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.

    πŸ”Ή μž₯점

    • 높은 좔상화 μˆ˜μ€€: λ‹¨μˆœν•œ CRUD μž‘μ—…μ„ μΈν„°νŽ˜μ΄μŠ€λ‘œ μ •μ˜ν•˜κΈ°λ§Œ ν•˜λ©΄, κ΅¬ν˜„ 없이 μžλ™μœΌλ‘œ λ™μž‘.
    • 개발 속도 빠름: 반볡적인 둜직 쀄일 수 있음 (findById, save, delete λ“± κΈ°λ³Έ 제곡).
    • Spring Data의 κΈ°λŠ₯을 ν™œμš© κ°€λŠ₯ (예: 쿼리 λ©”μ„œλ“œ, νŽ˜μ΄μ§• λ“±).

    πŸ”Ή 단점

    • μ„Έλ°€ν•œ μ œμ–΄ 어렀움: λ³΅μž‘ν•œ 데이터 κ΅¬μ‘°λ‚˜ μ»€μŠ€ν…€ λ‘œμ§μ€ κ΅¬ν˜„ν•˜κΈ° 어렀움.
    • 직렬화 방식 κ³ μ •: 기본적으둜 JDK 직렬화λ₯Ό μ‚¬μš©ν•˜κ³ , μ»€μŠ€ν„°λ§ˆμ΄μ§• ν•˜λ €λ©΄ μ„€μ • ν•„μš”.

    πŸ”Ή μ˜ˆμ‹œ

    public interface UserRedisRepository extends CrudRepository<User, String> {
        Optional<User> findByUsername(String username);
    }
    

    βœ… 2. RedisTemplate

    Springμ—μ„œ μ œκ³΅ν•˜λŠ” μ €μˆ˜μ€€ API둜, ν‚€-κ°’ μ €μž₯μ†Œλ‘œμ„œ Redisλ₯Ό μœ μ—°ν•˜κ²Œ λ‹€λ£° 수 있음.

    Created Wed, 26 Mar 2025 11:11:03 +0900
  • feign client μ‚¬μš©νŒ 1 - μƒλŒ€ μ„œλ²„κ°€ μ—¬λŸ¬λŒ€ μΌλ•Œ 랜덀 호좜

    load balancing 되고 μžˆλŠ” μƒλŒ€μΈ‘μ— λ²ˆκ°ˆμ•„κ°€λ©΄μ„œ ν˜ΈμΆœν•˜λŠ” 방법

    • build.gradle
    ...
    dependencies {
        implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
    }
    ...
    
    • application.yml
    # μƒλŒ€ μΈ‘μ—μ„œ 3개의 μ„œλ²„ LB되고 μžˆμ„ λ•Œ 
    other-party-url:
      - 123.456.789.001
      - 123.456.789.002
      - 123.456.789.003
    
    • ServerProperties.java
    @Setter
    @Getter
    @Configuration
    @ConfigurationProperties(prefix = "other-party-url")
    public class OtherServerProperties {
    
        private List<String> serverUris;
    }
    
    • FeignConfig.java
    @RequiredArgsConstructor
    public class OtherServerFeignConfig {
    
        private final OtherServerProperties otherServerProperties;
    
        private final AtomicInteger counter = new AtomicInteger(0);
    
        @Bean
        public RequestInterceptor randomServerInterceptor() {
            return requestTemplate -> {
                List<String> serverUris = otherServerProperties.getServerUris();
    
                int index = counter.getAndIncrement() % serverUris.size();
                String selectedUrl = serverUris.get(index);
    
                requestTemplate.target(selectedUrl);
            };
        }
    }
    
    • FeignClient interface
    @FeignClient(name = "your-server", configuration = OtherServerFeignConfig.class)
    public interface OtherServerFeignClientV1 {
        
        ...
    }
    
    Created Wed, 26 Mar 2025 08:37:45 +0900