Ch. 03 Spring DB연결, DAO

2023. 1. 13. 12:46

1. DB 연결하기

 

<JDBC api>

Maven repository에서 MySQL connector maven 복사해서 pom.xml에 붙혀넣기

        // 스키마의 이름(springbasic)이 다른 경우 알맞게 변경
        String DB_URL = "jdbc:mysql://localhost:3306/springbasic?useUnicode=true&characterEncoding=utf8";

        // DB의 userid와 pwd를 알맞게 변경
        String DB_USER = "root";
        String DB_PASSWORD = "1234";
        String DB_DRIVER = "com.mysql.jdbc.Driver";

        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName(DB_DRIVER);
        ds.setUrl(DB_URL);
        ds.setUsername(DB_USER);
        ds.setPassword(DB_PASSWORD);

 

<Spring jdbc>

 

    public static void main(String[] args) throws Exception{

            ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml");
            DataSource ds = ac.getBean(DataSource.class);

            Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다.

            System.out.println("conn = " + conn);
//          assertTrue(conn!=null);

    }

 

<TDD> - JUnit Test Framework 사용

- TDD(Test Drivien Development) 테스트 주도 개발
- 우리가 실행결과를 직접 눈으로 확인하는게 아니고 JUnit으로 Test 자동화해서 Test 성공여부만 볼 수 있음.
- 메소드 위에 @Test붙이고 메소드는 public void 여야 한다.
- assert문을 통해 테스트 결과 확인 

 

public class DBConnectionTest2Test {
    @Test
    public void main() throws Exception{
        ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml");
        DataSource ds = ac.getBean(DataSource.class);

        Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다.

        System.out.println("conn = " + conn);
        assertTrue(conn!=null); // 괄호 안의 조건식이 true면, 테스트 성공 아니면 실패

    }
}

 

test 성공

 

<@Autowired를 통한 자동 bean 연결>

- @RunWith(SpringJUnit4ClassRunner.class)이 ac를 자동으로 만들어 줌 (성능도 더 좋음)
- @ContextConfiguration(locations = {"file:src/main.webapp/WEB-INF/spring/**/root-context.xml"})로 위치 설정
- ApplicationContext도 주입받아 사용가능 (@Autowired ApplicationContext ac)

 

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/root-context.xml"})
public class DBConnectionTest2Test {
    @Autowired DataSource ds;

    @Test
    public void main() throws Exception{

        Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다.

        System.out.println("conn = " + conn);
        assertTrue(conn!=null); // 괄호 안의 조건식이 true면, 테스트 성공 아니면 실패

    }
}

 

2. 구현해보기

 

<insertUser>

	// 사용자 정보를 user_info 테이블에 저장하는 메서드
	public int insertUser(User user) throws  Exception{

        Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻음

        String sql = "insert into user_info values (?,?,?,?,?,?,now())";

        // PreparedStatement를 통해 values 안에 ? 채우고 밑에서 setString (",' 복잡하지 않게)
        // SQL Injection 공격방지, 성능향상
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setString(1,user.getId());
        pstmt.setString(2,user.getPwd());
        pstmt.setString(3,user.getName());
        pstmt.setString(4,user.getEmail());
        pstmt.setDate(5,new java.sql.Date(user.getBirth().getTime()));
        pstmt.setString(6,user.getSns());

        int rowCnt = pstmt.executeUpdate(); // insert,delete,update

        return rowCnt;
    }

 

<selectUser>

    public User selectUser(String id) throws Exception{

        Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻음

        String sql = "select * from user_info where id = ?";
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setString(1,id);
        ResultSet rs = pstmt.executeQuery(); // insert,delete,update

        if(rs.next()){
            User user = new User();
            user.setId(rs.getString(1));
            user.setPwd(rs.getString(2));
            user.setName(rs.getString(3));
            user.setEmail(rs.getString(4));
            user.setBirth(new Date(rs.getDate(5).getTime()));
            user.setSns(rs.getString(6));
            user.setReg_date(new Date(rs.getTimestamp(7).getTime()));

            return user;
        }

        return null;
    }

 

<deleteUser> 랑 <deleteAll>

public int deleteUser(String id) throws Exception{
    Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻음

    String sql = " delete from user_info where id = ?";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setString(1,id);
    int rowCnt = pstmt.executeUpdate(); // insert,delete,update

    return rowCnt;
}

 

private void deleteAll() throws Exception{

    Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻음

    String sql = "delete from user_info";

    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.executeUpdate(); // insert,delete,update

}

 

<Test>

	@Test
    public void insertUserTest() throws Exception{
        User user = new User("aadasdca","1234","abc","aaa@aaa.com",new java.util.Date(),
        								"fb",new java.util.Date());
        deleteAll();
        int rowCnt = insertUser(user);

        assertTrue(rowCnt==1);
    }

    @Test
    public void selectUserTest() throws Exception{
        deleteAll();

        User user = new User("aadasdca","1234","abc","aaa@aaa.com",new java.util.Date(),
        								"fb",new java.util.Date());
        int rowCnt = insertUser(user);

        User user2 = selectUser("aadasdca");

        assertTrue(user2.getId().equals("aadasdca"));

    }

    @Test
    public void deleteUserTest() throws Exception{
        deleteAll();

        int rowCnt = deleteUser("aadasdca");

        assertTrue(rowCnt == 0);

        User user = new User("aadasdca","1234","abc","aaa@aaa.com",new java.util.Date(),
        									"fb",new java.util.Date());
        rowCnt = insertUser(user);
        assertTrue(rowCnt == 1);

        rowCnt = deleteUser(user.getId());

        assertTrue(rowCnt == 1);

        assertTrue(selectUser(user.getId()) == null);
    }

 

3. DAO의 작성과 적용

 

<DAO(Data Access Object)>

- 데이터에 접근하기 위한 객체
- DAO가 CRUD를 통해 DB에 접근함 (DB 테이블당 하나의 DAO를 작성)

 

<계층(Layer)의 분리>

- Controller에서 DAO를 이용해서 DB를 다룬다 (Controller가 바로 DB에 접근할려고하면 반드시 중복이 생김)
- DAO를 영속계층(Persistence Layer, Data Access Layer) , Controller를 Presentation Layer라고 함 (계층 분리)
- 인터페이스를 이용해 UserDao를 MySQLUserDao, OracleUserDao로 사용하면 편함 

 

[참고] - 제일 좋은 예외처리 방법 

- AutoCloseable을 구현한 객체만 사용 가능
- 수동으로 안해도 자동으로 close 된다. 
// try-with-resources - since jdk7
        try (
                Connection conn = ds.getConnection();
                PreparedStatement pstmt = conn.prepareStatement(sql); // SQL Injection공격, 성능향상
        ){
            pstmt.setString(1, user.getPwd());
            pstmt.setString(2, user.getName());
            pstmt.setString(3, user.getEmail());
            pstmt.setDate(4, new java.sql.Date(user.getBirth().getTime()));
            pstmt.setString(5, user.getSns());
            pstmt.setTimestamp(6, new java.sql.Timestamp(user.getReg_date().getTime()));
            pstmt.setString(7, user.getId());

            rowCnt = pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            return FAIL;
        }

 

<UserDao interface>

- UserDaoImpl에서는 실제 구현체인 UserDaoImpl을 쓰는게 아니고 @Autowired UserDao userDao;로 인터페이스를 사용 
public interface UserDao {
    int deleteUser(String id);

    User selectUser(String id) throws Exception;

    // 사용자 정보를 user_info테이블에 저장하는 메서드
    int insertUser(User user);

    // 매개변수로 받은 사용자 정보로 user_info테이블을 update하는 메서드
    int updateUser(User user);

    void deleteAll() throws Exception;
}

 

<test>

   @Test
    public void updateUser() throws Exception {
        // Date의 시간정보 삭제 년,월,일 만
        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.set(2021,1,1);

        userDao.deleteAll();
        User user = new User("asdf","1234","abc","aaa@aaa.com", new Date(cal.getTimeInMillis()),"fb",new Date(cal.getTimeInMillis()));
        int rowCnt = userDao.insertUser(user);

        assertTrue(rowCnt==1);

        user.setPwd("4321");
        user.setEmail("bbb@bbb");
        rowCnt = userDao.updateUser(user);
        assertTrue(rowCnt == 1);

        User user2 = userDao.selectUser(user.getId());
        System.out.println("user = " + user);
        System.out.println("user2 = " + user2);
        assertTrue(user.equals(user2));

    }

 

BELATED ARTICLES

more