[스프링 입문] 스프링 예제 프로젝트 PetClinic 4

22372 단어 SpringSpring

Portable Service Abstraction
Service Abstraction ?

스프링 PSA

  • 예제(PetClinic)에서는 아래와 같이 Servlet을 형성하지 않는다.

    // /owner/create
    public class OwnerCreateServlet extends HttpServlet {
    
    	// GET
    	@Override
    	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    		super.doGet(req, resp);
    	}
    
    	// POST
    	@Override
    	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    		super.doPost(req, resp);
    	}
    }
  • 예제(PetClicin)에서는 아래와 같이 형성한다.

    • main\java\org\owner\OwnerController

      	@GetMapping("/owners/new")
      	@LogExecutionTime
      	public String initCreationForm(Map<String, Object> model) {
      		Owner owner = new Owner();
      		model.put("owner", owner);
      		return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
      	}
      
      	@PostMapping("/owners/new")
      	@LogExecutionTime
      	public String processCreationForm(@Valid Owner owner, BindingResult result) {
      		if (result.hasErrors()) {
      			return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
      		}
      		else {
      			this.owners.save(owner);
      			return "redirect:/owners/" + owner.getId();
      		}
      	}

      @GetMapping@PostMapping을 이용.

    • @을 사용했지만 그 아래 기반에는 서블릿 기반의 코드가 동작한다. (추상화 계층 사용)

  • PSA 사용 이유 : 참고 사이트


스프링 웹 M(odel) V(iew) C(ontroller)

  • @Controller를 사용하면 요청을 맵핑(@RequestMapping(@GetMapping @PostMapping 등))

    private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
    
    @GetMapping("/owners/new") //Controller
    @LogExecutionTime
    public String initCreationForm(Map<String, Object> model) {
    	Owner owner = new Owner(); //Model
    	model.put("owner", owner);
    	return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; //View
    }
    • /owners/new와 같은 URL에 해당하는 요청이 들어왔을때, Method가 처리하도록 매핑(GetMapping)
    • MVC가 무엇에 해당하는지 꼭 확인하기.
  • P(ortable)이 붙은 이유 : 여러 기술을 다른 것으로 변화 가능하다.

    • Spring에서 제공하는 추상화 인터페이스 기능을 쓰지만 (아래)

      <dependency>
      	<groupId>org.springframework.boot</groupId>
      	<artifactId>spring-boot-starter-webflux</artifactId>
      </dependency>
    • (위) 의존성을 추가하면 톰캣이 아닌 네티와 같은 서버에서도 Spring 기반의 프로그래밍이 구현된다.

    • 결론 : Servlet/Reactive 를 선택할 수 있으며, 톰캣/네티/언더로우 등 서버 또한 바꿀 수 있다. !코드를 거의 변경하지 않고!


스프링 트랜잭션

  • 트랜잭션 : 데이터의 하나의 작업 단위(처음부터 끝까지)

    • 원자성(Atomicity) : 트랜잭션과 관련된 작업들이 부분적으로 실행되다가 중단되지 않는 것을 보장
    • 일관성(Consistency) : 트랜잭션이 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 유지
    • 고립성(Isolation) : 트랜잭션을 수행 시 다른 트랜잭션의 연산 작업이 끼어들지 못하도록 보장
    • 지속성(Durability) : 성공적으로 수행된 트랜잭션은 영원히 반영
  • 아래의 코드를 보자. (Low Level의 트랙잭션 처리)

    import java.math.BigDecimal;
    import java.sql.*;
    import java.time.LocalDateTime;
    
    public class TransactionExample {
    
        public static void main(String[] args) {
    
            try (Connection conn = DriverManager.getConnection(
                    "jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password");
                 Statement statement = conn.createStatement();
                 PreparedStatement psInsert = conn.prepareStatement(SQL_INSERT);
                 PreparedStatement psUpdate = conn.prepareStatement(SQL_UPDATE)) {
    
                statement.execute(SQL_TABLE_DROP);
                statement.execute(SQL_TABLE_CREATE);
    
                // start transaction block
                conn.setAutoCommit(false); // default true
    
                // Run list of insert commands
                psInsert.setString(1, "mkyong");
                psInsert.setBigDecimal(2, new BigDecimal(10));
                psInsert.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now()));
                psInsert.execute();
    
                psInsert.setString(1, "kungfu");
                psInsert.setBigDecimal(2, new BigDecimal(20));
                psInsert.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now()));
                psInsert.execute();
    
                // Run list of update commands
    
                // error, test roolback
                // org.postgresql.util.PSQLException: No value specified for parameter 1.
                psUpdate.setBigDecimal(2, new BigDecimal(999.99));
                //psUpdate.setBigDecimal(1, new BigDecimal(999.99));
                psUpdate.setString(2, "mkyong");
                psUpdate.execute();
    
                // end transaction block, commit changes
                conn.commit();
    
                // good practice to set it back to default true
                conn.setAutoCommit(true);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //...
    }
    • conn.setAutoCommit(false); : sql이 여러번 날아가더라도 커밋을 하지 않는다.
    • ~~ conn.commit(); : ~~ 코드를 마치고 커밋.
  • 스프링의 @Transactional : Annotation이 붙어 있는 Method는 따로 트랜잭션 처리를 하지 않아도 된다.

    • 결론 : JpaTransacionManager | DatasourceTransactionManager | HibernateTransactionManager 등 사용 가능하다. !코드의 변경 없이!
    • 참고 사이트

스프링 캐시

  • @Cacheable (@CacheEvit... 등) 를 활용하여 자신의 코드(메소드) 를 변경하지 않고 CacheManager를 적용할 수 있다.

좋은 웹페이지 즐겨찾기