728x90
300x250
[Spring-Framework] 34. Spring JDBCTemplate - 사용하기


사용 방법은 무척 간단하다.

pom.xml 등의 학습 지식이 없다면, 이전 글을 참고하면 좋겠다.


[작성 환경]

- IDE: Eclipse 2020-06
- Spring Framework 4.2.4 RELEASES




1. POM.xml 설정


https://mvnrepository.com/artifact/org.springframework/spring-jdbc

사이트에 접속해서 Spring-JDBC의 정보를 찾아서 pom.xml에 입력시켜 준다.

(중략)
  
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${org.springframework-version}</version>
  </dependency>


(중략)




2. 구현 부분

 

핵심만 밑줄로 표기하였다.



package com.website.example.board;

import java.sql.Date;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.website.example.common.MyDataSourceFactory;
import com.website.example.model.FoodMenuVO;
import com.website.example.model.FoodMenuViewVO;


public class BoardDAOSpring {
 
 // Spring Framework - JDBC
 private JdbcTemplate jdbcTemplate = null;
 
 private final String FOODMENU_INSERT = "insert into foodmenu_tbl(name, price, store_id, cnt, regidate) values(?, ?, ?, ?, ?)";
 private final String BOARD_UPDATE = "update board set subject=?, memo=? where id=?";
 private final String FOODMENU_DELETE = "delete foodmenu_tbl where id=?";
 private final String BOARD_GET = "select * from board where id=?";

 
 private final String BOARD_LIST = "SELECT * FROM ( " +
                "SELECT /*+ INDEX_DESC(Z OP_SAMPLE_PK) */ ROWNUM AS RNUM, Z.* FROM ( " +
                   "SELECT f1.id, f1.name, f1.price, f2.name as storename from foodmenu_tbl f1, foodstore_tbl f2 " +
                "where f1.store_id = f2.id order by f1.id desc " +
                ") Z WHERE ROWNUM <= ? " +
                ") WHERE RNUM >= ?";
 
      private final String BOARD_FULL_COUNT = "select count(*) from foodmenu_tbl f1, foodstore_tbl f2 where f1.store_id = f2.id";

      // 변형을 할 필요가 있음. (태스트용)

      public BoardDAOSpring() {

              MyDataSourceFactory sourceFactory = new MyDataSourceFactory();
              DataSource ds = sourceFactory.getOracleDataSource();

              this.jdbcTemplate = new JdbcTemplate(ds);
      }
 
      public List<FoodMenuViewVO> getList(){
 
          // 코드 간결하게 작성가능해짐.
          System.out.println("Spring JDBC - GetBoardList()");
         //return jdbcTemplate.query(BOARD_LIST, new BoardRowMapper());
  
          Object args[] = {10, 1};
  
          return jdbcTemplate.query(BOARD_LIST, args, new FoodMenuViewRowMapper());

       // return null;

     }
 
     public int getCount() {
  
          int result = 0;
          FoodMenuVO vo =  jdbcTemplate.queryForObject(BOARD_FULL_COUNT, new FoodMenuViewCntRowMapper());
          result = vo.getId();
  
          System.out.println("갯수:" + result);
  
         return result;
  
     }
 
      public void insertTest() {
  
          FoodMenuVO vo = new FoodMenuVO();

  
          // 약 10만 개
          // insert 후에 commit 할 것
          /*

          for(int j = 0; j < 2000 ; j++) {
                for ( int i = 0; i < 50; i++) {
   
                       vo.setName("하하하하1234" + i);
                       vo.setPrice(1000);
                       vo.setStore_id(1);
                       vo.setCnt(0);
                       vo.setRegidate(Date.valueOf("2020-01-03"));
                       vo.setStore_id(1);
    
                       jdbcTemplate.update(FOODMENU_INSERT, vo.getName(),
                              vo.getPrice(), vo.getStore_id(),
                              vo.getCnt(), vo.getRegidate());
    
                }
        }// end of if
  */
  
        vo.setName("야해해");
        vo.setPrice(1000);
        vo.setStore_id(1);
        vo.setCnt(0);
        vo.setRegidate(Date.valueOf("2020-01-05"));
        vo.setStore_id(1);
  
        Object[] args = {vo.getName(),
                 vo.getPrice(),
                 vo.getStore_id(),
                 vo.getCnt(),
                 vo.getRegidate()};

  
        jdbcTemplate.update(FOODMENU_INSERT, args);
  
 }
 

      // 글 삭제
      public void deleteFoodMenu(FoodMenuVO vo) {
  
             System.out.println("===> Spring JDBC로 deleteBoard() 기능 처리");
             jdbcTemplate.update( FOODMENU_DELETE, vo.getId() );
  
      }
 
 
}


파일명: BoardDAOSpring.java



3. Mapper 구현


Spring JDBC의 특징은 Mapper 영역을 구현할 수 있다는 점이다.


package com.website.example.board;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

import com.website.example.model.FoodMenuVO;
import com.website.example.model.FoodMenuViewVO;


public class FoodMenuRowMapper implements RowMapper<FoodMenuVO>  {


        @Override
        public FoodMenuVO mapRow(ResultSet rs, int rowNum) throws SQLException {
  
              FoodMenuVO vo = new FoodMenuVO();

              vo.setId(rs.getInt(1));
              vo.setName(rs.getString(2));
              vo.setPrice(rs.getInt(3));
              vo.setStore_id(rs.getInt(4));
              vo.setCnt(rs.getInt(5));
              vo.setRegidate(rs.getDate(6));
  
              return vo;
        }

}


파일명: FoodMenuRowMapper.java


package com.website.example.board;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

import com.website.example.model.FoodMenuVO;


public class FoodMenuViewCntRowMapper implements RowMapper<FoodMenuVO>  {


        @Override
        public FoodMenuVO mapRow(ResultSet rs, int rowNum) throws SQLException {
  
               FoodMenuVO vo = new FoodMenuVO();
               vo.setId(rs.getInt(1));
               // System.out.println(rs.getInt(1));
  
               return vo;
       }

}


파일명: FoodMenuViewCntRowMapper.java


Mapper를 두 가지 형태로 두었는데, 상황에 따라서 변형이 가능하다.



* 맺음글(Conclusion)


Spring JDBC에 대해서 살펴보았다.

짧게 적은 이유는 사용 방법이 간단해서 그렇다. Spring JDBC의 트랜젝션을 언급하기 위해서 그렇다.


1. [Spring-Framework] 35. Spring-JDBCTemplate - 트랜젝션 (어노테이션 X), 2020-10-09

- https://yyman.tistory.com/1460


반응형
728x90
300x250

[JSP] 27. Java 스타일의 트랜젝션 구현하기(은행 계좌)


트랜젝션 처리에 대해서 소개하려고 한다.

이 주제는 사실 몇 가지 키워드가 있다.


ACID(원자성, 일관성, 고립성, 지속성)을 만족해야 한다.


기본적인 DML만 조작하다가 갑자기 접근하게 되면, 이 내용은 조금 난해할 수도 있다.


1. 자료처리에 있어서 4가지를 모두 충족해야 한다.


원자성(Atomicity)
트랜젝션은 분해가 불가능한 최소의 단위인 하나의 원자처럼 동작한다는 의미. 

트랜젝션 내의 모든 연산들은 반드시 한꺼번에 완전하게 전체가 정상적으로 수행이 완료되거나 아니면 연산자체를 수행하지 않음.


일관성(Consistency)
트랜잭션 작업이 시작되지 전에 데이터베이스 상태가 일관된 상태였다면 트랜잭션 작업이 종료된 후에도 일관성 있는 데이터 베이스 상태를 유지해아한다.

예를 들어서 게시판에 글을 쓰는데 제목의 글자 제한이 255자라고 하자.

트랜잭션이 일어나면 이러한 조건을 만족해야하는 것이다. 만약 이를 위반하는 트랜잭션이 있다면 롤백 처리해야 한다.

(문제가 있는 작업이라면, 입력자체를 시키면 안 되는 것이다.)


고립성(Isolation)
트랜잭션 작업 수행 중에는 다른 트랜잭션에 영향을 주어서도 안 되고, 다른 트랜잭션들에 의해 간섭을 받아서도 안 된다는 것을 의미. 


다른 트랜잭션의 영향을 받게 되면 영향을 주는 트랜잭션에 의해 자신의 동작이 달라 질 수 있기 때문이다.

트랜젝션 자신은 고립된 상태에서 수행되어야 한다는 것을 의미. 즉 다수의 트랜잭션이 동시에 수행중인 상황에서 하나의 트랜잭션이 완료될 때까지는 현재 실행 중인 트랜잭션의 중간 수행결과를 다른 트랜잭션에서 보거나 참조 할 수 없다.


지속성(Durablility)
일련의 데이터 조작(트렌젝션 조작)을 완료 하고 완료 통지를 사용자가 받는 시점에서 그 조작이 영구적이 되어 그 결과를 잃지 않는 것을 나타낸다. 시스템이 정상일 때 뿐 아니라 데이터베이스나 OS의 이상 종료, 즉 시스템 장애도 견딜 수 있다는 것을 말한다.




2. "은행 계좌"라는 주제


은행 계좌 구현의 문제를 놓고 보면, 돈을 이체시켰는데 시스템 장애로 돈이 빠져나가고 이체가 되지 않아버리면 입금자는 돈을 잃어버리게 된다.

물론 트랜젝션만 가지고 은행 시스템이 구축된 것은 아닐 것이다.


이런 경우를 컴퓨터 프로그래밍으로 표현해보려고 한다.




3. JSP/Servlet으로 구현해도 되고, JUnit 태스트 도구로 접근해도 상관없다.


이 프로젝트를 자습하는 데 있어서, 자유롭게 원하는 형식에서 태스트해도 무방하다.

자바 기반이면, 스프링프레임워크에서도 가능하고, Dynamic Web Project를 생성해도 무방하고 Java Project로 따라해도 괜찮다는 이야기를 하고 소개하겠다.


[태스트 환경]

IDE: Eclipse 2020-06

DB: Oracle 11g XE(Express Edition)
- Maven Projects(Spring 포함)

- JUnit 5



4. 데이터베이스 설계


-- Transaction 실습 DB (은행 - Account)
-- Oracle 11 - 자동번호 생성 테이블 정의
-- Table 생성 (FOODMENU_TBL)
-- NEW.ID (Table의 id를 가리킴)

CREATE TABLE account_tbl
(
    idx NUMBER PRIMARY KEY,
    name VARCHAR2(30),
    balance NUMBER,
    regidate TIMESTAMP
);


-- Sequence 정의
CREATE SEQUENCE account_sequence
START WITH 1
INCREMENT BY 1;


-- Trigger 생성
-- BEFORE INSERT on '테이블명'
CREATE OR REPLACE TRIGGER account_trigger
BEFORE INSERT
    ON account_tbl
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT account_sequence.nextval INTO :NEW.IDX FROM dual;
END;


트리거 작성과 스퀀스 번호 생성에 대해서도 적혀져 있으니깐, 잘 사용해도 무방하다.


파일명: account_tbl.sql


[첨부(Attachments)]

AccountTbl.zip




5. 프로젝트 구성도


아래 그림은 프로젝트 구성도이다.

HomeController.java 등은 생략해도 된다.



그림 1, 그림 2. 프로젝트 구성도



6. AccountVO.java(com.website.example.vo)


package com.website.example.vo;

import java.sql.Timestamp;

public class AccountVO {

 private int idx;
 private String name;
 private int balance;
 private Timestamp regidate;
 
 public int getIdx() {
      return idx;
 }
 
 public void setIdx(int idx) {
     this.idx = idx;
 }
 
 public String getName() {
     return name;
 }
 
 public void setName(String name) {
     this.name = name;
 }
 
 public int getBalance() {
     return balance;
 }

 public void setBalance(int balance) {
     this.balance = balance;
 }

 public Timestamp getRegidate() {
     return regidate;
 }
 
 public void setRegidate(Timestamp regidate) {
     this.regidate = regidate;
 }
 
}


파일명: AccountVO.java


[첨부(Attachments)]

AccountVO.zip




6-1. db.properties (/src/main/resources)


MYSQL_DB_URL=jdbc:mysql://localhost:3306/dbanme?useUnicode=true&characterEncoding=utf8
MYSQL_DB_USERNAME=
MYSQL_DB_PASSWORD=
ORACLE_DB_URL=jdbc:oracle:thin:@127.0.0.1:1521:xe
ORACLE_DB_USERNAME=HR
ORACLE_DB_PASSWORD=1234


파일명: db.properties


[첨부(Attachments)]

db.zip




7. JDBCUtil.java(com.website.example.common)


이 프로젝트에서는 close()만 사용하였다. 예비 태스트 용도로 자바 표준의 SQL 방식도 두고 있다.


package com.website.example.common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import javax.sql.DataSource;


public class JDBCUtil {
 
      private static final String driverName = "oracle.jdbc.driver.OracleDriver";
      private static final String jdbcUrl = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
      private static final String userId = "{사용자 계정명}";
      private static final String userPwd = "{비밀번호}";
 
 public static Connection getConnection() {


  try {
   
       Class.forName(driverName); 
        return DriverManager.getConnection(jdbcUrl, userId, userPwd);
   
  } catch (Exception e) {
        e.printStackTrace();
  }
  
  return null;
  
 }


 public static void close(PreparedStatement stmt, Connection conn) {
  
  if (stmt != null) {
   
   try {
    
    if (!stmt.isClosed())
     
       stmt.close();
    
   } catch (Exception e) {
    
        e.printStackTrace();
    
   } finally {
    
        stmt = null;
    
   }
   
  } // end of if
  
  if (conn != null) {
   
   try {
    
    if (!conn.isClosed())
         conn.close();
    
   } catch (Exception e) {
    
    e.printStackTrace();
    
   } finally {
    
    conn = null;
    
   }
   
  } // end of if
  
 }

 public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
  
  if (rs != null) {
   
   try {
    
    if (!rs.isClosed())
     rs.close();
    
   } catch (Exception e) {
    
    e.printStackTrace();
    
   } finally {
    
    rs = null;
    
   }
   
  } // end of if
  
  if (stmt != null) {
   
   try {
    
    if (!stmt.isClosed())
     stmt.close();
    
   } catch (Exception e) {
    
    e.printStackTrace();
    
   } finally {
    stmt = null;
   }
   
  } // end of if
  
  if (conn != null) {
   
   try {
    
    if (!conn.isClosed())
     conn.close();
    
   } catch (Exception e) {
    
    e.printStackTrace();
    
   } finally {
    
    conn = null;
    
   }
   
  } // end of if
    
 }

}



파일명: JDBCUtil.java


[첨부(Attachments)]

JDBCUtil.zip

AccountVO.zip




8. MyDataSourceFactory.java(com.website.example.common)


DataSourceFactory이다.



package com.website.example.common;

import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import com.mysql.cj.jdbc.MysqlDataSource;

import oracle.jdbc.pool.OracleDataSource;

public class MyDataSourceFactory {
 
 private InputStream is = null;
 
 public MyDataSourceFactory()  {
  
        String resource = "db.properties";
        is = getClass().getClassLoader().getResourceAsStream(resource);
 }
 
 public DataSource getMySQLDataSource() {
  
        Properties props = new Properties();
       
        MysqlDataSource mysqlDS = null;
       
        try {
         
            props.load(is);
            mysqlDS = new MysqlDataSource();
            mysqlDS.setURL(props.getProperty("MYSQL_DB_URL"));
            mysqlDS.setUser(props.getProperty("MYSQL_DB_USERNAME"));
            mysqlDS.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));
           
        } catch (IOException e) {
            e.printStackTrace();
        }
       
        return mysqlDS;
       
    }
    
    public DataSource getOracleDataSource(){
     
        Properties props = new Properties();
        OracleDataSource oracleDS = null;
       
        try {
         
            props.load(is);
            oracleDS = new OracleDataSource();
            oracleDS.setURL(props.getProperty("ORACLE_DB_URL"));
            oracleDS.setUser(props.getProperty("ORACLE_DB_USERNAME"));
            oracleDS.setPassword(props.getProperty("ORACLE_DB_PASSWORD"));
           
        } catch (IOException e) {
         
            e.printStackTrace();
           
        } catch (SQLException e) {
         
            e.printStackTrace();
           
        }
       
        return oracleDS;
       
    }

}


파일명: MyDataSourceFactory.java


[첨부(Attachments)]

MyDataSourceFactory.zip


JDBCUtil.zip

AccountVO.zip



9. AccountDAO.java (com.website.example.dao)


AccountDAO에 대한 명세이다. DAO는 Data Access Object의 약자이다.


package com.website.example.dao;

import java.sql.SQLException;

import com.website.example.vo.AccountVO;

public interface AccountDAO {

 // 계좌 생성
 public void create(AccountVO vo) throws SQLException;
 
 // 잔액 조회
 public int getBalance(String name) throws SQLException;
 
 // 플러스 계좌
 public void plus(String name, int money) throws SQLException;
 
 // 마이너스 계좌
 public void minus(String name, int money) throws SQLException;
 
 // 거래
 public void transfer(String sender, String receiver, int money) throws SQLException;
 
}


파일명: AccountDAO.java


[첨부(Attachments)]

AccountDAO.zip


JDBCUtil.zip

AccountVO.zip



10. AccountDAOImpl.java (com.website.example.dao)


AccountDAO에 대한 명세이다. DAO는 Data Access Object의 약자이다.


package com.website.example.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.website.example.common.JDBCUtil;
import com.website.example.vo.AccountVO;

// Transaction - 자바
public class AccountDAOImpl implements AccountDAO {


 private final String CREATE_ACCOUNT = "insert into account_tbl" +
        "(name, balance, regidate) values(?, ?, ?)";
 
 private final String SELECT_BALANCE = "select * from account_tbl where name = ?";
 
 private final String UPDATE_MINUS = "update account_tbl set balance = (select balance from account_tbl where name = ?) - ? " +
          "where name = ?";
 
 private final String UPDATE_PLUS = "update account_tbl set balance = (select balance from account_tbl where name = ?) + ? " +
            "where name = ?";
 
 private DataSource ds = null;
 
 public AccountDAOImpl(DataSource ds) {
       this.ds = ds;
 }
 
 // 단일 쿼리에서의 트랜젝션 방법
 @Override
 public void create(AccountVO vo) throws SQLException {


       Connection conn = ds.getConnection();
       PreparedStatement pstmt = null;
  
  try {
   conn.setAutoCommit(false); // 트랜젝션 시작
   
   pstmt = conn.prepareStatement(CREATE_ACCOUNT);
   pstmt.setString(1, vo.getName());
   pstmt.setInt(2, vo.getBalance());
   pstmt.setTimestamp(3, vo.getRegidate());
   
   pstmt.executeUpdate();
   
   conn.commit();
   
  }catch(SQLException e) {
   
   conn.rollback();
   e.getMessage();
   
  }finally {
   JDBCUtil.close(pstmt, conn);
  }
  
 }

 @Override
 public int getBalance(String name) throws SQLException {
  
  Connection conn = ds.getConnection();
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  
  int result = 0;
  
  try {
        conn.setAutoCommit(false); // 트랜젝션 시작
        pstmt = conn.prepareStatement(SELECT_BALANCE);
   
   pstmt.setString(1, name);
   
   rs = pstmt.executeQuery();
   
   if ( rs.next() ) {
         result = rs.getInt(3);
   }
   
   conn.commit();
   
  }catch(SQLException e) {
   
   conn.rollback();
   e.getMessage();
   
  }finally {
   JDBCUtil.close(pstmt, conn);
  }
  
  return result;
 }

 @Override
 public void plus(String name, int money) throws SQLException {


      Connection conn = ds.getConnection();
      PreparedStatement pstmt = null;
  
  try {
   
   conn.setAutoCommit(false);
   
   // plus, minus 다 확인 후에 commit처리 해야 함.
   // 그래서 지금 바로 트랜젝션을 구현하면 안 됨
   pstmt = conn.prepareStatement(UPDATE_PLUS);
   pstmt.setString(1, name);
   pstmt.setInt(2, money);
   pstmt.setString(3, name);
   
   pstmt.executeUpdate();
      System.out.println(money);

   conn.commit();
   
  }catch(SQLException e) {
   System.out.println(e.getMessage());
   conn.rollback();
   
  }finally {
   JDBCUtil.close(pstmt, conn);
  }
  
 }

 @Override
 public void minus(String name, int money) throws SQLException {
  

       Connection conn = ds.getConnection();
       PreparedStatement pstmt = null;
  
  try {
   
   conn.setAutoCommit(false);

      // 예외 발생시키기(트랜젝션 의도적 발생)
      if(true){
             throw new SQLException(); // 의도적 예외 발생
       }
        
   // plus, minus 다 확인 후에 commit처리 해야 함.
   // 그래서 지금 바로 트랜젝션을 구현하면 안 됨
   pstmt = conn.prepareStatement(UPDATE_MINUS);
   pstmt.setString(1, name);
   pstmt.setInt(2, money);
   pstmt.setString(3, name);
   
   pstmt.executeUpdate();
   
   conn.commit();
   
  }catch(SQLException e) {
   
        conn.rollback();
        System.out.println(e.getMessage());
    
  }finally {
        JDBCUtil.close(pstmt, conn);
  }
  
  
 }

 @Override
 public void transfer(String sender, String receiver, int money) throws SQLException {

  Connection conn = ds.getConnection();
  PreparedStatement pstmt = null;
  
  try {
   
   conn.setAutoCommit(false);

   /*
      // 예외 발생시키기(트랜젝션 의도적 발생)
      if(true){
       throw new SQLException(); // 의도적 예외 발생
         }
         */
        
   // plus, minus 다 확인 후에 commit처리 해야 함.
   // 그래서 지금 바로 트랜젝션을 구현하면 안 됨
   pstmt = conn.prepareStatement(UPDATE_MINUS);
   
   // 주는 분
   pstmt.setString(1, sender);
   pstmt.setInt(2, money);
   pstmt.setString(3, sender);
   
   pstmt.executeUpdate();
   
   // 받는 분
   pstmt = conn.prepareStatement(UPDATE_PLUS);
   pstmt.setString(1, receiver);
   pstmt.setInt(2, money);
   pstmt.setString(3, receiver);
   
   pstmt.executeUpdate();
   
        conn.commit();
   
  }catch(SQLException e) {
   
        conn.rollback();
        System.out.println(e.getMessage());
   
  }finally {
       JDBCUtil.close(pstmt, conn);
  }
  
 }

}


파일명: AccountDAOImpl.java


[첨부(Attachments)]

AccountDAOImpl.zip



JDBCUtil.zip

AccountVO.zip



11. AccountService.java (com.website.example.service)


AccountService에 대한 명세이다.

서비스에 대한 정의이다. DB를 정의하는 영역은 아니다.

하지만, Spring Framework로 구현할 때, Spring JDBC 등을 적용하여 트랜젝션 동기화 기능을 구현부에 구현하면, Connection을 사용할 수도 있다.

질의문을 정의하는 영역은 아니다.


package com.website.example.service;

import java.sql.SQLException;

import com.website.example.vo.AccountVO;


public interface AccountService {
 
     public void accountCreate(AccountVO vo) throws SQLException;
     public void accountTransfer(String sender, String receiver, int money) throws SQLException;
 
}


파일명: AccountService.java


[첨부(Attachments)]

AccountService.zip



12. AccountServiceImpl.java (com.website.example.service)


AccountServiceImpl.java는 AccountService의 구현부이다.

인터페이스의 역할을 정의해보면, 하나의 통로와 같은 역할을 한다고 볼 수 있다.


package com.website.example.service;

import java.sql.SQLException;

import javax.sql.DataSource;

import com.website.example.dao.AccountDAO;
import com.website.example.dao.AccountDAOImpl;
import com.website.example.vo.AccountVO;

public class AccountServiceImpl implements AccountService {


     private AccountDAO accountDAO;
     private DataSource ds = null;
 
 public AccountServiceImpl(DataSource ds) {
  
        accountDAO = new AccountDAOImpl(ds);
        this.ds = ds;
 }

 @Override
 public void accountCreate(AccountVO vo) throws SQLException {
  
        accountDAO.create(vo);
  
 }
 
    public void accountTransfer(String sender, String receiver, int money) throws SQLException{
       
     int balance = accountDAO.getBalance(sender); // 보내는 사람 잔액 체크
     
        if(balance >= money){ // 보내는 돈이 잔액보다 많으면
 
                   accountDAO.transfer(sender, receiver, money);
         
        } else{
                   System.out.println("돈 없음");
                   //throw new NoMoneyException();
        }
       
    }

 
}


파일명: AccountServiceImpl.java


[첨부(Attachments)]

AccountServiceImpl.zip




13. TestMain.java (com.website.example.unit)


JUnit의 태스트 영역이다.


package com.website.example.unit;

import static org.junit.jupiter.api.Assertions.*;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.jupiter.api.Test;

import com.website.example.common.MyDataSourceFactory;
import com.website.example.service.AccountService;
import com.website.example.service.AccountServiceImpl;
import com.website.example.vo.AccountVO;

class TestMain {


       @Test
       void test() throws SQLException {
   
                 DataSource ds = new MyDataSourceFactory().getOracleDataSource();
                 AccountService service = new AccountServiceImpl(ds);
  
  // 1. 계정 생성 (계정이 없는 경우라면, 주석 풀고 작업해보면 됨.
  /*
  AccountVO vo = new AccountVO();
  vo.setName("홍길동");
  vo.setBalance(10000);
  vo.setRegidate(Timestamp.valueOf("2020-10-01 10:30:00"));
  
  service.accountCreate(vo);

  vo.setName("홍길자");
  vo.setBalance(0);
  vo.setRegidate(Timestamp.valueOf("2020-10-04 23:20:00"));

  service.accountCreate(vo);
  */
  
  // 2. 금전 거래
  service.accountTransfer("홍길동", "홍길자", 500);
  
 }

}


파일명: TestMain.java


[첨부(Attachments)]

TestMain.zip




14. 태스트 해보기 - 결과


코드로 구현하여 태스트를 해봐도 좋을 듯 싶다.



그림 3. 태스트 하기



그림 4. 태스트 하기


트랜젝션을 한번 해보면, 무슨 일이 일어나는지 구경을 조금해보면 좋을 듯 싶다.




15. 맺음글(Conclusion)


setAutoCommit(), conn.commit(), conn.rollback() 사소해보이는 이 코드가 반응하는 것을 관찰해보면, 트랜젝션이 중요하다는 사실을 알 수 있다.



* 참고자료(References)


1. JDBC 트랜젝션 동기화, https://joont.tistory.com/158, Accessed by 2020-10-09, Last Modified 2016-07-11.

-> 추천(50점): 정말 잘 설명해주고 있다.

2. Data Access - Transaction, https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#transaction, Accessed by 2020-10-09, Last Modified 2020-09-15.


3. 

반응형
728x90
300x250
[Spring Framework] 33. AOP(Aspect-Oriented-Programming) - XML 방식


XML 기반으로 작성된 AOP 구현 방법에 대해서 소개하려고 한다.

AOP의 관점에 대한 5가지 방식을 모두 적용해보았다.


[태스트 환경]

* IDE: Eclipse 2020-06

* Spring Framework 4.2.4.RELEASE
* Aspectjweaver 1.6.10
* Spring-aop 4.2.4.RELEASE
* JUnit 5




1. 프로젝트 구성도


프로젝트 구성도이다.



그림 1, 그림 2. 프로젝트 구성도




2. 프로젝트 생성


Spring Legacy Project로 프로젝트를 생성한다.

참고로 Spring MVC Project로 선택하고 생성해야 한다.



3. Build Path, Java Compiler, Project Factes 버전 맞춰주기


* Build Path: JRE 버전을 1.8로 변경해준다.
               - Add Library로 JUnit 5를 등록해준다.

* Java Compiler: Compiler compliance level - 1.8로 변경해준다.

* Project Factes: Java 버전을 1.8로 변경해준다.




4. POM.xml 설정하기


(중략)
 <properties>
  <java-version>1.8</java-version>
  <org.springframework-version>4.2.4.RELEASE</org.springframework-version>
  <org.aspectj-version>1.6.10</org.aspectj-version>
  <org.slf4j-version>1.6.6</org.slf4j-version>
 </properties>

~~~

(중략)
    <!-- AspectJ -->
    <dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjrt</artifactId>
     <version>${org.aspectj-version}</version>
    </dependency>
   
    <!-- AspectJWeaver -->
    <dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjweaver</artifactId>
     <version>${org.aspectj-version}</version>
    </dependency>
   
    <!-- Spring AOP 추가(Java) --> 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${org.springframework-version}</version>
    </dependency> 
(중략)






5. applicationContext.xml (src/main/resources/applicationContext.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"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
 
 <!-- 방법1 - JAVA -->
 <!-- JAVA 방식(어노테이션)의 AOP - AspectJ Weaver -->
 <!--  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>  어노테이션 작업시 필수 선언해야 함. -->
 
 <!--  XML 방식의 AOP - AsepectJ Weaver -->
 <bean id="resultAOP" class="com.website.example.test.ResultAOP"></bean>
 <bean id="txAdviceXML" class="com.website.example.aop.LogAdvisorXML"></bean>

 <aop:config>
  <!-- txAdviceXML 하나 영역임 -->
  <aop:aspect ref='txAdviceXML'>

   <!-- 진입영역 -->
   <!-- 1개만 가능함 -->
   <!-- <aop:pointcut id="point1" expression="execution(* com.website.example.test..*())"/> -->
   <aop:pointcut id="point1" expression="execution(* com.website.example.test.ResultAOP..*())"/>           
          
          <!-- before -->
          <aop:before method="beforeAdvice" pointcut-ref="point1"/>
          <!-- after -->
          <aop:after method="afterAdvice" pointcut-ref="point1"/>
          
          <!-- around(메서드 자체를 가로채기) -->
          <aop:around method="aroundAdvice" pointcut-ref="point1"/>
          
          <!-- afterThrowing -->
          <aop:after-throwing method="afterThrowing" pointcut-ref="point1"/>
          
          <!-- afterReturning -->
          <aop:after-returning method="afterReturning" pointcut-ref="point1"/>
          
        </aop:aspect>
       
        <!-- 2번째 선언자 -->
 </aop:config>
 
</beans>


파일명: applicationContext.xml


[첨부(Attachments)]

applicationContext.zip



6. ResultAOP.java - com.website.example.text


핵심 로직에 해당되는 부분이다. 이 부분을 비즈니스 로직이라고 표현하기도 한다.


package com.website.example.test;


public class ResultAOP {


     public void method1() {
           System.out.println("[중간]:");
  
           // afterThrowing 유발 코드
           // int d = 2/0;
  
           System.out.println("결과: 메서드");
     }
 
}


파일명: ResultAOP.java


[첨부(Attachments)]

ResultAOP.zip


applicationContext.zip



7. LogAdvisor.java - com.website.example.aop


인터페이스 정의이다.

package com.website.example.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public interface LogAdvisor {

        public void beforeAdvice();
        public void afterAdvice();
        public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable;
        public void afterThrowing();
        public void afterReturning();
 
}


파일명: LogAdvisor.java


[첨부(Attachments)]

LogAdvisor.zip




8. LogAdvisorXML.java - com.website.example.aop


package com.website.example.aop;

import org.aspectj.lang.ProceedingJoinPoint;


public class LogAdvisorXML implements LogAdvisor{
  
       // around advice
       @Override
       public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
  
               System.out.println("2단계A?:");
               System.out.println("aroundMethod 호출 1");
  
               // 원래의 메소드를 호출한다.
               Object obj = pjp.proceed();

               System.out.println("2단계B?:");
               System.out.println("aroundMethod 호출 2");
  
               return obj;
       }


       // before advice
       @Override
       public void beforeAdvice() {
              System.out.println("1단계:");
              System.out.println("beforeMethod 호출");
  
       }


       // after
       @Override
       public void afterAdvice() {
              System.out.println("5단계:");
              System.out.println("afterMethod 호출");
  
       }


       // afterThrowing
      @Override
      public void afterThrowing() {
              System.out.println("4단계:");
              System.out.println("afterThrowing 호출");
      }

      // afterReturning
      @Override
      public void afterReturning() {
              System.out.println("3단계:");
              System.out.println("afterReturning 호출");
  
      }
 
}


파일명: LogAdvisorXML.java


[첨부(Attachments)]

LogAdvisorXML.zip


LogAdvisor.zip




9. TestMain.java - com.website.example.unit


package com.website.example.unit;


import org.junit.jupiter.api.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.website.example.test.ResultAOP;


public class TestMain {

      
       // 사용방법1
       @Test
       public void sample() {

                AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
   
                ResultAOP rAOP = (ResultAOP) factory.getBean("resultAOP");

                rAOP.method1();
  
                factory.close();
       }
 

       // 사용방법2
       @Test
       public void sample2() {

               ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
               ResultAOP rAOP = ctx.getBean("resultAOP", ResultAOP.class);
               //rAOP.method1();
  
               ctx.close();
       }
 
}


파일명: TestMain.java


[첨부(Attachments)]

TestMain.zip




10. 동작 결과


구현한 코드의 동작 결과이다.



그림 3. 출력 결과 1



그림 4. 출력 결과 2




11. 맺음글(Conclusion)


직관적으로 AOP를 아주 쉽게 이해할 수 있도록 작성하였다.

반응형
728x90
300x250
[Spring Framework] 32. AOP(Aspect-Oriented-Programming) - Java 방식2(Context.xml)


Spring Framework에서 사용되는 AOP 구현방식을 소개하려고 한다.

AOP를 다루고자 하는 사람들은 조금 방법이 다양하게 있으니, 원하는 방식 하나 택해서 사용하면 될듯 싶다.


[배경 입문 지식]

1. [Spring-Framework] 30. AOP(Aspect-Oriented-Programming) 관점지향 프로그래밍 (Java셋팅) (1), 2020-10-04

- https://yyman.tistory.com/1447

2. [Spring-Framework] 30. AOP(Aspect-Oriented-Programming) 관점지향 프로그래밍 (Java셋팅) (2), 2020-10-04

- https://yyman.tistory.com/1448


셋팅 방법에서 다르다.

동일하게 생각하고 작성하면, 오류를 경험할 수 있다.


AOP를 다루는 건 큰 틀에서는 같은 일인데 불구하고, Service 어노테이션 정의부터 다소 셋팅이 달라져버릴 수가 있어서 신중하게 사용하는 것을 권장한다. 셋팅을 먼저 한 경우라면, 거기에 맞춰서 흐름을 타주는 방식으로 가야 하겠다.


XML, 순수한 Java 방식, Context.xml 및 Java 방식(어노테이션) 크게 3가지 방법으로 AOP를 설정할 수 있다.

이론적으로는 같으나 실질적인 구현에서는 호환이 안 되니 주의하여 사용할 것을 권한다.


3가지 방법 중 하나를 택해서 AOP 대상을 두었으면 그 방법을 따라가는 형태로 진행하는 것을 권장한다.

(구현 관점에서보면, 표준화가 진행이 덜된 느낌이 있다.) 시간이 나면, 소개해주겠다.


[태스트 환경]

* IDE: Eclipse 2020-06 (Spring Tools 3 Addon.....)
* Spring Framework Version: 4.2.4.RELEASE

* JUnit 5(태스트 실행)




1. 프로젝트 생성


-> Spring Legacy Project -> Spring MVC Project로 진행하였음.


프로젝트 생성 및 셋팅 방법에 대해서는 "이전 글들"을 참고하면 된다. (동일하게 진행함.)




2. pom.xml


매우 중요한 부분이다. 노란색 불은 들어오는데 빌드하면 오류가 생긴 경우도 있을 수도 있다.

셋팅을 잘해야 한다.


-> Spring Tool-Suites 4.7로 작업하면 14버전을 사용해도 무방하다. 다만, 이전 버전의 Eclipse 등에서 프로젝트 구성에서 오류가 생길 수도 있다.

지금 pom 셋팅은 공통적인 작업이다.


(중략)

 <properties>
  <java-version>1.8</java-version>
  <org.springframework-version>4.2.4.RELEASE</org.springframework-version>
  <org.aspectj-version>1.6.10</org.aspectj-version>
  <org.slf4j-version>1.6.6</org.slf4j-version>
 </properties>

(중략)
    
  <!-- AspectJ -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>${org.aspectj-version}</version>
  </dependency> 
  
  <!-- AspectJWeaver -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.8.8</version>
  </dependency>
  
  <!-- Spring AOP 추가(Java) -->  
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${org.springframework-version}</version>
  </dependency>

(중략)




3. 미리 살펴보는 프로젝트 구성도


이번 작업에서는 JUnit5로 TDD 방식으로 구동한 프로젝트이다.



그림 1. 프로젝트 구성도

작업할 프로젝트 구성이다.




4. 프로젝트 환경설정(Build Path, Java Compiler, Project Factes)


Build Path의 Libraries에 들어가서 버전을 1.8로 설정한다.

JUnit 5도 추가해준다.


참고로 JUnit 5은 자바 1.8버전에서부터 지원한다.



그림 2. 프로젝트 구성도


Build Path를 설정해준다. "Add Library"를 클릭해서 JUnit 5을 추가할 수 있다.




그림 3. 자바 컴파일러 환경설정


JDK를 잘 설치하였음에도 1.8버전 등으로 변경하였을 때 이클립스에서 오류로 간주해버리는 경우가 있다.

오류가 생기는 이유는 Project Factes 옵션을 조작할 때 발생한다.


JDK Compliance의 Compiler compliance level 버전을 맞춰주면 오류가 사라지는 것을 확인할 수 있다.



그림 4. Project Factes


Java의 버전을 1.8으로 변경한다.




5. applicationJavaAOP.xml (src/main/resources/applicationJavaAOP.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"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
 
 <aop:aspectj-autoproxy />
 <context:component-scan base-package="com.website.example" />
 <bean id="loggingAspect" class="com.website.example.aop.LogAdvisorJava" />
 
</beans>



AOP 스키마 정의는 servlet-context.xml에서 간단한 조작으로 추가하였다.


그림 5. aop 환경설정해주기 - 네임스페이스 정의


양식 틀은 /src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml에서 복사 붙여넣기하였다.


작성한 코드는 <aop>.....</bean> 이 정도이다.


* 파일명: applicationJavaAOP.xml


[첨부(Attachments)]

applicationJavaAOP.zip




6. ResultAOPJava.java (com.website.example.text)


package com.website.example.test;

import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;


@Service
public class ResultAOPJava {
 
     @Pointcut("execution(* com.website.example.test.*(..))")
      public void method1() {
              System.out.println("결과: 메서드");
      }
 
}


* 파일명: ResultAOPJava.java


[첨부(Attachments)]

ResultAOPJava.zip




7. LogAdvisor.java (com.website.example.aop)


관점에 대한 인터페이스이다.
객체의 다형성을 생각하면 좋을 것으로 보인다.


package com.website.example.aop;

import org.aspectj.lang.annotation.Aspect;


@Aspect
public interface LogAdvisor {

       public void beforeAdvice();
       public void afterAdvice();
       public void aroundAdvice();
 
}


* 파일명: LogAdvisor.java


[첨부(Attachments)]

LogAdvisor.zip

ResultAOPJava.zip




8. LogAdvisorJava.java (com.website.example.aop)


클래스명을 Impl로 해도 되었을 법한데 태스트용이니 생략하도록 하자.


package com.website.example.aop;


import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;


// 어노테이션 방식
@Aspect
public class LogAdvisorJava implements LogAdvisor{


         @Before("execution(* com.website.example.test.ResultAOPJava.*(..))")
          public void beforeAdvice() {
                 System.out.println("전 단계");
         }

         @After("execution(* com.website.example.test.ResultAOPJava.*(..))")
         public void afterAdvice() {
                 System.out.println("후 단계");
         }


         public void aroundAdvice() {
   
          }
 
}


* 파일명: LogAdvisorJava.java


[첨부(Attachments)]

LogAdvisorJava.zip


LogAdvisor.zip

ResultAOPJava.zip



9. TestMain.java (com.website.example.test)


JUnit 태스트 도구로 실행 영역을 구현하였다.


package com.website.example.test;

import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class TestMain {


     @Test
     public void test() {


              // 방법 1
             @SuppressWarnings("resource")
             AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationJavaAOP.xml");
  
             ResultAOPJava cal = factory.getBean(ResultAOPJava.class);
             cal.method1();
  
     }
 
}


* 파일명: TestMain.java


[첨부(Attachments)]

TestMain.zip



10. 출력 결과


아래의 그림처럼 AOP가 잘 출력되는 것을 확인할 수 있다.



그림 6. AOP 화면 출력 결과


정상적으로 AOP 환경설정이 이뤄진 것을 확인할 수 있다.



* 참고자료(References)


1. Spring AOP – AspectJ Annotation Config Example - HowToDoInJava, https://howtodoinjava.com/spring-aop/spring-aop-aspectj-example-tutorial-using-annotation-config/, Accessed by 2020-10-09, Last Modified 2015-02.


-> 추천(25점): 구현에 대해서 많은 도움을 주었다.


2. 스프링 부트(Spring Boot) - AOP와 트랜잭션(Transaction) 설정하기 [개발을 시작해봐요!], https://congsong.tistory.com/25, Accessed by 2020-10-09, Last Modified 2020-04-28.

-> 추천(25점): 스프링 부트로 작성되었지만, AOP 개발 방법의 흐름을 살펴볼 수 있었음.

반응형
728x90
300x250

[PC 활용] Eclipse 2020-06에서 STS(Spring Tool-Suites) 설치하기


Eclipse IDE를 사용하는 유저를 대상으로 작성된 글이다.

Spring.io 사이트에서 STS(Spring Tool-Suites)를 내려받아도 되지만, 순정 Eclipse에서 플러그인 형태에서 설치하는 것도 지원한다.


[작업 환경]

* OS: Microsoft Windows 10

* IDE: Eclipse 2020-06
{순정 상태}




1. Eclipse Marketplace


Help->Eclipse Marketplace를 클릭한다.


그림 1. STS 검색하기


STS라고 검색한다.


"Spring Tools 3 Add-On for Spring Tools 4 3.9.14. RELEASE"를 찾아서 Install을 누른다.



그림 2. STS 설치하기


전부 다 설치해야 한다. 설치 내역을 확인한 후 "Confirm"을 누른다.


(중략하였음.)



2. 확인해보기


File -> New -> Others를 클릭한다.

참고로 초기 세팅에서는 File-> New 메뉴에 Spring Project가 바로 보이진 않을 것이다.

그래서 Others를 클릭하는 것이다.



그림 3. STS 프로젝트 생성의 예


Spring 프로젝트가 지원되는 것을 확인할 수 있다.



반응형
728x90
300x250
[PC 활용] 오라클 - 반복문으로 다중 입력 시(예:insert into) 퍼짐 현상


이 글은 JSP, Java, PHP, C#를 예로 들어서 개발을 수행했을 때, 태스트로 "DML(Insert 문)"으로 DB에 Query 호출을 반복문으로 하였을 때 초기 환경 상태에서의 오라클 데이터베이스에서 일어나는 반응에 대한 글이다.


[PseudoCode]


public void insertMember(){


    (연결자)
    Connection conn = .....;
    
    try{
        conn.open(); // (연결)

        for ( 1 to 10000 ){


           String sql = "insert into ........";

           conn.executeQuery(sql);

        }


     }catch(Exception e){

     }finally{
           conn.close(); // (종료)
     }

    


}


슈도 코드) 문제가 되는 영역


이런 문제를 처리하고자 했을 때, 발생되는 오류를 소개하려고 한다.


[태스트 환경]

1. MS Windows 10

2. Oracle 11g (Express Edition, XE)



1. 프로그래밍 도구에서 호출되는 오류명


ora-12519 TNS:no appropriate handler found


이러한 오류가 발생한다면, 다음과 같이 입력하여 해결하면 된다.



2. 해결 방법


명령어를 몇 가지 요약하였다.


1. 명령 프롬프트 실행하기

   cmd


2. 관리자 계정 접속 명령어

   sqlplus "/as sysdba"


3. 프로세스 조회하기
   SQL> SELECT * FROM v$resource_limit where resource_name='processes';


4. 프로세스 조정하기 크기
   SQL> ALTER SYSTEM SET PROCESSES=500 SCOPE=spfile; -- 200으로 늘려줌


5. 서버 재시작
   SQL> shutdown immediate; --셧다운
   SQL> startup; --재시작



그림 1. cmd 명령어 - 시작 메뉴


시작 메뉴에서 cmd를 입력한다.



그림 2. sqlplus


sqlplus "/as sysdba"


이렇게 입력해도 관리자 권한으로 오라클에 접속할 수 있다.


SQL> SELECT * FROM v$resource_limit where resource_name='processes';


프로세스 조회 명령어로 프로세스 자원 한계를 확인하자.

프로세스가 100으로 작게 설정되어 있으니 조금 더 늘려보도록 하자.



그림 3. sqlplus


SQL> ALTER SYSTEM SET PROCESSES=500 SCOPE=spfile;


프로세스 500으로 수정을 해주었다.

변경되었는지 조회를 해보자.


SQL> SELECT * FROM v$resource_limit where resource_name='processes';


조회를 해보니, 변경되지 않았다.

그래서 commit을 안 해서 발생한 문제인지 commit을 입력하였다.


SQL> commit;


그리고 다시 조회를 해본다.


SQL> SELECT * FROM v$resource_limit where resource_name='processes';


변경되지 않았다.

오라클 DB를 재부팅해보면 해결되는 문제인지 시도해보았다.



그림 4. sqlplus


SQL> shutdown immediate;

SQL> startup;


서버를 다시 시작하였다.

그리고 프로세스 조회 명령어를 입력하였다.


SQL> SELECT * FROM v$resource_limit where resource_name='processes';


변경된 프로세스 내용을 확인할 수 있다.

반응형
728x90
300x250
[PC 활용] 오라클 XE 11(Oracle Express Edition 11g) - 설치 및 로그인


윈도우 10에서 오라클 XE를 설치하는 방법에 대해서 소개하려고 한다.

Standard Edition, Enterprise Edition에 비해서 설치 프로그램 용량도 적고, 간편하다.

다만, 아파치 톰캣을 사용하는 개발자라면, 포트 충돌이 날 수 있다.



[작성 환경]

1. MS윈도우 10

2. 포멧 후 깨끗한 상태



1. 설치하기


설치하는 방법은 다음과 같다.




그림 1. 오라클 설치하기


setup.exe를 실행한다.



그림 2. 오라클 설치하기


잠시 기다린다.



그림 3. 오라클 설치하기


Next를 누른다.



그림 4. 오라클 설치하기


"I accpet the terms......"을 체크한다.

Next를 누른다.




그림 5. 오라클 설치하기


Next를 누른다.



그림 6. 오라클 설치하기


이 비밀번호는 Oracle XE에서는 매우 중요한 암호가 된다. 기억해두자.

암호를 입력한 후에는 Next를 누른다.




그림 7. 오라클 설치하기


설치 환경설정을 살펴본다.

Oracle HTTP에서도 8080포트를 사용하는 것을 살펴볼 수 있다.


Install을 누른다.




그림 8. 오라클 설치하기


기다린다.



그림 9. 오라클 설치하기


Finish를 누르면 설치가 완료된 것이다.




2. 명령 프롬프트(cmd) 작업 - Sqlplus


설치를 완료하였다면, 바로 사용가능한 것이 아니라 몇 가지 계정 설정을 해줘야 한다.



그림 10. sqlplus 작업을 위한 명령 프롬프트 실행하기


시작 메뉴에서 cmd를 입력한다.



그림 11. sqlplus 작업을 위한 명령 프롬프트 실행하기


system이라고 입력한다.

아까 입력했던 패스워드를 입력한 후 엔터를 누른다.



그림 12. sqlplus 작업을 위한 명령 프롬프트 실행하기


경로: C:\oraclexe\app\oracle\product\11.2.0\server\rdbms\admin\
찾아야 하는 파일명: scott.sql


해당 파일을 찾아야 한다.



그림 13. sqlplus 작업을 위한 명령 프롬프트 실행하기


SQL> @C:\oraclexe\app\oracle\product\11.2.0\server\rdbms\admin\scott.sql
SQL> alter user scott identified by tiger;

SQL> commit;


3줄 명령어를 입력한다. (SQL>은 입력하는 게 아님)


scott 계정을 활성화한 것이다.



4. scott 계정 접속하기


앞서 작업한 scott 계정을 로그인해볼 것이다.



그림 14. sqlplus 작업을 위한 명령 프롬프트 실행하기


SQL> conn scott/tiger
SQL> show user;

SQL> select * from tab;


3줄 명령어는 다음과 같다.

1줄은 scott/tiger(비밀번호)로 연결하라는 것이다.

2줄은 접속중인 계정이 무엇인지 확인하는 명령어이다.

3줄은 tab 테이블을 조회하는 명령이다. (SELECT문)



그림 15. sqlplus 작업을 위한 명령 프롬프트 실행하기


SQL> exit


exit는 연결을 끊는다는 명령어이다.


c:\Users\{사용자계정명}>sqlplus
Enter user-name: system
Enter password: (비밀번호 입력하기)


관리자 계정으로 접속하는 명령어를 3줄로 요약한 것이다. 
(xe버전 방법은 standard, enterprise의 방법은 미세한 차이가 있을 수도 있음.)



5. HR 계정 - 활성화 하기


Oracle XE 11g에서 제공하는 연습용 계정 HR을 활성화 하는 방법이다.


SQL> alter user hr account unlock;



그림 16. sqlplus 작업을 위한 명령 프롬프트 실행하기


간단한 명령으로 연습용 HR 계정을 활성화 시킬 수 있다.


- 참고로 Oracle 공식 사이트에서 제공하는 메뉴얼도 있으니 참고하면 좋겠다.

https://docs.oracle.com/cd/E17781_01/admin.112/e18585/toc.htm#XEGSG120

반응형
728x90
300x250

[PC활용] 오라클 - 배포 사이트 소개


오라클 배포 사이트에 관한 것이다.

개발 연습 등을 할 때 중요하게 고려하고, 사용하면 좋겠다.



1. Oracle XE 버전


Express Edition은 Oracle Databases를 조금 가볍게 만든 버전이라고 보면 된다.

가벼운 만큼 기능도 제한적일 수도 있다.

그러나 PL/SQL 기능까지 지원한다.


                               표 1. Oracle Databases XE(Express Edition) 버전별 정리 - 배포 사이트


번호

버전

비고

1

Oracle Database Express Edition (XE)

Release 11.2.0.2.0

 https://www.oracle.com/database/technologies/xe-prior-releases.html

2

Oracle Database Express Edition (XE) Release 18.4.0.0.0 (18c)

https://www.oracle.com/database/technologies/xe-downloads.html 



[흥미로운 이야기] - 개발과 데이터베이스

* Hibernate를 고려한다면, Oracle 11을 사용하면 된다.

 - (2020-10-05 현재에는 Oracle 11 이상을 Hibernate에서 사용하려고 하면, 동작하지 않는다.)

 - 태스트 작업을 완료함. (미지원 상태이다.)


(오라클 11 버전이 현재로 보면, 매우 오래된 데이터베이스이다.)

(문제는 Hibernate로 작업해버린 프로젝트들에서는 문제가 조금 있을 수 있다.)

 - JSP 웹을 이야기해보면, Hibernate를 버리고 전환 작업을 한다고 했을 때 상당히 오래걸린다. 

   (영속 프레임워크 중 ORM(Object-Relational-Mapping)이 무조건 좋은 특징을 가지는 게 아님.)


 - 아마 종속되어 있는 프로젝트들이 상당히 많을 것으로 예상된다.
   (Hibernate를 최신 기준에서 태스트를 해본 결과로는 상당히 많은 문제가 있었다.)


= 이런 문제를 하나의 약점이라고 보면 좋겠다.




2. Oracle 일반 버전(Standard, Enterprise Edition)


조금 정리할 필요성이 있어서 작성하게 되었다.


                                             표 2. Oracle Databases 버전별 정리 - 배포 사이트


번호

버전

비고

1

Oracle Database 19c

(19.5 , 19.3)

https://www.oracle.com/database/technologies/oracle-database-software-downloads.html

2

Oracle Database 18c
(18.3, 18.4)

3

Oracle Database 12c Release 2
(12.2.0.1.0) -
Standard Edition 2 and Enterprise Edition

4

Oracle Database 12c Release 1

(12.1.0.2.0) - Enterprise Edition)

(12.1.0.2.0) - Standard Edition (SE2)

5

Oracle Database 11g Release 2

(11.2.0.4.0)

Standard Edition, 

Standard Edition One, 

and Enterprise Edition

6

(11.2.0.2.0)



3. JDBC - Oracle JDBC


자바로 오라클 개발할 때, 가급적이면 최신 버전을 사용하는 것을 추천한다. 

JDBC는 참고로 높은 버전이 호환 된다.


번호

버전 및 프로그램 이름

비고

1

 Oracle Database 19c (19.7) JDBC Driver & UCP

(ojdbc10, ojdbc8)

- 이 버전부터 로그인없이

Free License로 배포함.

 https://www.oracle.com/database/technologies/appdev/jdbc-ucp-19-7-c-downloads.html

2

 Oracle Database 19c (19.3) JDBC Driver & UCP

(ojdbc10)

https://www.oracle.com/database/technologies/appdev/jdbc-ucp-19c-downloads.html 

3

Oracle Database 18c (18.3) JDBC Driver and UCP

(ojdbc8)

 https://www.oracle.com/database/technologies/appdev/jdbc-ucp-183-downloads.html

4

(Oracle Database 12.2.0.1 JDBC Driver & UCP)

ojdbc8-full.tar.gz

https://www.oracle.com/database/technologies/jdbc-ucp-122-downloads.html 

5

 Oracle Database 11g Release 2 (11.2.0.4) JDBC Drivers & UCP

ojdbc-full.tar.gz

(ojdbc6)

https://www.oracle.com/database/technologies/jdbcdriver-ucp-downloads.html 


https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html


ojdbc는 가급적이면 최신버전 사용하는 것을 추천한다.

호환성이 보장되고 다양한 버전을 지원해주고 있다.

반응형

+ Recent posts