-
TIL(22일차)(2021.11.12)TIL(Today I Learned) 2021. 11. 12. 14:22
Spring Framework의 장점📌
-> 객체지향 설계가 가능
-> 인터페이스를 지정하고 구현체를 사용자 임의대로 바꿀 수 있음.(DI 덕분에)
-> 즉, memberService는 memberRepository를 의존하고 있고, 구현체로 memoryMemberReposotory와 , jdbcMemberRepository가 있다고 가정했을 때
-> 사용자 임의대로 memoryMemberRepository를 삭제하고 jdbcMemberRepository로 구현할 수 있다.
-> 이는, SOLID에서 O(OCP, Open-Closed Principle) 즉, 개방-폐쇄의 원칙을 만족시킨다.
-> 확장에는 열려있고, 수정에는 닫혀있다. 왜냐하면 기존 코드는 손대지 않고 새로운 jdbcMemberRepository를 새로 구현한뒤에 추가할 때
-> memberRepository 인터페이스 구현체를 살짝만 수정해도 되기 때문이다.JDBC(Java DataBase Connectivity) 📌
-> java에서 데이터베이스와 연결하기 위한 드라이버
//build.gradle implementation 'org.springframework.boot:spring-boot-starter-jdbc' runtimeOnly 'com.h2database:h2'
-> DB와 연결하기위해 dependencies에 추가
//HelloSpringApplicationTests spring.datasource.url=jdbc:h2:tcp://localhost/~/test spring.datasource.driver-class-name=org.h2.Driver spring.datasource.username=sa
-> 경로 지정
-> buildGradle에 가서 Load Gradle Changes 클릭.preparedStatement 📌
-> 객체를 캐시에 담아 재사용한다.
-> 반복적으로 사용한다면 statement에 비해 성능이 좋다.
-> secure coding에 나와있듯이 statement보다 보안성이 좋다.
-> statement는 sql 쿼리문을 작성할 때, 변수값을 사용하지만
-> preparedStatement는 변수값 대신 ?를 사용한다.statement
String sql = "INSERT into member(name) VALUES('"name"')";
preparedStatement
String sql = "INSERT into member(name) VALUES(?)";
e.printStackTrace(); 📌
-> 에러의 발생근원지를 찾아서 단계별로 에러 출력한다.
-> 상세한 에러 내역을 확인할 수 있어서 유용하다.
-> log4에서는 사용할 수 없다.
-> 때문에 log.error("error:",e);로 선언해줘야한다.e.printStackTrace(); 예시
try{ if(conn !== null){ close(conn); } catch(SQLException e) { e.printStackTrace(); } }
log4에서 e.printStackTrace(); 예시
try { //.. } catch(Exception e){ StackTraceElement[] elem = e.getStackTrace(); for(int i = 0; i<elem.length; i++) logger.error(elem[i]); }
spring integration Test 📌
-> spring + database + test를 한변에 통합해서 테스트
-> 단점 : 속도가 느리다.
-> 더 좋은 테스트 방식은 더 잘게 쪼개서 단위테스트를 하는것이 바람직함.
-> Configuration에 선언된 spring bean으로 구현한 spring container에 있는 객체들을 가져다가 쓴다.@SpringBootTest Annotation
-> 스프링 컨테이너와 테스트를 함께 실행한다.
@Transactional Annotation
-> 테스트 시작 전에 트랜잭션을 시작하고(각각의 메소드마다), 테스트 완료 후에 항상 롤백한다.
-> 이렇게하면 DB에 데이터가 남지 않으므로, 다음 테스트에 영향을 주지 않는다.
-> AfterEach Annotation 구현과 비슷한 기능이다.
-> 트랜잭션을 통해 회원 중복 테스트 , 반복 테스트, 회원 join 테스트 등을 수행할 수 있다.
-> 트랜잭션이 서비스에 선언되면 롤백하지 않고 정상적으로 돌고, 테스트에 붙을 때만 롤백한다.JdbcTemplate와 Mybatis 라이브러리 📌
-> JDBC API에서 사용되는(아주 오래된 방식의 코드) 반복 코드를 대부분 제거해준다.
-> 하지만 SQL은 직접 작성해야한다.
-> injection을 받을 수 없다. 즉, DI가 불가능하다.
-> DataSource(DB와 연결할 때 선언해주는..)를 통해 injection 문제를 해결
-> 손쉽게 DB와 연동할 수 있도록 구현되어 있다.JdbcTemplate 선언
//JdbcTemplateMemberRepository private final JdbcTemplate jdbcTemplate; public JdbcTemplateMemberRepository(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); }
스프링 빈 수정
//SpringConfig @Bean public MemberRepository memberRepository(){ // return new MemoryMemberRepository(); return new JdbcTemplateMemberRepository(dataSource); }
-> return new JdbcTemplateMemberRepository(dataSource); 추가
DataSource
private final DataSource dataSource; public SpringConfig(DataSource dataSource) { this.dataSource = dataSource; }
-> DataSource를 통해 DB connection을 획득한다.
-> 스프링부트는 데이터베이스 커넥션 정보를 바탕으로 DataSource를 생성하고
-> 스프링 빈으로 만들어 DI를 받을 수 있게된다.stream() 📌
-> 람다에서 사용하는 메서드.
-> '데이터의 흐름'
-> 배열 또는 컬렉션 인스턴스를 함수형으로 처리 가능
-> 람다를 사용하여 코드의 양을 줄이고 간결하게 표현할 수 있다.
-> 병렬처리 가능(multi-threading)
-> List로 반환할 수 있다.RowMapper 📌
-> 원하는 형태의 결과값을 반환할 수 있다.
-> SELECT로 나온 여러개의 값을 반환할 수 있을 뿐만 아니라
-> 사용자가 원하는 형태로도 바꿀 수 있다.
-> 람다식으로 코드를 간결하게 만들 수 있다.
-> RowMapper는 과거 순수 JDBC에서 ResultSet으로 값을 받고
-> 객체에 담아서 반환하는 과정을
-> 간결하고 짧게 구현할 수 있게 해준다.
-> 즉, 쿼리날려준걸 맵핑해준다.//JdbcTemplateMemberRepository private RowMapper<Member> memberRowMapper(){ return (rs, rowNum) -> { Member member = new Member(); member.setId(rs.getLong("id")); member.setName(rs.getString("name")); return member; }; }
JPA(Java Persistence API)📌
-> JdbcTemplate도 코드가 짧고 간결해졌지만, SQL문 쿼리를 직접 작성해야한다는 단점이있다.
-> 이를 JPA가 해결해준다.
-> JPA는 기존의 반복 코드도 실행해준다.
-> JPA를 사용하면 SQL과 데이터 중심의 설계에서, 객체 중심의 설계로 패러다임을 전환할 수 있다.
-> JPA를 사용하면 개발 생산성을 크게 향상시킬 수 있다.
-> 객체랑, ORM을 이용하는 인터페이스이다.(ORM: Object Relational Mapping)//build.gradle implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
-> dependencies에 추가
-> 입력후 Load Gradle Changes 클릭(라이브러리 다운로드)//application.properties spring.jpa.show-sql=true //jpa에서 sql문 확인 가능하게 해줌 spring.jpa.hibernate.ddl-auto=none //none이 아닌 create로 선언하면 DB column 객체를 보고 자기가 테이블을 자동으로 생성함.
//Member.java @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
-> IDENTITY는 컬럼의 ID값을 자동으로 생성하고 증가 시키는것을 의미한다.
-> 본 구현에서는 자동으로 ID가 상승하도록(++sequence) or (h2database 성질) 설정해주었기 때문에 IDENTITY를 선언해준다.
-> DB가 알아서 생성해주는것을 IDENTITY라고 한다.//JpaMemberRepository private final EntityManager em; public JpaMemberRepository(EntityManager em) { this.em = em; }
-> 위에서 build.gradle에 선언한
-> implementation 'org.springframework.boot:spring-boot-starter-data-jpa'가 자동으로
-> EntityManager를 선언할 수 있게 해줌.
-> EntityManager를 통해 JPA를 컨트롤함
-> application.properties와 DB Connection에 들어있는 정보랑 섞어서 자동으로 EntityManager를 만들어준다.
-> EntityManager를 통해 DB와의 통신을 내부적으로 처리한다.
-> 결론 JPA를 사용하려면 EntityManager를 주입받아야한다.@Transaction @Commit
-> 트랜잭션 어노테이션을 사용할 때, 모든 값을 롤백해주는데,
-> 이때, 롤백하기 싫다면, Commit 어노테이션을 사용하면 값이 정상적으로 저장된다.@Override public Member save(Member member) { em.persist(member); return member; }
-> jpa em을 이용한 선언 방식
-> persistence : 영속적
-> 즉, 영속적으로 save한다.라는 의미//JpaMemberRepository @Override public List<Member> findAll() { return em.createQuery("select m from Member m", Member.class) .getResultList(); }
-> JPQL
-> 객체를 대상으로 쿼리를 날림@Transactional public class MemberService {
-> JPA 사용할 때는 @Transaction을 추가해줘야한다(JPA는 트랜잭션 안에서 실행되어야함).
//springConfig.java private EntityManager em; @Autowired public SpringConfig(EntityManager em) { this.em = em; } return new JpaMemberRepository(em);
-> spring환경을 JPA로 돌아가도록 설정.
-> EntityManager를 선언해서 DI'TIL(Today I Learned)' 카테고리의 다른 글
TIL(24일차)(2021.11.14) (0) 2021.11.14 TIL(23일차)(2021.11.13) (0) 2021.11.13 TIL 21일차(11.11) (0) 2021.11.11 TIL 20일차 (2021.11.10) (0) 2021.11.10 TIL 19일차(2021.11.09), 단축키 TIP 모음, intellij create git (0) 2021.11.09