반응형

# 한영키 없는 키보드 해결방법

  • 기계식 키보드 등의 경우 한영키가 없는데, 보통은 우측 ALT 키를 누르면 한영 전환이 이루어 진다.

## 해결방법1 (제조사 홈페이지를 통한 레지스트리 등록)

  • 하지만 우측 ALT 키를 눌러도 한영 전환이 안되는 경우도 있는데, 이 경우 해당 키보드 제조사 홈페이지에서 한영키 전환관련 파일을 받아 등록해주면된다.

## 해결방법2 

  • 인터넷을 사용할 수 없는 특수한 환경에서 일을 하는 경우 제조사 홈페이지에서 파일을 받아 등록할 수 없다.
  • 이 경우에는 설정 > 시간 및 언어 > 왼쪽의 언어 선택 후, 아래와 같이 기본 설정 언어에서 한국어 선택.

  • 활성화 된 옵션 버튼 클릭 후 하드웨어 및 키보드 레이아웃에서 레이아웃 변경 선택 후 나오는 팝업에서 '한글 키보드(101키) 종류 1' 로 변경하면 해결된다.

1. 101키 종류1
- 한영(오른쪽 ALT)
- 한자(오른쪽 CTRL)

2. 101키 종류2
- 한영(오른쪽 CTRL)
- 한자(오른쪽 ALT)

3. 101키 종류3
- 한영(SHIFT + SPACE)
- 한자(CTRL + SPACE)
반응형

'기타' 카테고리의 다른 글

오라클 WITH절  (0) 2022.10.13
DQM, DEM 등 MVC 모델의 파일 약자와 의미  (2) 2022.10.13
DB2 란?  (0) 2022.10.04
IT 관련 각종 자격정보  (0) 2022.09.03
오라클 정규식  (0) 2022.08.29
반응형

# DB2

## DB2 란?

  • DB2 란 IBM 에서 만든 상업용 관계 데이터베이스 관리 시스템이다. (대형화된 데이터 관리를 목적으로 만들어졌다.)
  • 관계형 데이터베이스의 종류 : 오라클 (세계적으로 많이 사용), DB2 등 존재.

## DB2의 특징

  • 각 업무의 특성에 맞게 시스템이 최적화 될 수 있다.
  • 다양한 기능 (자가 최적화, 자가 치유, 자가 구성, 업무 관리, 자동화 기능 등) 구현 가능.
  • 데이터 압축 기술이 좋아 대형화된 데이터를 다루는데 최적화.

## DB2 더미 테이블

  • 오라클의 from dual 을 DB2 에서는 아래와 같이 사용한다.
SELECT 'test'
FROM sysibm.sysdummy1;


SELECT 'test'
FROM sysibm.dual;

## 그외 DB2 관련 내장 함수 등 필요사항

 

내장 함수

내장 함수는 데이터베이스 관리자가 제공하는 함수이고 집계 함수, 스칼라 함수 또는 테이블 함수로 분류됩니다. 이 주제에서는 유형별로 분류된 지원되는 내장 함수를 나열합니다. 집계 함수(

www.ibm.com

 

반응형

'기타' 카테고리의 다른 글

DQM, DEM 등 MVC 모델의 파일 약자와 의미  (2) 2022.10.13
한영키 없는 키보드 해결방법  (0) 2022.10.05
IT 관련 각종 자격정보  (0) 2022.09.03
오라클 정규식  (0) 2022.08.29
포워딩, 리다이렉트  (0) 2022.08.25
반응형

# 오라클 소수점 처리

  • 프로젝트를 하다보면 고객의 요청에 따라 0.7 같이 소수점을 표시 해서 보여줘야 하는 경우가 존재한다.
  • 간혹 소수점을 표시하여 처리하는 경우 .5 등의 표시 오류가 발생하는데, 이를 해결하는 방법은 TO_CHAR 와 FM 을 사용하는것이다.

## FM990.99

  • 사용방법 : TO_CHAR(표시할숫자, 'FM990.99')

FM

  • 좌우 9로 치환된 소수점 이상의 공백 및 소수점 이하의 0 제거.
  • FM 이 없는 경우 : 소수점 이상의 숫자는 공백, 소수점 이하의 숫자는 0으로 표시

9

  • 해당 자리의 숫자. (가변길이)
  • 값이 없는경우 소수점 이상 : 공백 으로 표시.
  • 값이 없는경우 소수점 이하 : 0 으로 표시.
  • 0이거나 숫자가 존재하지 않으면 값을 버림.

0

  • 해당 자리의 숫자. (고정길이)
  • 값이 없는경우 : 0으로 표시.
  • 고정적으로 숫자의 길이를 표시할 경우 사용한다.
  • 숫자의 길이를 맞추고 싶을때 길이만큼 0을 추가.

## 사용 예시

SELECT '0.5' AS A  -- 0.05표시
    , TO_CHAR('0.05', '999,999') AS B  -- 0표시
    , TO_CHAR('0.05', '999.999') AS C  -- .050표시
    , TO_CHAR('0.05', 'FM999.99') AS D  -- .05표시
    , TO_CHAR('0.05', 'FM990.99') AS E  -- 0.05표시
    , TO_CHAR('0.05', 'FM900.99') AS F  -- 00.05표시
    , TO_CHAR('0.05', 'FM990.990') AS G  -- 0.050표시
    , TO_CHAR('0.05', 'FM990.9900') AS H  -- 0.0500표시
FROM DUAL;
반응형
반응형

# 싱글톤 컨테이너

## 싱글톤 컨테이너

  • 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도 객체 인스턴스를 싱글톤으로 관리한다.
  • 스프링 컨테이너가 싱글톤 역할을 한다.
  • 싱글톤 레지스트리 : 싱글톤 객체를 생성, 관리하는 기능.

SingletonTest

public class SingletonTest {
    @Test
    @DisplayName("스프링 컨테이너와 싱글톤")
    void springContainer() {

        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        // 1. 조회 : 호출할 때마다 객체 생성하는지 확인.
        MemberService memberService1 = ac.getBean("memberService", MemberService.class);
        MemberService memberService2 = ac.getBean("memberService", MemberService.class);

        // 참조값이 다른 것 확인.
        System.out.println("memberService1 = " + memberService1);
        System.out.println("memberService2 = " + memberService2);

        Assertions.assertThat(memberService1).isSameAs(memberService2);
    }
}
  • 클라이언트의 요청(memberService 요청) 시 동일한 memberService를 반환(요청시마다 새로 생성하는게 아닌 이미 만들어진 객체(동일한 객체)를 반환).

## 싱글톤 방식의 주의점 (공유필드 조심! 항상 무상태 (stateless) 로 설계하기!)

  • 객체 인스턴스를 하나만 생성해서 공유하는 경우, 여러 클라이언트가 하나의 객체를 공유해서 사용하기 때문에 싱글톤 객체는 상태를 유지 (stateful) 하게 설계하면 안된다. -> 무상태 (stateless) 로 설계해야 한다.
  1. 특정 클라이언트에 의존적인 필드가 없어야 한다.
  2. 특정 클라이언트가 값을 변경할수 있는 필드가 없어야 한다.
  3. 읽기만 가능해야 하고 값을 수정하면 안된다.
  4. 필드 대신 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.

상태 유지로 설계된 경우 예시.

StatefulService (상태 유지)

package singleton;

public class StatefulService {

    private int price;  // 상태 유지하는 필드

    public void order(String name, int price) {
        System.out.println("name = " + name + " price = " + price);

        // 문제점.
        this.price = price;
    }

    public int getPrice() {
        return price;
    }
}

statefulServiceTest

package singleton;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

public class StatefulServiceTest {

    @Test
    void statefulServiceSingleton() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);

        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        // ThreadA : A 사용자 20,000 주문.
        statefulService1.order("userA", 20000);
        // ThreadB : B 사용자 150,000 주문.
        statefulService2.order("userB", 150000);

        // ThreadA : 사용자A 가 주문 금액을 조회.
        int price = statefulService1.getPrice();
        System.out.println("price = " + price);

        Assertions.assertThat(statefulService1.getPrice()).isEqualTo(150000);
    }

    static class TestConfig {
        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }
    }
}
  • 위 테스트 코드 실행 시  A사용자가 주문한 금액을 조회하면 아래와 같은 결과가 나온다.

  • 특정 클라이언트가 공유되는 필드의 값을 변경하여 문제 발생. (공유 필드는 조심해야 함)

무상태로 설계된 경우 예시. (위 상태 유지 코드를 아래와 같이 변경 가능)

package singleton;

public class StatefulService {
    public int order(String name, int price) {
        System.out.println("name = " + name + " price = " + price);
        return price;
    }
}
package singleton;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

public class StatefulServiceTest {

    @Test
    void statefulServiceSingleton() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);

        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        // ThreadA : A 사용자 20,000 주문.
        int userAPrice = statefulService1.order("userA", 20000);
        // ThreadB : B 사용자 150,000 주문.
        int userBPrice = statefulService2.order("userB", 150000);

        // ThreadA : 사용자A 가 주문 금액을 조회.
        System.out.println("price = " + userAPrice);

    }

    static class TestConfig {
        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }
    }
}

## @Configuration 과 싱글톤

AppConfig

@Configuration
public class AppConfig {

    // memberService 역할
    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    // memberRepository 역할
    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    // orderService 역할
    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    // discountPolicy 역할
    @Bean
    public DiscountPolicy discountPolicy() {
//        return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
}
  • AppConfig 에서 로직을 살펴보면 아래와 같은 문제점이 존재한다는걸 확인할 수 있다.
@Bean memberService() 시 new MemoryMemberRepository() 호출

@Bean orderService() 시 new MemoryMemberRepository() 중복 호출

 

위 내용 관련하여 테스트해서 확인 진행

MemberServiceImpl 에 테스트용 메서드 생성.

package hello.core.member;

public class MemberServiceImpl implements MemberService {

    private final MemberRepository memberRepository;

    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }

    // 테스트용
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}

OrderServiceImpl 에 테스트용 메서드 생성.

package hello.core.order;

import hello.core.discount.DiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;

public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }

    // 테스트용
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}

ConfigurationSingletonTest

package singleton;

import hello.core.AppConfig;
import hello.core.member.MemberRepository;
import hello.core.member.MemberServiceImpl;
import hello.core.order.OrderServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ConfigurationSingletonTest {

    @Test
    void configurationTest() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
        OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
        MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);

        MemberRepository memberRepository1 = memberService.getMemberRepository();
        MemberRepository memberRepository2 = orderService.getMemberRepository();

        System.out.println("memberService > memberRepository = " + memberRepository1);
        System.out.println("orderService > memberRepository = " + memberRepository2);
        System.out.println("memberRepository = " + memberRepository);

        Assertions.assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
        Assertions.assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
    }
}
  • 테스트 코드를 실행해 보면 아래와 같은 결과를 확인할 수 있다. (동일함)

  • 동일한 인스턴스를 공유해서 사용중임을 확인할 수 있다. 
  • AppConfig 동작 시 아래와 같이 특정 메서드가 중복 호출될 것 같은데 실제로는 중복 없이 호출된다. (@Configuration)
AppConfig.memberService
AppConfig.memberRepository
AppConfig.memberRepository
AppConfig.orderService
AppConfig.memberRepository

## @Configuration 과 바이트코드 조작의 마법 

  • 스프링 컨테이너는 싱글톤 레지스트리임. (스프링 빈이 싱글톤이 되도록 보장)
  • AppConfig 에서 특정 메서드가 중복으로 호출될 것 같은데 실제로는 중복 없이 호출되는 비밀은 @Configuration 에 있다.
  • 아래와 같이 AnnotationConfigApplicationContext 에 파라미터로 넘긴 값(AppConfig) 은 스프링 빈으로 등록된다. 그렇기 때문에 AppConfig 도 스프링 빈으로 등록됨.
new AnnotationConfigApplicationContext(AppConfig.class);

ConfigurationSingletonTest 에서 등록된 AppConfig 조회 관련 테스트 코드 추가. (빈을 조회하여 클래스 정보 출력)

@Test
void configurationDeep() {
    ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    AppConfig bean = ac.getBean(AppConfig.class);

    System.out.println("bean = " + bean.getClass());
}

 

  • 위 테스트 코드 실행 시 아래와 같은 결과를 확인 할 수 있다. (순수한 클래스라면 정상적인 path가 출력)

  • 위와 같은 결과가 나온 이유는 스프링 빈이 CGLIB라는 바이트코드 조작 라이브러리를 사용, AppConfig 클래스를 상속받은 임의의 다른 클래스를 생성하고 그걸 스프링 빈으로 등록한 것.
  • 그래서 이름은 등록한 AppConfig 이지만, 바이트코드를 조작하여 작성된 다른 클래스 정보가 표시되는 것.
  • AppConfig@CGLIB 내부 로직을 예상해 보면 아마도, 등록된 빈이 없으면 신규로 빈을 등록하고, 존재하면 등록된 빈을 반환하도록 되어있을 것임 -> 그래서 AppConfig에서 중복없이 메서드 호출.

@Configuration 부착여부에 따라

  • @Configuration 을 붙이면 바이트코드를 조작하는 CGLIB 를 사용해서 싱글톤을 보장해준다.
  • @Configuration  붙이지 않고 @Bean 만 사용해도 스프링 빈으로 등록되지만, 싱글톤은 보장하지 않게됨. > AppConfig 실행 시, 중복된 메서드를 호출하게 된다. (중복 호출된 빈은 모두 동일하지 않음)
반응형

+ Recent posts