public class Group {
    @Id
    @Column(name = "groupidx")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int groupIdx;
}

 

public class Project {
    @Id
    @Column(name = "projectidx")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int projectIdx;
    
    @OneToOne(mappedBy = "project", cascade = CascadeType.PERSIST)
    Apple apple;
    
    @OneToOne(mappedBy = "project", cascade = CascadeType.PERSIST)
    Samsung samsung;

    @ManyToOne(fetch = FetchType.EAGER)
    @JsonBackReference
    @JoinColumn(name = "groupidx", insertable=false, updatable=false)
    private Group group;
 }

 

public class Apple {
    @Id
    @Column(name = "id", unique = true, nullable = false)
    private String id;
 
    @Column(name = "projectidx", unique = true)
    private int projectIdx;
    
 	@MapsId("projectIdx")
    @OneToOne
    @JoinColumn(name = "projectidx")
    private Project project;
}
public class Samsung {
    @Id
    @Column(name = "id", unique = true, nullable = false)
    private String id;
 
    @Column(name = "projectidx", unique = true)
    private int projectIdx;
    
 	@MapsId("projectIdx")
    @OneToOne
    @JoinColumn(name = "projectidx")
    private Project project;
}

 

 

TestCode

    @Transactional
    @Test
    public void groupAndProjectTest() {
        Group group = groupRepository.findById(1).get();
        List<Project> project = group.getProject();
        
        assertNotNull(project.getProjectIdx);
        assertNotNull(project.get(0).getApple().getApple***());
    }

Group -> Project -> Apple or Samsung 

group을 가져오면 해당 그룹이 가지고 있는 project, apple or samsung 데이터를 확인할 수 있다. 

 

 

 

 

케빈 TV (자바8) 못다한 이야기를 들으며 내용을 정리해보았습니다.

https://www.youtube.com/watch?v=Ql9car-IjR0&t=2s

 

 

최대한 잘 정리해서 실무에 적용하고 싶을 때 참고할 수 있는 자료가 되었으면 좋겠네요 ^^

 

 

  • Functional Interface
    • 인터페이스인데 그 안에 구현해야 될 Abstract Method가 하나만 존재하면 그것을 Functional Interface라고 부른다.
    • 이 인터페이스는 람다표현식으로 구현 가능하다. 
  • 중요한 이유 ? 
    • Functional Interface를 사용하는 코드는 Functional Interface의 Object, Instance에 해당하는 Anonymous class를 생성할 필요없이 Lambda Expression으로 대체할 수 있음
    • Lambda Expression을 사용하기에 꼭 필요한 Interface라고 볼 수 있다. 
    • 사실, Lambda Expression의 type이 Functional Interface
    • 구현해야하는 Abstract Method가 1개여야만 하는 이유는 메소드 이름, 매개변수의 타입 지정 같은 것이 없어야 컴파일러가 인터페이스와 메서드, 인자를 추론할 수 있기 때문이다. 

 

 

 

 

 

자바 8에 추가된 Functional Interface Type을 알아보자!

 

 

Function

@FunctionalInterface
public interface Function<T, R> {
	R apply(T t);
    
    default<V> Function<V, R> compose(Function<? super V,? extends T> before) {
    	Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
    
    static <T> Function<T, T> identity() { return t -> t;}
}
  • @FunctionalInterface라는 애노테이션을 추가하여 이 인터페이스는 추상 메서드 하나만을 가질 수 있는 함수형 인터페이스라는 걸 알려준다. -> 추상메서드 개수 제한!
  • FunctionalInterface 애노테이션이 있는 인터페이스는 람다 표현식으로 구현할 수 있다. 
    • 애노테이션 반드시 달아야 하는 것은 아니나 나중에 누가 메서드를 추가하거나 하는 상황을 막기 위해서는 이 애노테이션을 달고 그런 문제를 사전에 방지하도록 하자!
  • R apply (T t)를 보면 다른 전달받은 Type과 다른 Type을 반환하는 것을 알 수 있다.
    • 같은 Type을 리턴하는 함수를 Identity 함수라고 한다. -> 입력값과 같은 Type의 Value를 리턴하는 함수

람다 적용 전

Function<String, Integer> toInt = new Function<String, Integer>() {
  @Override
  public Integer apply(final String value) {
  return Integer.parseInt(value);
  }
};

final Integer number = toInt.apply("100");
System.out.println(number);

람다 적용중

 

Function<String, Integer> toInt1 = (final String value) -> {
   return Integer.parseInt(value);
};

람다 적용 완성!

Function<String, Integer> toInt2 = value -> Integer.parseInt(value);

 

 

 


 

 

Consumer

@FunctionalInterface
public interface Consumer<T> {
	void accept(T t);
}

 

람다적용 전

final Consumer<String> print = new Consumer<String>() {
	@Override
    public void accept(final String value) {
    	System.out.println(value);
    }
}

print.accept("Hello");

 

람다적용 후

final Consumer<String> pringt = value -> System.out.println(value);
print.accept("Hello");

 

  • Consumer를 Function으로 바꾸면 ? 
final Consumer<String> print = value -> System.out.println(value); // OK
final Function<String, Void> print2 = value -> System.out.println(value); //ERROR!!

Function은 반드시 입력값과 출력값이 있어야 한다. 리턴값을 Void로 명시해주더라도 에러가 발생한다. 

따라서, 리턴되는 값이 없는 경우에는 Consumer Function Interface를 사용해주도록 한다. 

 

 

 

 


 

Predicate

@FunctionalInterface
public interface Predicate<T> {
	boolean test(T t);
}

입력값 T만 있고 리턴되는 값은 항상 Boolean이다. 

 

Predicate<Integer> isPositive = i -> i > 0;

System.out.println(isPositive.test(1)); //  true

 

Predicate을 사용한 번외편 ? 

 

Predicate<Integer> isPositive = i -> i > 0;
Predicate<Integer> lessThan = i -> i < 3;

List<Integer> positiveNumbers = Arrays.asList(-3,-2,-1,0,1,2,3,4,5);

List<Integer> positiveNumbersResult = new ArrayList<>();
for (Integer num : numbers) {
	if (isPositive.test(num)) {
    	positiveNumbers.add(num);
    }
}

List<Integer> lessThan3Result = new ArrayList<>();
for (Integer num : numbers) {
	if (lessThan.test(num)) {
    	lessThan3Result.add(num);
    }
}

for문 안의 if 조건문만을 제외하고는 두개의 for문이 중복된다는 것을 알 수 있다.

중복 부분을 제거하기 위해 공통으로 사용하는 메소드로 처리해보자. 

 

 

Predicate<Integer> isPositive = i -> i > 0;
Predicate<Integer> lessThan = i -> i < 3;

List<Integer> positiveNumbers = Arrays.asList(-3,-2,-1,0,1,2,3,4,5);

System.out.println("positive integers : "  + filter(numbers, isPositive));
System.out.println("less than 3 : "  + filter(numbers, lessThan3));

private static <T> List<T> filter(List<T> list, Predicate<T> filter) {
	List<T> result = new ArrayList<>();
    for (T input : list) {
    	if (filter.test(input)) {
        	result.add(input);
       }
    }
    return result;
}

두개가 다른 if 조건문에다가는 Functional Interface인 Predicate 을 입력했다. 

Predicate 덕분에 'i > 0', 'i < 3' 이렇게 조건문이 다른 데도 같은 동작을 할 수 있다는 것을 알 수 있다.

아니면 Lambda Expression 덕분에 메소드에 다른 메소드를 넘길 수 있게된 덕? 이라고 할 수도 있겠다.

 

 

 

 


Supplier

@FunctionalInterface
public interface Supplier<T> { 
	T get();
}

입력값이 없는데 리턴값이 있다. -> Lazy evaluation(계산의 결과값이 필요할 때까지 계산을 늦추는 기법) 가능하게 한다.

 

final Supplier<String> helloSupplier = () -> "Hello";

System.out.println(helloSupplier.get() + "world");

 

왜 그냥 "Hello"를 쓰면 되지 Supplier를 쓰는가? 예제로 알아보자

private String getVeryExpensiveValue() {
	return "Kevin";
}

private static String getVeryExpensiveValue() {
    try {
    	TimeUnit.SECONDS.sleep(3);
    } catch (InterruptionException e) {
    	e.printStackTrace();
    }
    
    return "KEVIN"
}

private static void printIfValidIndex(int number, String value) {
	if (number >= 0) {
    	System.out.println("The value is " + value + ".");
    } else {
    	System.out.println("Invalid);
    }
}

long start = System.currentTimeMills();
printIfValidIndex(0, getVeryExpensiveValue()); //3s
printIfValidIndex(-1, getVeryExpensiveValue()); //3s
printIfValidIndex(-2, getVeryExpensiveValue()); //3s

System.out.println("It took " + ((System.currentTimeMillis() - start) / 1000) + " seconds");

"It took 9 seconds" -> 결과는 9초

조건에 부합되지 않는 것 까지 계산하였으니..

 

 

Supplier를 써보자! -> Lazy Evaluation으로 불필요한 계산을 줄여 메모리, CPU 자원 낭비도 줄이고 싶다면!

private String getVeryExpensiveValue() {
	return "Kevin";
}

private static String getVeryExpensiveValue() {
    try {
    	TimeUnit.SECONDS.sleep(3);
    } catch (InterruptionException e) {
    	e.printStackTrace();
    }
    
    return "KEVIN"
}

private static void printIfValidIndex(int number, Supplier<String> valueSupplier) {
	if (number >= 0) {
    	System.out.println("The value is " + valueSupplier.get() + ".");
    } else {
    	System.out.println("Invalid);
    }
}

long start = System.currentTimeMills();
printIfValidIndex(0, () -> getVeryExpensiveValue()); // 3s
printIfValidIndex(-1, () -> getVeryExpensiveValue()); // 조건통과안되어 getVeryExpensiveValue 실행 X
printIfValidIndex(-2, () -> getVeryExpensiveValue()); // 조건통과안되어 getVeryExpensiveValue 실행 X

System.out.println("It took " + ((System.currentTimeMillis() - start) / 1000) + " seconds");

결과는 3초!

printIfValidIndex(0, new Supplier<String>() {
	@Override
    public String get() {
    	return getVeryExpensiveValue();
    }
});

 

 

 

 


 

 

케빈님 강좌가 참 좋은게 람다는 이렇게 쓰는 거다! 라고 정답을 바로 말해주는 것이 아니라

원래는 ~~이런데 요렇게 요렇게 바뀌어서 이렇게 된거다! 라는 식으로 

이전버전과 현재버전을 비교해주시면서 설명해주신다는 것! 

이해하는 데 참 많은 도움이 된다. 

 

Google Quick Lab 에 있는 내용을 조금 정리해보았어요~ :-)

오늘 들어야 할 랩이 4개나 남았는데 왜이리 졸린지 ㅠㅠ

 

 

  •  BigQuery
    • 구글 클라우드 플랫폼에서 실행되는 페타바이트 규모의 데이터 웨어하우스
  • Exporting queries as CSV files
    • BigQuery Consoel에서의 데이터 결과를 CSV파일로 추출
  • Upload CSV files to Cloud Storage
    • Navigation menu > Storage > Browser 선택해서 Create Bucket 선택 
    • 버켓 이름 지어주고 버켓생성하기~
    • 버켓 생성 후 Upload files 클릭해서 아까 추출한 CSV 파일을 올린다.
  • Cloud SQL 생성해서 CSV 파일 넣어주기
    • Navigation menu > SQL
    • 인스턴스 생성 클릭
    • MySQL 을 데이터베이스 엔진으로 선택
    • Console에서 데이터베이스와 테이블 생성
      • gcloud sql connect qwiklabs-demo --user=root
      • CREATE DATABASE bike;
      • CREATE TABLE london1 (필드명 1 VARCHAR(255), 필드명 INT ...)
      • USE bike;
      • CREATE TABLE london1;
      • 여기까지 하면 데이터를 부을 준비가 완료된 것임,
    • Cloud SQL 인스턴스 페이지에서 IMPORT 클릭
    • 아까 생성한 CSV 파일을 넣어주고 만들어둔 데이터베이스와 테이블을 선택한다. 
    •  Import 해주면 완성!

'TIL (Today I Learned)' 카테고리의 다른 글

Redis  (0) 2021.12.08
Docker mac에 설치해서 컨테이너 실행해보기 / Docker 문법  (0) 2021.08.04
Docker 도커가 대체 뭐야 ㅠㅠ  (0) 2021.08.03
Google Kubernetes Engine(GKE)  (1) 2019.10.15
NGINX  (0) 2019.10.15
  • Google Kubernetes Engine(GKE)은 Google 인프라를 사용하여 컨테이너형 애플리케이션을 배포, 관리 및 확장할 수 있는 관리 환경을 제공한다. Kubernetes Engine 환경은 컨테이너 클러스터를 형성하기 위해 그룹화된 여러 개의 기계(특히 Google Compute Engine 인스턴스)로 구성된다. 
  • Kubernetes 명령과 리소스를 사용하여 애플리케이션을 배포 및 관리하고, 관리 작업을 수행하고 정책을 설정하고, 배포된 워크로드의 상태를 모니터링 할 수 있다.
  • Kubernetes Engine cluster를 사용하면 Google 클라우드에서 제공하는 아래 기능을 활용할 수 있다. 
    • Load-balancing
    • Node Pools (클러스터 내의 노드 하위 세트를 지정하는 역할)
    • Automatic scaling
    • Automatic upgrades
    • Node auto-repair
    • Logging and Monitoring
  • GKE를 사용하여 컨테이너 생성, 애플리케이션 배포를 해봅시다!

 

'TIL (Today I Learned)' 카테고리의 다른 글

Redis  (0) 2021.12.08
Docker mac에 설치해서 컨테이너 실행해보기 / Docker 문법  (0) 2021.08.04
Docker 도커가 대체 뭐야 ㅠㅠ  (0) 2021.08.03
BigQuery - Cloud SQL , CSV 파일  (0) 2019.10.18
NGINX  (0) 2019.10.15

TIL인 만큼 짧은 메모 형식으로만 기록하겠다.

 

Google Quick Lab에 참여하는 도중 NGINX란 단어가 나와 조금 찾아보았다. 

  • 엔진 X라고 읽음
  • Web Server , FTP, EMAIL 기능을 가진다. 
  • 클라이언트 요청에 응답하기 위해서 비동기 이벤트 기반의 구조를 가지고 작동하는데, 아파치 웹서버의 경우는 스레드/프로세스 기반의 구조를 가진다. 
  • Web Server ( = HTTP SERVER)
    • 서버쪽에서 데이터를 전달하는 소프트웨어
    • HTTP 요청을 처리할 수 있는 서버
  • Apache에 비해 더 빠르게 데이터를 제공한다. -> 경량화된 Web Server
  • 핵심은? 빠르다!

내가 현재 듣는 Quick Lab은 GCP ESSENTIAL 의 'CREATING A VIRTUAL MACHINE'이다.

Google Compute Engine은 다양한 OS를 실행하는 가상머신을 만들고 나서, NGINX web server를 요 가상머신에 연결시킨다. 

 

톰캣으로 웹 서버를 만든다고 하면 나는 아파치 웹서버를 썼다고 말할 수 있는 건가?

-> 톰캣에 아파치의 기능이 포함되어 있군..!

 

우선, 다른 사이트에 나온 내용 중 이해하는 데 도움된 내용이 있어서 정리할 겸 적어봤다. 

 

Web Server는 정적인 요청을 처리하는 서버이다. 

Web Application Server 는 동적인 요청을 처리하고, JSP와 Servlet이 실행될 수 있는 환경을 제공한다. 웹서버로부터 요청이 오면 컨테이너가 받아서 처리하고, 컨테이너는 web.xml을 참조하여 해당 서블릿에 대한 쓰레드를 생성한 다음 httpServeletRequest와 httpServletResponse 객체를 생성하여 전달한다. 컨테이너는 서블릿을 호출한다. 호출된 서블릿의 작업을 담당하게 된 쓰레드는 doPost()와 doGet()을 호출하여 이 메소드를 통해 동적페이지를 response객체에 담아 컨테이너에 전달하며, 컨테이너는 전달받은 response객체를 http response 형태로 바꾸어 웹서버에 전달하고 생성된 쓰레드를 종료하고 httpServletRequest, httpServletResponse 객체를 소멸시킨다.  WAS가 처리한 걸 웹서버가 받아서 응답해준다. (출처 : https://jeong-pro.tistory.com/84)

 

+ Recent posts