I. 웹개발
1. JDBC
(1) 트랜잭션
1)
트랜젝션
각각의 하나는 물리적 명령어이다
계좌이체는 사용자가 원하는 하나의 단위 -> 실행하려면 물리적으로 2번의 업데이트 필요!
서비스는 사용자가 원하는 일 + 이러한 일이 곳 업무단위 => 업무단위 실행하기 위해 물리적으로 여러개 명령어 실행가능
dao 는 CRUD 관련 함수로 구성되어있다
서비스레이어에는 업무라고 함수화 되어있음
업데이트 두번이 깨지면안되는, 즉 두개 다 정상적으로 실행되어야 완료된다.
계좌이체라는 업무단위를 한번에 실행해야되는 업무단위 (작게 진행되는 물리적단위)
트랜잭션 : 업무단위 or 논리적인 명령단위
이러한 업무는 한번에 실행되면 계좌이체가 완벽히 되어야하지만, 그 안에는 자잘하게 물리적으로 엮여야하는데 하나라도 안되면 업무단위가 깨져버린다. 고로 트랜잭션은 깨지면 아니된다.
2)
con.setAutoCommit => 내가 커넥션에 하면 실행하면 커밋자동으로 되지만 , false 하면 커밋안돼!
flase이면 con.commit() 을 하고, 실패했을 시 con.rollback()을 할수있게끔한다
3)
서비스가 트랜잭션, (업무로직) 처리해야하는데 그러면 깨지면 처리를 모두 취소한다.
(2) 트랜잭션 실습
1)
2가지가 달라진다
1 select 부분 / 2 데이터 담는부분 (mapping)
이거 만 하면 된다. 40개이면! 40번 반복하는면 돼!
이거를 해결하기 위해서 라이브러리 나옴 -> 스프링은 JDBC API / JPA 관련 어노테이션을 제공한다
2)
스프링의 2. 부터 지원해주던거 먼저 해보자!
데이터 소스를 객체화 작업을 해주자!
우리가 작성하는 것 중에 꼭 하는거 빼고 다 해주고있다.
쿼리문은 우리가 만드는게 동일하고, 연결소스 동일하다.
다만 쿼리문으로 데이터 담아주는 부분 while(rs.next()) 를 담아준다!
public class jdbcMenuRepository implements MenuRepository{
@Override
public List<Menu> findAll() {
//가져온다 : 라이브러리가 해결할 수 있는것이 아니기 때문!
String sql = "select id, name, price, regDate, categoryId from menu";
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("org.mariadb.jdbc.Driver"); //사용자 계정
dataSourceBuilder.url("jdbc:mariadb://db.newlecture.com:3306/rlanddb");
dataSourceBuilder.username("rland"); //이부분 바꿔주면 됨!
dataSourceBuilder.password("20220823");
DataSource dataSource = dataSourceBuilder.build();
JdbcTemplate template = new JdbcTemplate(dataSource);
List<Menu> list = template.query(sql, new BeanPropertyRowMapper(Menu.class));
return list;
}
3)
그런데 우리가
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("org.mariadb.jdbc.Driver"); //사용자 계정
dataSourceBuilder.url("jdbc:mariadb://db.newlecture.com:3306/rlanddb");
dataSourceBuilder.username("rland"); //이부분 바꿔주면 됨!
dataSourceBuilder.password("20220823");
DataSource dataSource = dataSourceBuilder.build();
JdbcTemplate template = new JdbcTemplate(dataSource);
이거를 거두어 낼 수 있다면 좋을 것 같다.
거둔다면 어디 둘꺼야? 같이 쓸수있는 공간에 둘거야
우리는 쪼개어서 개체 수가 많아지면 그것들이 각각이 아니라 합쳐서 쓸거야
뽑아내고 결합해서 쓰면 돼!
(3) 컨테이너
1)
하나를 생각하자 스프링은 커다란 컨테이너가 있다. 즉 IOC 라 한다
여기에 객체(Bean)를 담아두고 필요하면 뽑아쓴다.
스프링사용하는 모든 객체를 담는 것을 컨테이너라고하고, 여기 담긴 객체를 bean 이라고했다
bean 객체 혹은 자바객체라고 했다
bean 을 담는 컨테이라 하면 콩자루 이다.
그런데 bean컨테이너라고 하지않는다. IOC라고 해!
IOC 는 객체를 단순히 담았다 빼는게아니라, 결합했다가 뺄수도 있고!
컨테이너는 뺏는거 뿐만아니라 결합 까지도 설정 돼! (템플릿 주는거 뿐만아니라 소스껴서 줘!)
부품을 Dependency 라고해, 결합을 injection
의존성 주입보다는 부품을 결합! 한다고 생각하자
결합을 해주는데 부품(템플릿)하고 제품(데이터소스)이 있다.
2개 부품, 제품이 있다
결합은 어떤순서로 할까? 일반적으로 작은것 부터 차근차근 결합하는 방식이다
이런 결합방식을 조립되어주는 컨테이너라고 하는데, 이를 다르게말했다
조립품의 반대는 일체형이다. 생성자안에서 생성자(연속된 생성자)가 생성하는 일체형이 있다고 생각하자
사용자는 첫번째 A만 만들면되는데, 실제는 연속된 생성자안 중에서 생성자의 끝에서 부터 한다.
-
즉 제어의 역전은 부품부터 만들기 시작한다
- 참고로 SOLID 의 Inversion은 외부에서 와 여기에서 Inversion은 다르다. 그래서 외부라고 볼 수도 없다.
정리 : 제어의 역전이란 Spring이 컨테이너 가짐, 조립까지해줘!
즉 조립컨테이너 가지있고, 조립을 명령해서 달라 두가지가 가능해야한다.
2)
@ 이 붙으면, @을 붙인녀석이 콩자루(bean)을 붙여줘
@component 하면은 콩자루에 담을게! 라고하는거야
즉 특정 패키지(어플있는 패키지)가 있어!
여기다 클래스만들 때 클래스 위에다가 컴포넌트야 하고 @ 붙여주면 메모리 올라가고, 콩자루에 들어간다는 의미이다.
3)
-에러
콩자루 담을 때 설정해주어야하는데, 부트는 알아서 다해줘 그래서 설정다해버려서 url 알려줘 하는거야!
spring.datasource.u1rl=jdbc:mariadb://db.newlecture.com:3306/rlanddb
spring.datasource.d1river-class-name=org.mariadb.jdbc.Driver
spring.datasource.u1sername=rland
spring.datasource.p1assword=20220823
4)
@Component
public class jdbcMenuRepository implements MenuRepository{
@Component 이렇게 하면 콩자루에 담는다. 그래서 담으면 뭐해?? 더 조치를 해야해
DI 방법은 여러가지이다.
field injection / constructor injection / setter injection 등이있다
@Component
public class jdbcMenuRepository implements MenuRepository{
Component 를 뺴면은 아래과 같이 Autowired 할때 오류가 발생한다.
5)
이제 <MenuController.java>
여기다가 추가하면 된다.
myCookie = URLDecoder.decode(myCookie, "utf-8");
System.out.println(menuRepository.findAll());
System.out.println(myCookie);
이제 모든객체를 직접 만드는거야
이해가 어려운데 DI에 대해서 알아보자!
II. DI
1. 들어가며
DI는 결합을 의미하는 것이다.
(1) 의의
종속성 결합이 아니라 그냥 부품결합 이라고 생각하자!
좌측은 결합이 아니다 (injection X)
우측은 set으로 하는건데 이것을 종속성 결합이다 (injection O)
결합을 보며 A를 필요로 하는 애는 B를 생각안해, B는 'A가' 알아서 만드는거야
아래는 AB가 사용할수있으나 같이 탄생은 아냐, 다만 set과정이 필요해
비단 setter방식 뿐만 아니라 생성자 인젝션도 돼
3)
이렇게 인젝션 해주는 방식이 꼭 필요해!
2. 객체화와 결합
내가 만드는게 아니고, 만들어 달라하는 방식이다
1)
IoC 컨테이너를 만들고, 부품결합을 할거야!
이렇게 스프링에 주문서(XML 등)를 주어서 객체화 할것이다
객체화 -> 결합 -> 객체화 -> 결합 -> 객체화 -> 결합 -> 객체화 -> 결합
이런방식으로 제어의 역전을 한다
2)
어노테이션이 쉽지만, 이해를 위해서 XML을 써보자
3. Spring IoC 컨테이너 이용하기 (app Context 이용하기) : 스프링부트 X / IoC컨테이너 이해!
(1) context.xml 세팅
프라모델 작업 중 그만둘 때 이전꺼 남겨주고 싶을 때 프라모델 컨텍스트, 프로세스도 다른 담아두기 프로세스 컨텍스트
등 컨텍스트는 결국 작업하던것 담아두는 것일수도 있고 꺼낼 수도 있다
app Context 도 마찬가지로 도구함이다 ( = Ioc Contatiner)
2)
지시서(XML)에 사용자가 원하는것 기재할것임
XML파일을 만들고 (context.xml) XML 스키마 베이스를 넣자
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean definitions here -->
</beans>
그리고 bean 태그를 만들어서 거기다가 jdbc 패키지를 넣어주자
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean definitions here -->
<bean class="kr.co.rland.web.repository.jdbc.jdbcMenuRepository"/>
</beans>
이렇게 하면 객체를 만들어준다고?
3)
설정하고, applicationContext는 interface야 실제 applicationContext 종류는 다양해
차이가 없는데, 설정파일 어디에 두었느냐 따라 달라
현재 java프로그램 실행되는 클래스파일 위치면 classPathXml
Web이면 xmlWebApp 등 설정파일이 어디있느냐에 따라 달라져
(2) MenuRepository
1)
결국 우리는 같은 경로에있으니까 classPathXml 하자!
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class program {
public static void main(String[] args) {
ApplicationContext context
= new ClassPathXmlApplicationContext("context.xml");
}
}
2)
담은 것을 꺼내고 싶어?
public class program {
public static void main(String[] args) {
ApplicationContext context
= new ClassPathXmlApplicationContext("context.xml");
MenuRepository menuRepository = context.getBean(MenuRepository.class);
List<Menu> list = menuRepository.findAll();
System.out.println(list);
}
context.getBean() 을 쓰면된다.
3)
servlet의 application와 다른거야! 그런데 실행했는데,
이런 요류가 발생했다
classPath 는 root 인데, 현재 패키지 폴더와 거리가 있어! 디렉토리 설정해주자!
ApplicationContext context
= new ClassPathXmlApplicationContext("kr/co/rland/web/di/context.xml");
출력이 잘 된다.
4)
어떤 의미인지 설명한다. main함수 어디에도 jdbc 관련된게 없다.
스프링 도움 안받으면 이렇게 new 해주어야 한다
하지만 스프링 도움으로 객체 가져오면, 코드 수정없이 객체를 바꿀 수있어! (context.xml 을 수정!)
<bean class="kr.co.rland.web.repository.mybatis.MbMenuRepository"/>
package kr.co.rland.web.repository.mybatis;
import java.util.ArrayList;
import java.util.List;
import kr.co.rland.web.entity.Menu;
import kr.co.rland.web.repository.MenuRepository;
public class MbMenuRepository implements MenuRepository{
@Override
public List<Menu> findAll() {
// TODO Auto-generated method stub
return new ArrayList<Menu>();
}
}
(2) 리스트를 얻는 서비스
1)
리스트를 얻는 서비스를 만들자
우선 인터페이스를 만든다.
package kr.co.rland.web.service;
import java.util.List;
import kr.co.rland.web.entity.Menu;
public interface MenuService {
List<Menu> getList();
}
그리고 구현체를 만든다
package kr.co.rland.web.service;
import java.util.List;
import kr.co.rland.web.entity.Menu;
import kr.co.rland.web.repository.MenuRepository;
public class DefaultMenuService implements MenuService {
private MenuRepository repository;
@Override
public List<Menu> getList() {
return repository.findAll();
}
}
context에다가 서비스 객체를 객체화하는 작업을 한다
public class program {
public static void main(String[] args) {
ApplicationContext context
= new ClassPathXmlApplicationContext("kr/co/rland/web/di/context.xml");
// MenuRepository menuRepository = context.getBean(MenuRepository.class);
// List<Menu> list = menuRepository.findAll();
MenuService service = context.getBean(MenuService.class);
List<Menu> list = service.getList();
System.out.println(list);
}
}
하지만 실행결과
Null 관련 오류가 발생한다.
2)
private MenuRepository repository;
왜냐 여기에 변수만 선언했지, 객체를 만든적이 없어!
- 스프링 == IoC == applicationContext
Spring에서 xml 은 지시하는 지시서야, 지시는 객체생성, 객체결합 두가지가 있어
객체 생성은 bean에다가 클래스명 알려주면 보따리 담아줘!
3)
public class DefaultMenuService implements MenuService {
private MenuRepository repository;
public void setRepository(MenuRepository repository) {
this.repository = repository;
}
여기서 MenuRepository 는 interface에 불과하기 때문에 null이 발생한다
이런경우 구현체를 붙여주어야해
<bean name="repository" class="kr.co.rland.web.repository.mybatis.MbMenuRepository"/>
<bean class="kr.co.rland.web.service.DefaultMenuService">
<property name="repository" ref="repository" ></property>
</bean>
상단 bean의 MbMenuRepository 는 MenuRepository의 구현체이다.
이 이름을 가지고, property 에서 레퍼런스(ref)로서 이것을 담아준다.
name 으로 repository 를 넣어주면은 setRepository (즉 setter) 를 통해서 객체어서 연결시킨다.
4)
다음시간은 어노테이션방식으로 객체를 생성해서 연결하는 것을 해보자!
1. 보충
(1) IoC 컨테이너
What (정의) :
- IoC : 객체의 생성과 생명주기에 제어권을 개발자가 아닌 프레임워크에게 전이된것을 의미한다
- 컨테이너 : 생명주기 관리와 생성된 인스턴스에 추가적인 기능을 제공하는 것이다.
- IoC 컨테이너 : 객체를 생성, 관리, 책임지고 의존성 관리해주는 컨테이너이다. (= 스프링 컨테이너)
Why (존재이유) : 개발자는 로직에 집중 (POJO클래스)할 수있게 된다
(2) bean 객체
What (정의) : IoC 컨테이너가 생성한 객체를 bean객체라고 한다.
Why (존재이유) : 스프링 프레임웍에 의하여 관리당하는 객체임을 구분하기 위해서이다 (직접 new를 한게 아님)
How (방법) :
- IoC 컨테이너에 bean 객체 등록하는 방법 관련
자바 어노테이션을 사용하는 방법 / @Config, @Bean 을 이용하면 가능함
(3) applicationContext
What (정의) : 스프링에 의해 생성되고 관리되는 Bean객체를 얻기위한 것이다.
Why (존재이유) : spring Bean 을 얻기위한 것이다.
How (방법) : ApplicationContext.getBean() 메소드 이용한다.
2. 회고
1) 더욱더 연습하자!
'배움 __IL > TIL 1기' 카테고리의 다른 글
TIL : 62번째- 230304 [3-1-월] (0) | 2023.03.06 |
---|---|
TIL : 61번째- 230302 [2-4-목] (0) | 2023.03.02 |
TIL : 58번째- 230224 [2-3-금] (0) | 2023.02.24 |
TIL : 57번째- 230223 [2-3-목] (0) | 2023.02.23 |
TIL : 56번째- 230222 [2-3-수] (0) | 2023.02.22 |