ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [๊ฐ•์˜] ์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB์ ‘๊ทผ ๊ธฐ์ˆ  3
    SPRING/INFLEARN 2021. 4. 5. 20:54

    ์Šคํ”„๋ง ๊ณต๋ถ€~

    inf.run/reCZ

     

    [๋ฌด๋ฃŒ] ์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB ์ ‘๊ทผ ๊ธฐ์ˆ  - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

    ์Šคํ”„๋ง ์ž…๋ฌธ์ž๊ฐ€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ์Šคํ”„๋ง ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ์ „๋ฐ˜์„ ๋น ๋ฅด๊ฒŒ ํ•™์Šตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., ์Šคํ”„๋ง ํ•™์Šต ์ฒซ ๊ธธ์žก์ด! ๊ฐœ๋ฐœ ๊ณต๋ถ€์˜ ๊ธธ์„ ์žƒ์ง€ ์•Š๋„๋ก ๋„์™€๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๐Ÿ“ฃ ํ™•์ธํ•ด์ฃผ์„ธ

    www.inflearn.com

     

    ์ถœ์ฒ˜ : inf.run/reCZ ๊ฐ•์˜

     

    6.์Šคํ”„๋ง DB ์ ‘๊ทผ ๊ธฐ์ˆ 

    - H2 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์น˜

    ๋น„๋šซ์–ด์ง ์ฃผ์˜ ์•„๋ž˜๊ฑธ ๋‹ค์šด๋ฐ›์œผ์„ธ์—ผ ์ƒ๊ด€ ์—†๋‹ค๊ณ ๋Š” ํ•˜๋˜๋ฐ ๋‚œ ์œ„์—๊ฑฐ ๋ฐ›์œผ๋‹ˆ๊นŒ ์•ˆ๋˜๋˜๋ฐ
    ๋ฐ›์€ ํŒŒ์ผ์„ ์••์ถ•์„ ํ’€์–ด์„œ ๋ฉ‹์ง„ ์œ„์น˜์— ๋‘๊ณ  bin\h2.bat์„ ์‹คํ–‰ํ•œ๋‹ค. ./h2.sh๋Š” ์œˆ๋„์šฐ๊ฑฐ๊ฐ€ ์•„๋‹ˆ๋‹ˆ ์œˆ๋„์šฐ๋ผ๋ฉด ๋ฐ”๋ณด์ฒ˜๋Ÿผ ์ €๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•œ๋‹ค.
    ํ•˜๊ณ  ๋‚˜๋ฉด ์š”๋Ÿฐ ์ฐฝ์ด ๋œฌ๋‹ค

    ์—ฐ๊ฒฐํ•ด๋ณด๊ณ 

    cmd ๋“ค์–ด๊ฐ€์ž๋งˆ์ž dir๋กœ ์ €๊ฑฐ ์ƒ๊ฒผ๋‚˜ ํ™•์ธ
    ์•ˆ๋ ๊ฒฝ์šฐ์—” ๋…ธ๋ž€ ๋ถ€๋ถ„์„ localhost๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค

    insert into member(name) values('spring') - "์•„๋‹ˆ๊ณ  '์ธ๊ฑฐ ์ฃผ์˜, ์ด๊ฑธ๋กœ ์ด๋ฆ„์„ ๋„ฃ์–ด ๋ณด์•˜๋‹ค

    ํ˜ธํ˜ธ ์ž˜ ๋‚˜์˜จ๋‹ค

     

     

    - ์ˆœ์ˆ˜ JDBC

    ์˜ˆ์ „์— ์‚ฌ์šฉ - ์ฐธ๊ณ ๋งŒ ํ•˜๊ณ  ๋„˜์–ด๊ฐ€์ž

    ๊ธฐ์กด์˜ ์ฝ”๋“œ๋Š” ํ•˜๋‚˜๋„ ์†๋Œ€์ง€ ์•Š๊ณ  SpringConfig.java๋งŒ ์†๋Œ€์„œ ๊ฐˆ์•„๋ผ์šธ ์ˆ˜ ์žˆ๋‹ค.

    ๊ฐœ๋ฐฉ-ํŒจ์‡„ ์›์น™ : ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ , ์ˆ˜์ •, ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ๋‹ค. 

    ์ถ”๊ฐ€ ์ฝ”๋“œ

    build.gradle์— ์ถ”๊ฐ€

    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    runtimeOnly 'com.h2database:h2'

    application.properties์— ์ถ”๊ฐ€

    spring.datasource.url=jdbc:h2:tcp://localhost/~/test
    spring.datasource.driver-class-name=org.h2.Driver
    spring.datasource.username=sa
    //๊ณต๋ฐฑ ๋ชจ๋‘ ์ œ๊ฑฐ!!

    JdbcMemberRepository.java

     

    ํ•ด๋ณด๋‹ˆ๊นŒ ์ž˜ ๋‚˜์™”๋‹ค!

     

    - ์Šคํ”„๋ง ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

    @SpringBootTest : ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ํ…Œ์ŠคํŠธ ํ•จ๊ป˜ ์‹คํ–‰. ์ •๋ง spring์ด ๋Œ์•„๊ฐ

    ์ˆœ์ˆ˜ ์ž๋ฐ” ์ฝ”๋“œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ vs ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

    ์ „์ž๊ฐ€ ์ข‹์„ ํ™•๋ฅ ์ด ๋†’๋‹ค. ๋น ๋ฅด๊ธฐ ๋•Œ๋ฌธ ์›ฌ๋งŒํ•˜๋ฉด ์ „์ž๋กœ ๊ฐ€์ž

    @Transactional : ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ์ „์— ํŠธ๋ Œ์ ์…˜ ์‹œ์ž‘, ์™„๋ฃŒ ํ›„ ๋กค๋ฐฑ. DB์— ๋‚จ์ง€ ์•Š๋Š”๋‹ค.

    //MemberServiceIntegrationTest.java
    @SpringBootTest
    @Transactional //->์—†์œผ๋ฉด DB์— ์Œ“์ธ๋‹ค(๋ฐ˜๋ณต๋ถˆ๊ฐ€)
    public class MemberServiceIntegrationTest {
    
    
        //์ง์ ‘ ๊ฐ์ฒด ๋งŒ๋“ค๊ธฐ -> contructor ๊ฐ€์ง€๊ณ  ํ•˜๊ธฐ
        @Autowired MemberService memberService;
        @Autowired MemberRepository memberRepository;
    
        //AfterEach๋„ ํ•„์š” x
    
        @Test
        void ํšŒ์›๊ฐ€์ž…() { //ํ•œ๊ธ€๋กœ ํ•ด๋„ ๋œ๋‹ค!
            //given ์ƒํ™ฉ์ด ์ฃผ์–ด์ง
            Member member = new Member();
            member.setName("spring");
    
            //when ์ด๊ฑธ๋กœ ์‹คํ–‰ํ•จ
            Long saveId = memberService.join(member);
    
            //then ์ด๋Ÿฐ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ด
            Member findMember = memberService.findOne(saveId).get();
            assertThat(member.getName()).isEqualTo(findMember.getName());
        }
        //์‹คํ–‰ ํ…Œ์ŠคํŠธ์ธ๋ฐ๋„ spring์ด ๋œฌ๋‹ค!
    
        @Test
        public void ์ค‘๋ณต_ํšŒ์›_์˜ˆ์™ธ(){
            //given
            Member member1 = new Member();
            member1.setName("spring");
            Member member2 = new Member();
            member1.setName("spring");
    
            //when
            memberService.join(member1);
            /*1)
            try {
                memberService.join(member2);
                fail(); //fail์—์„œ ๊ณ„์† ์˜ค๋ฅ˜๋‚จ ์ด์œ  ์•Œ์•„๋‚ผ ๊ฒƒ
            }catch(IllegalStateException e){
                assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
            }*/
            //2)
            IllegalStateException e = assertThrows(IllegalStateException.class,
                    () -> memberService.join(member1));
    
            //then
    
        }
    }
    

     

    - ์Šคํ”„๋ง JDBCTemplate

    ๋ฐ˜๋ณต ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•ด์ค€๋‹ค.

    //JdbcTemplateMemberRepository.java
    public class JdbcTemplateMemberRepository implements MemberRepository{
    
        private final JdbcTemplate jdbcTemplate;
    
        //@Autowired ์ƒ์„ฑ์ž๊ฐ€ ํ•˜๋‚˜์ผ ๊ฒฝ์šฐ ์ƒ๋žต ๊ฐ€๋Šฅ
        public JdbcTemplateMemberRepository(DataSource dataSource) {
            jdbcTemplate = new JdbcTemplate(dataSource);
        }
    
        @Override
        public Member save(Member member) {
            SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
            jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");
    
            HashMap<String, Object> parameters = new HashMap<>();//!!!
            parameters.put("name", member.getName());
    
            Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters));
            member.setId(key.longValue());
            return member;
        }
    
        @Override
        public Optional<Member> findById(Long id) {
            List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
            return result.stream().findAny();
        }
    
        @Override
        public Optional<Member> findByName(String name) {
            List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
            return result.stream().findAny();
        }
    
        @Override
        public List<Member> findAll() {
            return jdbcTemplate.query("select * from member", memberRowMapper());
        }
    
        private RowMapper<Member> memberRowMapper() {
            return (rs, rowNum) -> { //new RowMapper<Member>()
                Member member = new Member();
                member.setId(rs.getLong("id"));
                member.setName(rs.getString("name"));
                return member;
            };
        }
    }

    ์ฝ”๋“œ๊ฐ€ ์ˆœ์ˆ˜ jdbc๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ด์ง„ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

     

    ์•„๊นŒ ๋งŒ๋“  MemberServiceIntegrationTest.java๋กœ ํ…Œ์ŠคํŠธ๋„ ํ•ด๋ณด์ž! ๋‚œ ์ž˜๋๋‹ค.

     

     

    - JPA

    ๊ฐ์ฒด๋ฅผ ๋ฐ”๋กœ DB์— Query์—†์ด ์ €์žฅ, ๊ด€๋ฆฌ ๊ฐ€๋Šฅ

    JDBCํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ๋งค์šฐ ๊ฐ„๊ฒฐํ•ด์กŒ์ง€๋งŒ ๊ฒฐ๊ตญ SQL์€ ์ง์ ‘ ์งœ์•ผํ•œ๋‹ค -> ์ด ๋ฌธ์ œ ํ•ด๊ฒฐ JPA ์ƒ์‚ฐ์„ฑ ์—…!

     

    ์ถ”๊ฐ€ ์ฝ”๋“œ

    build.gradle์— ์ถ”๊ฐ€

    //implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    application.properties์— ์ถ”๊ฐ€

    spring.jpa.show-sql=ture
    spring.jpa.hibernate.ddl-auto=none
    //domain.Member.java์— @์ถ”๊ฐ€
    @Entity
    public class Member {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;//id ์‹๋ณ„์ž, ์‹œ์Šคํ…œ์ด ์ž๋™ ์ €์žฅ
        
        //๋งŒ์•ฝ DB ๋ณ€์ˆ˜๋ช…์ด name์ด ์•„๋‹ˆ๋ผ๋ฉด, @Column(name = "username") ์œผ๋กœ ๋งตํ•‘
        private String name;//์ด๋ฆ„
        
    	...
        
    }
    //JpaMemberRepository.java
    public class JpaMemberRepository implements MemberRepository{
    
        private final EntityManager em;
    
        public JpaMemberRepository(EntityManager em) {
            this.em = em;
        }
    
        @Override
        public Member save(Member member) {
            em.persist(member); //์—ฌ๊ธฐ์„œ ๋ชจ๋“ ๊ฑธ ๋‹คํ•ด์คŒ
            return member;
        }
    
        @Override
        public Optional<Member> findById(Long id) {
            Member member = em.find(Member.class, id);
            return Optional.ofNullable(member);
        }
    
        @Override
        public Optional<Member> findByName(String name) {
            List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class)
                    .setParameter("name", name)
                    .getResultList();
            return result.stream().findAny();
        }
    
        @Override
        public List<Member> findAll() {
            return em.createQuery("select m from Member m", Member.class).getResultList();
            //Member entity๋ฅผ ์ƒ๋Œ€๋กœ Query๋ฅผ ๋‚ ๋ฆผ
        }
    }
    

    @Transactional ์ถ”๊ฐ€

    ์—ญ์‹œ MemberServiceIntegrationTest.java๋กœ ํ…Œ์ŠคํŠธ ๋Œ๋ ค๋ดค๋Š”๋ฐ ์ž˜๋จ.

     

     

    - ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA

    JPA๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋„๋ก ํ•œ ๋ฒˆ ๊ฐ์‹ผ ๊ธฐ์ˆ 

    interface๋งŒ์œผ๋กœ ๊ฐœ๋ฐœ์„ ์™„๋ฃŒํ•  ์ˆ˜ ์žˆ๋‹ค.

    //SpringDataJavaMemberRepository.java
    public interface SpringDataJavaMemberRepository 
    extends JpaRepository<Member,Long>/*๋งŽ์€ ๋ฉ”์„œ๋“œ ์ œ๊ณต ๊ฐ€์ ธ๋‹ค์“ฐ๊ธฐ*/, MemberRepository {
        @Override
        Optional<Member> findByName(String name);
    }
    
    //SpringConfig.java
    @Configuration
    public class SpringConfig {
    
        private final MemberRepository memberRepository;
    
        @Autowired
        public SpringConfig(MemberRepository memberRepository) {
            this.memberRepository = memberRepository;
        }
    
    
        @Bean
        public MemberService memberService() {
            return new MemberService(memberRepository);
        }
        
    }

    ์˜›๋ฒ„์ „์ด๋ผ ์•ฝ๊ฐ„์˜ ์ฐจ์ด๋Š” ์žˆ๋‹ค.

     

    7.AOP

    - AOP๊ฐ€ ํ•„์š”ํ•œ ์ƒํ™ฉ

    //MemberService.java
    @Transactional
    public class MemberService {
    
        ...
    
        //ํšŒ์›๊ฐ€์ž…
        public Long join(Member member){
            long start = System.currentTimeMillis();
            try {
                //๊ฐ™์€ ์ด๋ฆ„ ์ค‘๋ณตํšŒ์› x
                validateDuplicateMember(member);
                memberRepository.save(member);
                return member.getId();
            } finally {
                long finish = System.currentTimeMillis();
                long timeMs = finish - start;
                System.out.println("join = " + timeMs + "ms");
            }
        }
    
       ...
    
        //์ „์ฒด ํšŒ์› ์กฐํšŒ
        public List<Member> findMembers(){
            long start = System.currentTimeMillis();
            try {
                return memberRepository.findAll();
            }finally {
                long finish = System.currentTimeMillis();
                long timeMs = finish - start;
                System.out.println("findMembers " + timeMs + "ms");
            }
        }
    
        ...
    }
    

    ์‹œ๊ฐ„ ์•„์ฃผ ์ž˜๋œธ. ใ…—ใ…‘ ๋Š” ๋‚ด๊ฐ€ ์ด๋ฆ„์„ ์•„๋ฌด๋ ‡๊ฒŒ ๊ทธ๋ ‡๊ฒŒ ์ ์—ˆ๋Š”๋ฐ... ์ข€ ์ •์ƒ์ ์œผ๋กœ ์ ์„๊ฑธ

    ํ•˜์ง€๋งŒ ํ•ต์‹ฌ ๋กœ์ง๊ณผ ๊ณตํ†ต ๊ด€์‹ฌ ์‚ฌํ•ญ(์‹œ๊ฐ„ ์ธก์ •) ์ด ์„ž์—ฌ์žˆ์–ด ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๋‹ค.

     

    - AOP ์ ์šฉ

    ์•„๊นŒ ๋งŒ๋“  ์ง์ ‘ ์‹œ๊ฐ„์„ ํ”„๋ฆฐํŠธ ํ•˜๋˜ ์ฝ”๋“œ๋Š” ์ง€์šฐ๊ณ  ํ•ต์‹ฌ ๋กœ์ง๋งŒ ๋‚จ๊ฒจ๋†“๋Š”๋‹ค.

    //TimeTraceAop.java
    @Aspect
    /*1)*/@Component
    public class TimeTraceAop {
        @Around("execution(* hello.hellospring..*(..))")
        public Object excute(ProceedingJoinPoint joinPoint) throws Throwable{
            long start = System.currentTimeMillis();
            System.out.println("START : " + joinPoint.toString());
            try{
                return joinPoint.proceed();
            }finally {
                long finish = System.currentTimeMillis();
                long timeMs = finish - start;
                System.out.println("END : " + joinPoint.toString() + " " + timeMs + "ms");
            }
        }
    }
    /*2) SpringConfig.java์— ์ถ”๊ฐ€
        @Bean
        public TimeTraceAop timeTraceAop(){
            return new TimeTraceAop();
        }*/
    

    ๋„ˆ๋ฌด ์ž˜๋œ๋‹ค.

    ํ•ต์‹ฌ ๊ด€์‹ฌ ์‚ฌํ•ญ์„ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

    ํ”„๋ก์‹œ๋ผ๋Š” ๊ธฐ์ˆ ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๊ฐ€์งœ MemberService๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค. ์—ฌ๊ธฐ์„œ AOP๊ฐ€ ์‹คํ–‰๋˜๊ณ  ๋‚˜์ค‘์— joinPoint.proceed();๊ฐ€ ์ง„์งœ ๋ฐ๋ ค์˜ด

     

Designed by Tistory.