본문 바로가기

학원/복기

[Spring] 데이터베이스 연동

xyz.itwill08.dao 패키지 생성

 

DataSource 객체를 스프링 컨테이너에게 제공받아 사용하는 방법

  • DataSource 객체는 다수의 Connection 객체를 미리 생성하여 저장하고 있는 객체이다. DBCP(DataBase Connection Pool)이라고 한다.
  • Spirng Bean Configuration File에서 DataSource 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록하여 스프링 컨테이너에게 제공받아 사용할 수 있다. 
  • DataSource 인터페이스를 상속받은 자식클래스는 Spring 프레임워크에서 제공해주는 spring-jdbc 라이브러리를 빌드 처리하면 된다. (메이븐 사용 : pom.xml) 
  • DataSource 관련 라이브러리 외에 Oracle Driver 관련 라이브러리도 프로젝트에 빌드 처리해야 한다.

 

 

 spring-jdbc 라이브러리를 빌드 처리 해주자.

 

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

 

 

오라클 드라이버도 빌드 처리 해준다.

 

https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc11/23.2.0.0

 

 

pom.xml

 

 

DataSource 인터페이스를 상속받은 자식 클래스를 Spring Bean으로 등록해주자 

  • spring-jdbc 라이브러리의 DriverManagerDataSource 클래스를 사용한다.
  • DBCP(DataBase Connection Pool) 기능을 제공하는 DataSource 객체를 생성한다.
  • DataSource 객체 필드에 Connection 객체를 생성하기 위한 값을 전달하여 저장한다. (Setter Injection)

 

08_dao.xml

 

DataSourceApp

public class DataSourceApp {
	public static void main(String[] args) throws SQLException {
		ApplicationContext context=new ClassPathXmlApplicationContext("08_dao.xml");
		DataSource dataSource=context.getBean("dataSource", DataSource.class);
		System.out.println("==========================================================");
		System.out.println("dataSource = "+dataSource);
		Connection connection=dataSource.getConnection();
		System.out.println("connection = "+connection);
		connection.close();
		System.out.println("==========================================================");
		((ClassPathXmlApplicationContext)context).close();
	
	}
}

 

 

 


DTO  클래스 및 DAO 클래스가 상속받을 인터페이스 선언 

//학생정보를 저장하기 위한 DTO 클래스
@Data
public class Student {
	private int no;
	private String name;
	private String phone;
	private String address;
	private String birthday;
}


//StudentDAOImpl 클래스(DAO 클래스)가 상속받을 인터페이스
public interface StudentDAO {
	int insertStudent(Student student);
	int updateStudent(Student student);
	int deleteStudent(int no);
	Student selectStudent(int no);
	List<Student> selectStudentList();
}

 

 

SpringDAO 기능을 이용하여 DAO 클래스를 작성할 것이다.

 

이를 위해선 spring-jdbc 라이브러리가 반드시 프로젝트에 빌드 처리 되어 있어야 한다. (위의 과정에서 이미 빌드 처리 했기 때문에 생략하겠다.)

 

JdbcTemplate 객체의 메소드를 호출하여 DAO 클래스의 메소드를 작성해주면 된다. 

 

 

* JdbcTemplate 객체의 메소드 정리

 

JdbcTemplate.update(String sql, Object ... args) 

  • SQL 명령(INSERT, UPDATE, DELETE)을 DBMS 서버에 전달하여 실행하는 메소드이며, 조작행의 갯수(int)를 반환한다.
  • 매개변수에는 DBMS 서버에 전달하여 실행할 SQL 명령과 InParameter(?) 대신 사용될 값을 차례대로 나열하여 제공하면 된다. 
  • SQL 명령의 InParameter(?) 갯수만큼 args 매개변수에 값을  반드시 전달해야 한다.

JdbcTemplate.queryForObjcet(String sql, RowMapper<T> rowMapper, Object ... args)

  • SQL 명령(SELECT)을 DBMS 서버에 전달하여 실행하는 메소드
  • 단일행의 검색결과를 하나의 Java 객체로 반환하기 위해 사용한다. 
  • 매개변수에는 DBMS 서버에 전달하여 실행할 SQL 명령과 검색행을 Java 객체로 변환하기 위한 매핑정보를 제공하는 RowMapper 객체와 InParameter(?) 대신 사용될 값을 차례대로 나열하여 제공하면 된다.
    • RowMapper 객체
      • RowMapper 객체는 검색행을 Java 객체로 변환하여 제공하기 위한 매핑정보가 저장된 객체이다.
      • 검색행의 컬럼값을 Java 객체 필드에 저장하기 위한 매핑정보를 제공한다. 
      • RowMapper 인터페이스를 상속받는 자식클래스로 객체를 생성해주면 된다. - 익명의 내부클래스로 객체 생성 
      • RowMapper 객체를 생성할 때 사용되는 제네릭에는 검색행을 변환할 Java 객체의 자료형을 설정하면 된다. 
      • RowMapper 인터페이스를 상속받는 자식클래스는 mapRow() 추상 메소드를 오버라이드 선언해주어야 한다.
      • mapRow() 메소드의 매개변수로 ResultSet 객체를 제공받아 Java 객체로 변환하는 명령을 작성해주면 된다.

 

JdbcTemplate.query(String sql, RowMapper<T> rowMapper, Object ... args)

  • SQL 명령(SELECT)을 DBMS 서버에 전달하여 실행하는 메소드
  • 다수행의 검색결과를 List 객체로 반환하기 위해 사용한다. - 하나의 검색행은 List 객체의 요소로 저장된다.
  • 매개변수에는 DBMS 서버에 전달하여 실행할 SQL 명령과 검색행을 Java 객체로 변환하기 위한 매핑정보를 제공하는 RowMapper 객체와 InParameter(?) 대신 사용될 값을 차례대로 나열하여 제공하면 된다.

 

StudentDAOImpl (DAO 클래스)

//SpringDAO 기능을 이용하여 DAO 클래스 작성
public class StudentDAOImpl implements StudentDAO {
	//JdbcTemplate 객체를 저장하기 위한 필드 선언 - DI 기능을 이용하여 JdbcTemplate를 필드에 저장
	// => Spring Bean Configuration File에서 DAO 클래스를 Spring Bean으로 등록할 때 JdbcTemplate 클래스의 
	//Spring Bean를 제공받아 의존성을 주입한다. (Setter Injection)
	@Setter
	private JdbcTemplate jdbcTemplate;
	
	//학생정보를 전달받아 STUDENT 테이블에 학생정보를 삽입하고 삽입행의 갯수를 반환하는 메소드 
	@Override
	public int insertStudent(Student student) {
		String sql="insert into student values(?,?,?,?,?)";
		return jdbcTemplate.update(sql, student.getNo(), student.getName()
				, student.getPhone(), student.getAddress(), student.getBirthday());
	}

	//학생정보를 전달받아 STUDENT 테이블에 저장된 학생정보를 변경하고 변경행의 갯수를 반환하는 메소드 
	@Override
	public int updateStudent(Student student) {
		String sql="update student set name=?, phone=?, address=?, birthday=? where no=?";
		return jdbcTemplate.update(sql,student.getName(), student.getPhone()
				, student.getAddress(), student.getBirthday(), student.getNo());
	}
	
	//학생번호를 전달받아 STUDENT 테이블에 저장된 학생정보를 삭제하고 삭제행의 갯수를 반환하는 메소드 
	@Override
	public int deleteStudent(int no) {
		return jdbcTemplate.update("delete from student where no=?", no);
	}
	
	//학생번호를 전달받아 STUDENT 테이블에 저장된 학생정보를 검색하여 DTO 객체로 반환하는 메소드 
	@Override
	public Student selectStudent(int no) {
		try {
			String sql="select no, name, phone, address, birthday from student where no=?";
			/*
			return jdbcTemplate.queryForObject(sql, new RowMapper<Student>() {
				
				@Override
				public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
					Student student=new Student();
					student.setNo(rs.getInt("no"));
					student.setName(rs.getString("name"));
					student.setPhone(rs.getString("phone"));
					student.setAddress(rs.getString("address"));
					student.setBirthday(rs.getString("birthday"));
					return student;
				}
			}, no);
			*/
			
			return jdbcTemplate.queryForObject(sql, new StudentRowMapper(), no);
			//queryForObject() 메소드로 전달된 SELECT 명령에 대한 검색행이 없는 경우 발생되는 예외
			//(queryForObject() 메소드에서만 발생되는 예외)
		} catch (EmptyResultDataAccessException e) {
			return null;
		}
	}
	
	//STUDENT 테이블에 저장된 모든 학생정보를 검색하여 List 객체로 반환하는 메소드 
	@Override
	public List<Student> selectStudentList() {
		String sql="select no, name, phone, address, birthday from student order by no";
		/*
		return jdbcTemplate.query(sql, new RowMapper<Student>() {
			
			@Override
			public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
				Student student=new Student();
				student.setNo(rs.getInt("no"));
				student.setName(rs.getString("name"));
				student.setPhone(rs.getString("phone"));
				student.setAddress(rs.getString("address"));
				student.setBirthday(rs.getString("birthday"));
				return student;
			}
		});
		*/
		return jdbcTemplate.query(sql, new StudentRowMapper());
	}
	
	//RowMapper 객체를 생성하기 위해 내부 클래스 선언
	public class StudentRowMapper implements RowMapper<Student> {
		@Override
		public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
			Student student=new Student();
			student.setNo(rs.getInt("no"));
			student.setName(rs.getString("name"));
			student.setPhone(rs.getString("phone"));
			student.setAddress(rs.getString("address"));
			student.setBirthday(rs.getString("birthday"));
			return student;
		}
	}
}

 

 

 

Service 클래스를 만들어보자

그전에 Service 클래스가 상속받을 인터페이스를 먼저 선언해주자

 

 

StudentService / StudentServiceImpl

//Service 클래스가 상속받을 인터페이스
public interface StudentService {
	void addStudent(Student student);
	void modifyStudent(Student student);
	void removeStudent(int no);
	Student getStudent(int no);
	List<Student> getStudentList();
}


public class StudentServiceImpl implements StudentService {
	//Student 인터페이스를 상속받은 자식클래스의 객체를 저장하기 위한 필드 
	// => Spring Bean Configuration File에서 Service 클래스를 Spring Bean으로 등록할 때 StudentDAO 
	//인터페이스를 상속받은 자식클래스의 Spring Bean를 제공받아 의존성을 주입한다. (Setter Injection)
	@Setter
	private StudentDAO studentDAO;

	@Override
	public void addStudent(Student student) {
		studentDAO.updateStudent(student);
		
	}

	@Override
	public void modifyStudent(Student student) {
		studentDAO.updateStudent(student);
		
	}

	@Override
	public void removeStudent(int no) {
		studentDAO.deleteStudent(no);
		
	}

	@Override
	public Student getStudent(int no) {
		return studentDAO.selectStudent(no);
	}

	@Override
	public List<Student> getStudentList() {
		return studentDAO.selectStudentList();
	}
}

 

08_dao.xml

...
    	<!-- JdbcTemplate 클래스를 Spring Bean으로 등록 -->
	<!-- => JdbcTemplate 클래스의 dataSource 필드에 DataSource 인터페이스를 상속받은 자식클래스의 
	Spring Bean(객체)를 제공받아 의존성 주입(DI) - Setter Injection -->
	<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<!-- StudentDAO 인터페이스를 상속받은 자식클래스(StudentDAOImpl 클래스)을 Spring Bean으로 등록 -->
	<!-- => StudentDAOImpl 클래스의 jdbcTemplate 필드에 JdbcTemplate 클래스의 Spring Bean(객체)를
	제공받아 의존성 주입(DI) - Setter Injection -->
	<bean class="xyz.itwill08.dao.StudentDAOImpl" id="studentDAO">
		<property name="jdbcTemplate" ref="jdbcTemplate"/>
	</bean>
	
	<!-- StudentService 인터페이스를 상속받은 자식클래스(StudentServiceImpl 클래스)을 Spring Bean으로 등록 -->
	<!-- => StudentServiceImpl 클래스의 studentDAO 필드에 StudentDAO 인터페이스를 상속받은
	자식클래스의 Spring Bean(객체)를 제공받아 의존성 주입(DI) - Setter Injection -->
	<bean class="xyz.itwill08.dao.StudentServiceImpl" id="studentService">
		<property name="studentDAO" ref="studentDAO"/>
	</bean>
...

 

 

StudentApp

public class StudentApp {
	public static void main(String[] args) {
		ApplicationContext context=new ClassPathXmlApplicationContext("08_dao.xml");
		StudentService service=context.getBean("studentService", StudentService.class);
		System.out.println("==========================================================");
		/*
		Student newStudent=new Student();
		newStudent.setNo(6000);
		newStudent.setName("홍경래");
		newStudent.setPhone("010-3189-9622");
		newStudent.setAddress("서울시 도봉구");
		newStudent.setBirthday("1999-05-05");
		service.addStudent(newStudent);
		*/
		
		/*
		Student searchStudent=service.getStudent(6000);
		System.out.println(searchStudent);//toString() 메소드를 호출하여 필드값을 반환받아 출력 
		searchStudent.setName("로빈훗");
		searchStudent.setBirthday("1999-02-05");
		service.modifyStudent(searchStudent);
		*/
		
		service.removeStudent(6000);
		
		List<Student> studentList=service.getStudentList();
		for(Student student : studentList) {
			System.out.println("학번 = "+student.getNo()+", 이름 = "+student.getName()
					+", 전화번호 = "+student.getPhone()+", 주소 = "+student.getAddress()
					+", 생년월일 = "+student.getBirthday().substring(0, 10));
		}
		System.out.println("==========================================================");
		((ClassPathXmlApplicationContext)context).close();
	}
}