상세 컨텐츠

본문 제목

[Spring 1팀] 14장. 데이터베이스 연동

25-26/Spring

by soyee_ 2026. 1. 13. 10:00

본문

728x90


1. 데이터베이스 설치

1) MySQL 설치

  • 데이터베이스와 상호작용을 위해서 데이터 관리 시스템 (DBMS) 필요
  • DBMS는 MySQL 사용
  •  아래 링크에서 MySQL Installer for Windows 다운로드

https://dev.mysql.com/downloads/

 

MySQL :: MySQL Community Downloads

 

dev.mysql.com

 

2) MySQL 기본 명령

  • SQL은 데이터베이스용 쿼리 언어.
  • 데이터 정의 언어(DDL), 데이터 조작 언어(DML), 데이터 제어 언어(DCL)

 

  • 데이터베이스 관련 명령어
CREATE DATABASE DB이름; // DB 생성
SHOW DATABASE;          // DB 조회
DROP DATABASE DB이름;   // DB 삭제
  • 테이블 관련 명령어
CREATE TABLE 테이블이름(
	필드이름1 자료형1,
    필드이름2 자료형2,
    필드이름3 자료형3,
    필드이름4 자료형4,
    ...
);              // 테이블 생성

SHOW TABLES;    // 테이블 조회
DESC 테이블이름; // 테이블 세부 조회
  • 데이터 조작 관련 명령어
// 데이터 삽입
INSERT INTO 테이블이름 (필드이름1, 필드이름2, 필드이름3...) VALUES (필드값1, 필드값2, 필드값3...)

// 데이터 조회
SELECT 필드이름 FROM 테이블이름;
SELECT 필드이름 FROM 테이블이름 WHERE 검색조건 ORDER BY 필드이름 ASC/DESC GROUP BY 필드이름;

// 데이터 수정
UPDATE 테이블이름 SET 필드이름=필드값 WHERE 검색조건

// 데이터 삭제
DELETE FROM 테이블이름 WHERE 검색조건

2. JDBC

  • 많이 사용하는 데이터 접근 기술 두 가지 → JDBC, JPA

1) JDBC란

  • JDBC = Java DateBase Connectivity
  • DB에 접근할 수 있도록 제공하는 자바 표준 API
  • 연동 구조
    •  JDBC 드라이버: 각 DBMS 회사에서 제공하는 라이브러리 압축파일
    •  JDBC API

  • JDBC의 특징
    • 간결한 코드
    • 자동 리소스 관리
    • SQL 파라미터화

2) JDBC 환경 설정

  • 의존성 라이브러리 추가 (build.gradle)
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation group: 'com.mysql', name: 'mysql-connector-j'
  • 데이터 경로 정보, JDBC 설정 (application.properties)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver   // 드라이버 클래스 이름
spring.datasource.url=jdbc:mysql://localhost:3306/springbootDB // DB URL
spring.datasource.username=root                                // 관리자 계정 아이디
spring.datasource.password=1234                                // 관리자 비밀번호

 


3) JDBC 로 CRUD 처리

  • JdbcTemplate 클래스 : 데이터베이스 연동에서 데이터 조회, 삽입, 수정, 삭제 처리를 담당하는 클래스
  • 선언 부분 추가
@Autowired
JdbcTemplate jdbcTemplate;
  • 데이터 조회
    • queryForObject() 
    • queryForList()
    • query()
// queryForObject()
String sql = "SELECT * FROM person";
Person person = jdbcTemplate.queryForObject(sql, BeanPropertyRowMapper.newInstance(Person.class));
// queryForList()
String sql = "SELECT * FROM person";
List<Map<String, Object>> personList= jdbcTemplate.queryForList(sql);
// query()
String sql = "SELECT * FROM person";
List<Person> personList= jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(Person.class));

 

  • 데이터 삽입, 수정, 삭제 - update() 메서드 이용
    • 삽입
    • 수정
    • 삭제
// 데이터 삽입
String sql = "INSERT INTO person (name, age, email) VALUES (?, ?, ?)";
int result = jdbcTemplate.update(sql, "hong", 20, hong@naver.com);
// 데이터 수정
String sql = "UPDATE person SET name=?, age=?, email=?";
int result = jdbcTemplate.update(sql, hong, 20, hong@naver.com);
// 데이터 삭제
String sql = "DELETE FROM person WHERE name=?";		
int result = jdbcTemplate.update(sql, hong);

 

 

  • Person 테이블에서 데이터 삽입, 수정, 삭제, 조회하기
// ExController.java

@Controller
@RequestMapping("/exam01")
public class Example01Controller {

	// 선언 부분 추가
	@Autowired
	JdbcTemplate jdbcTemplate;
	
	@GetMapping
	public String requestMethod(Model model) {
    	// 데이터 조회
		 String sql = "SELECT * FROM person";
		 List<Person>  personList= jdbcTemplate.query(sql,
					BeanPropertyRowMapper.newInstance(Person.class));		
	
		model.addAttribute("personList", personList);
		return "viewPage01";
	}	
	
	@GetMapping("/new") // 삽입 뷰 페이지
	public String newMethod(Model model) {
		Person person = new Person();
		model.addAttribute("person", person);
		
		return "viewPage01_new";
	}
	
	@PostMapping("/insert")
	public String insertMethod(@ModelAttribute("Person") Person person) {
        // 데이터 삽입
		String sql = "INSERT INTO person (name, age, email) VALUES (?, ?, ?)";
		int result = jdbcTemplate.update(sql, person.getName(), person.getAge(), person.getEmail());
		
		return "redirect:/exam01";
	}
	
	@GetMapping("/edit/{id}") // 수정 뷰 페이지
	public String editMethod(@PathVariable(name = "id") int id, Model model) {
				
		 String sql = "SELECT * FROM person WHERE id =?";		
		 Person person = jdbcTemplate.queryForObject(sql,
				 BeanPropertyRowMapper.newInstance(Person.class), id);
		 model.addAttribute("person", person);
		
		return "viewPage01_edit";
	}	
	
	@PostMapping("/update")
	public String updateMethod(@ModelAttribute("Person") Person person) {
	// 데이터 수정
		String sql = "UPDATE person SET name=?, age=?, email=? WHERE id=?";
		int result = jdbcTemplate.update(sql, person.getName(), person.getAge(), person.getEmail(), person.getId()); 		
				
		return "redirect:/exam01";
	}
	
	@GetMapping("/delete/{id}")
	public String deleteMethod(@PathVariable(name = "id") int id) {
    	// 데이터 삭제
		String sql = "DELETE FROM person WHERE id=?";		
		int result = jdbcTemplate.update(sql, id);
		
		return "redirect:/exam01";
	}

}

3. JPA

1) JPA란

  • JPA = Java Persistent API
  • 객체-관계 매핑(ORM)을 위한 자바 표준 API
더보기

ORM(Object Relational Mapping)

- 객체-관계 매핑. 클래스와 테이블을 자동으로 연결

- 클래스와 테이블은 호환이 되지 않지만, SQL 문을 자동으로 생성하여 이를 해결

- 객체를 통해 간접적으로 데이터베이스를 조작할 수 있게 되었음

  • JPA 구조 
    • 하이버네이트(Hibernate): JPA는 인터페이스이므로 구현체가 따로 필요. 하이버네이트가 구현체 역할
    • DB-객체를 매핑할 뿐, 통신을 위해서는 JDBC 사용 필요함

  • JPA의 특징
    • 객체 지향적 접근
    • 자동화된 쿼리 생성
    • 캐시 및 지연 로딩
  • JPA 주요 애너테이션


2) JPA 환경 설정

  • 의존성 라이브러리 추가 (build.gradle)
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation group: 'com.mysql', name: 'mysql-connector-j'
  • 데이터 경로 정보, JDBC 설정 (application.properties)
// 데이터 소스
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver   // 드라이버 클래스 이름
spring.datasource.url=jdbc:mysql://localhost:3306/springbootDB // DB URL
spring.datasource.username=root                                // 관리자 계정 아이디
spring.datasource.password=1234                                // 관리자 비밀번호

// JPA 설정
spring.jpa.database=mysql                                        // 데이터베이스 종류
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect // 데이터베이스 플랫폼
spring.jpa.hibernate.ddl-auto=update                             // 엔티티의 변경부분만 적용
spring.jpa.generate-ddl=false                                    // 시작할 때 스키마 초기화x
spring.jpa.show-sql=true                                         // SQL문 로깅 활성화
spring.jpa.properties.hibernate.format_sql=true                  // 로그/콘솔에 SQL문 출력

3) JPA 로 CRUD 처리

  • 데이터 조회, 삽입, 수정, 삭제를 처리하는 방법 3가지
  1. JpaRepository 기본 메서드
    • 확장(상속) 인터페이스 생성
    • 기본 키와 설정된 데이터 타입 일치
// Member.java
@Entity
@Data	
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id; // 키 타입
    private String name;
    private int age;
    private String email;
}

// MemberRepository.java
@Repository
public interface MemberRepository02 extends JpaRepository<Member, Integer> { // 설정 데이터 타입 일치 	
	 	 
}
@Controller
@RequestMapping("/exam02")
public class Example02Controller {
	
	@Autowired
	MemberRepository02 repository;
	
	@GetMapping
	public String viewHomePage(Model model) {		 
		// 데이터 조회
		Iterable<Member> memberList = repository.findAll();		
		
		model.addAttribute("memberList", memberList);
		return "viewPage02";
	}
	
	@GetMapping("/new") // 삽입 뷰 페이지
	public String newMethod(Model model) {
		Member member = new Member();
		model.addAttribute("member", member);
		return "viewPage02_new";
	}
	
	@PostMapping("/insert")
	public String insertMethod(@ModelAttribute("member") Member member) {
		// 데이터 삽입
		repository.save(member);		
		return "redirect:/exam02";
	}
	
	@GetMapping("/edit/{id}") // 수정 뷰 페이지
	public String editMethod(@PathVariable(name = "id") int id, Model model) {
		Optional<Member> member = repository.findById(id);
		 model.addAttribute("member", member);
		return "viewPage02_edit";
	}	
	
	@PostMapping("/update")
	public String updateMethod(@ModelAttribute("member") Member member) {
		// 데이터 수정
		repository.save(member);					
		return "redirect:/exam02";
	}
	
	@GetMapping("/delete/{id}")
	public String deleteMethod(@PathVariable(name = "id") int id) {
		// 데이터 삭제
		repository.deleteById(id);
		return "redirect:/exam02";
	}

}

 

 

2. @Query

  • 사용자 정의 쿼리문을 작성 가능해서 복잡한 작업을 하게 함
  • @Query 에서 nativeQuery 옵션  → false(default)는 JPQL, true는 SQL
  • @Transactional: 오류가 발생하면 모두 롤백.
  • @Modifying: INSERT, DELETE, UPDATE 사용할 경우에 무조건 사용
@Repository
public interface MemberRepository03 extends JpaRepository<Member, Integer> {	
	 // 데이터 조회
    @Transactional
    @Query(value = "SELECT entity FROM Member entity")         //jsql
    //@Query(value = "SELECT * FROM Member", nativeQuery=true) //sql
    public List<Member> selectMethod();

    @Transactional
    @Query(value = "SELECT entity FROM Member entity WHERE id = :e_id")     //jsql
    //@Query(value = "SELECT * FROM Member WHERE id = ?", nativeQuery=true) //sql
    public Member  selectMethodById(@Param("e_id") int id);	


    // 데이터 삽입
    @Transactional
    @Modifying 
    @Query(value = "INSERT INTO Member(name, age, email)  VALUES(:e_name, :e_age, :e_email)")
    // @Query(value = "INSERT INTO Member(name, age, email) VALUES(?,?,?)", nativeQuery=true) 
    public int insertMethod(@Param("e_name") String name, @Param("e_age") int age, @Param("e_email") String email);

    @Transactional
    @Modifying 
    // 데이터가 많을 경우, 이렇게 할 수도 있음
    @Query(value = "INSERT INTO Member(name, age, email)  VALUES(:#{#entity.name}, :#{#entity.age}, :#{#entity.email})")
    public int insertMethod2(@Param("entity") Member member);


    // 데이터 수정
    @Transactional
    @Modifying 
    @Query(value = "UPDATE Member SET  name =:e_name, age =:e_age, email =:e_email WHERE id = :e_id")
    // @Query(value = "UPDATE Member SET  name =?, age =?, email =? WHERE id = ?", nativeQuery=true)
    public int updateMethod(@Param("e_name") String name, @Param("e_age") int age, @Param("e_email") String email, @Param("e_id") int id);

    @Transactional
    @Modifying 
    // 데이터가 많을 경우, 이렇게 할 수도 있음
    @Query(value = "UPDATE Member SET  name =:#{#entity.name}, age =:#{#entity.age}, email =:#{#entity.email} WHERE id = :#{#entity.id}")	
    public int updateMethod2(@Param("entity") Member member);


     // 데이터 삭제
    @Transactional
    @Modifying 
    @Query(value = "DELETE FROM Member WHERE id = :e_id")
    //@Query(value = "DELETE FROM Member WHERE id = ?", nativeQuery=true) 
    public int deleteMethod(@Param("e_id") int id);

}
@Controller
@RequestMapping("/exam03")
public class Example03Controller {
	
	@Autowired
	MemberRepository03 repository;
	
	@GetMapping // 데이터 조회	
	public String viewHomePage(Model model) {		
		Iterable<Member> memberList = repository.selectMethod();
		System.out.println(memberList);
		model.addAttribute("memberList", memberList);
		return "viewPage03";
	}
	
	@GetMapping("/new") // 삽입 뷰 페이지
	public String newMethod(Model model) {
		Member member = new Member();
		model.addAttribute("member", member);
		return "viewPage03_new";
	}
	
	@PostMapping("/insert") // 데이터 삽입
	public String insertMethod(@ModelAttribute("member") Member member) {		
		repository.insertMethod(member.getName(), member.getAge(), member.getEmail());
		//repository.insertMethod2(member);
		return "redirect:/exam03";
	}
	
	@GetMapping("/edit/{id}") // 수정 뷰 페이지
	public String editMethod(@PathVariable(name = "id") int id, Model model) {
		Member  member = repository.selectMethodById(id);
		 model.addAttribute("member", member);
		return "viewPage03_edit";
	}	
	
	@PostMapping("/update") // 데이터 수정
	public String updateMethod(@ModelAttribute("member") Member member) {
		repository.updateMethod( member.getName(), member.getAge(), member.getEmail(), member.getId());	
		//repository.updateMethod2(member);
		return "redirect:/exam03";
	}
	
	@GetMapping("/delete/{id}") // 데이터 삭제
	public String deleteMethod(@PathVariable(name = "id") int id) {	
		repository.deleteMethod(id);
		return "redirect:/exam03";
	}
}

 

3. EntityManager

  • 엔티티를 관리하는 인터페이스
  • EntityManager, PersistenceContext 사용
    • PersistenceContext: EntityManager를 빈으로 주입할 때 사용하는 어노테이션
@Repository
public class MemberRepository04 {
    @PersistenceContext //
    private EntityManager entityManager;
    
    
   	  public List<Member> selectMethod(){ // 데이터 조회
   		String jpql = "SELECT entity FROM Member entity";
    	Query query = entityManager.createQuery(jpql);
    	List<Member>  member = query.getResultList();   
    	return member;
    }   	  
   	
		
	 public Member selectMethodById(int id) { // 아이디 지정
		 String jpql = "SELECT entity FROM Member entity WHERE id =:e_id";
		 Query query = entityManager.createQuery(jpql);
		 query.setParameter("e_id", id);
		 Member  member =(Member) query.getSingleResult();		
		 return member;
	 }
		
	
	 @Transactional
	 public void insertMethod(Member member) {	// 데이터 삽입	
		 String jpql = "INSERT INTO Member(name, age, email)  VALUES(:e_name, :e_age, :e_email)";
		 Query query = entityManager.createQuery(jpql);
		 query.setParameter("e_name", member.getName());
		 query.setParameter("e_age", member.getAge());
		 query.setParameter("e_email", member.getEmail());
		 query.executeUpdate();
		  
	 }
	 
	 @Transactional
	 public void updateMethod(Member member) { // 데이터 수정
		String jpql =  "UPDATE Member SET  name =:e_name, age =:e_age, email =:e_email WHERE id = :e_id";
			
		 Query query = entityManager.createQuery(jpql);
		 query.setParameter("e_name", member.getName());
		 query.setParameter("e_age", member.getAge());	
		 query.setParameter("e_email", member.getEmail());	
		 query.setParameter("e_id", member.getId());	
		 query.executeUpdate();
	 }
	
	 
	
	@Transactional	
	 public void deleteMethod(int id) { // 데이터 삭제, 아이디 지정
		 String jpql = "DELETE FROM Member WHERE id = :e_id";
		 Query query = entityManager.createQuery(jpql);
		 query.setParameter("e_id", id);
		 query.executeUpdate();		 
	
	 };
	
    
}
@Controller
@RequestMapping("/exam04")
public class Example04Controller {
	
	@Autowired //
	MemberRepository04 repository;
	
	@GetMapping // 데이터 조회
	public String viewHomePage(Model model) {
	
				 
		List<Member> memberList = repository.selectMethod();
		System.out.println(memberList);
		model.addAttribute("memberList", memberList);
		return "viewPage04";
	}
	
	@GetMapping("/new") // 삽입 뷰 페이지
	public String newMethod(Model model) {
		Member member = new Member();
		model.addAttribute("member", member);
		
		return "viewPage04_new";
	}
	
	@PostMapping("/insert") // 데이터 삽입
	public String insertMethod(@ModelAttribute("member") Member member) {
		
		//repository.save(member);	
		repository.insertMethod(member);
		System.out.println("member                " + member);
		return "redirect:/exam04";
	}

	@GetMapping("/edit/{id}") // 수정 뷰 페이지
	public String editMethod(@PathVariable(name = "id") int id, Model model) {				
		
		Member member = repository.selectMethodById(id);
		
		 model.addAttribute("member", member);
		
		return "viewPage04_edit";
	}	

	@PostMapping("/update") // 데이터 수정
	public String updateMethod(@ModelAttribute("member") Member member) {
		
		repository.updateMethod(member);
		//repository.updateMethod2(member.getId(), member.getName(), member.getPrice() );
		//repository.save(member);					
		return "redirect:/exam04";
	}
	
	@GetMapping("/delete/{id}") // 데이터 삭제
	public String deleteMethod(@PathVariable(name = "id") int id) {
			
		//repository.deleteById(id);
		repository.deleteMethod(id);
		return "redirect:/exam04";
	}

}

 

 

 


4)  엔티티 간의 연관 관계 매핑

  • 원래 객체는 조인을 통해 참조가 불가능하지만
  • JPA가 객체 간의 연관 관계를 설정하여 엔티티를 참조할 수 있게 함.
  • 주 엔티티 - 외래키 가짐. 등록,수정,삭제 가능
  • 상대 엔티티 - 읽기만 가능
  • @OneToOne(1:1), @OneToMany(1:N), @ManyToOne(N:1), @ManyToMany(N:N)

 

1. OneToOne 연관 관계

  • 1대 1 관계
  • 외래키는 유일성을 가져야 함

 

  • 외래키 사용 단방향
    • 주 엔티티가 상대 엔티티만 참조
    • 주 엔티티가 외래 키를 가짐
    • 주 엔티티 외래키 = 상대 엔티티의 기본키
@Entity
@Data
public class Product {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	private String name;
	private float price;
	
	// 외래키 단방향
	@OneToOne(cascade = CascadeType.ALL)	
        @JoinColumn(name = "detail_id") // 상대엔티티_기본키
	private Detail detail;
}

 

  • 외래키 사용 양방향
    • 관계를 맺은 두 엔티티가 서로 참조
@Entity
@Data
public class Detail {
	
    private String description;
    private float weight; 
    private float height;
    private float width;
	
    @OneToOne(mappedBy = "detail") // 상대 엔티티 이름
    private Product product; // 주 엔티티 클래스 선언
}
@Entity
@Data
public class Product {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	private String name;
	private float price;
    
    // 양방향
	 @OneToOne(mappedBy = "product", cascade = CascadeType.ALL)
	 @PrimaryKeyJoinColumn	 
	 private Detail detail;
}

 

  • 공유 기본키 사용 양방향
    • 주 엔티티 기본키 = 상대 엔티티 외래키
// Product.java 주엔티티

@Entity
@Data
public class Product {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	private String name;
	private float price;
    
    // 양방향
	 @OneToOne(mappedBy = "product", cascade = CascadeType.ALL) 
	 @PrimaryKeyJoinColumn  // 주 엔티티 기본키를 상대 엔티티 외래키로 설정
	 private Detail detail; // 상대 엔티티 선언

	
	
	 
	 
}
// Detail.java 상대엔티티
@Entity
@Data
public class Detail {

	
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String description;
    private float weight; 
    private float height;
    private float width;
    
    //공유양방향
    @OneToOne
    @JoinColumn(name = "product_id")  
    @MapsId // 외래키를 기본키로 설정
    private Product product;
   
    
    
   
}

 

 

2. @OneToMany, @ManyToOne

  • 항상 N쪽이 외래키 가짐 -> 주 엔티티
  • N:1 관계 매핑 단방향
    • 주엔티티 : 상대 엔티티를 참조하는 외래키 가짐
    • 주엔티티에서 설정
@Entity
@Data
public class Player {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

  
    private String name;

    @ManyToOne
    @JoinColumn(name = "team_id") // 상대 엔티티 이름_ 기본키
    private Team team; // 상대 엔티티 클래스 선언
}
  • 1:N 관계 매핑 양방향
    • 관계 맺은 두 엔티티가 서로 참조
    • 자바 컬렉션(Collection, List, Set, Map) 사용 -> 초기화
@Entity
@Data

public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    //양방향 매핑
    @OneToMany(mappedBy = "team", cascade = CascadeType.ALL)
    List<Player> player = new ArrayList<>();
}

 


출처: 송미영, 스프링 부트 완전 정복 : 개념부터 실전 프로젝트까지 , 길벗(2024)

Coner Spring1

Editor: soyee

728x90

관련글 더보기