본문 바로가기
Programming/Spring Boot

Spring 기반의 DB 연동 - springframework 및 SpringBoot 트랜잭션 처리

by yoon9i 2024. 7. 2.

5> springframework 및 SpringBoot 트랜잭션 처리
- Service 빈에서 @Transactional 어노테이션으로 트랜잭션 처리한다.
- @Transactional

  클래스 레벨: 클래스내의 모든 메서드가 트랜잭션 으로 처리됨.
  메서드 레벨: 지정된 메서드에서만 트랜잭션 으로 처리됨.

 

package com.exam;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import com.exam.dto.TodoDTO;
import com.exam.service.TodoMyBatisMySQLServiceImpl;

@SpringBootApplication
public class Application implements CommandLineRunner{

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
	ApplicationContext ctx;

	@Override
	public void run(String... args) throws Exception {
		logger.info("logger:ApplicationContext:{}",ctx);
		
		TodoMyBatisMySQLServiceImpl service =
				ctx.getBean("todoService",TodoMyBatisMySQLServiceImpl.class);
				
		// 저장
//		service.save(new TodoDTO(5, "github공부", "홍길동"));
		
		// 수정
//		service.update(new TodoDTO(5, "git 및 github 공부", "홍길동"));
		
		// 삭제
//		service.delete(2);
		
		// 전체조회
		List<TodoDTO> list = service.findAll();
		System.out.println(list);
		
		// 트랜잭션 호출
		// 1. delete 성공, save 실패 하는 경우
		// tx(delete, save)
		service.tx(5, new TodoDTO(4, "github공부", "홍길동"));
		// save 에서 오류가 나서 rollback 처리가 되버려서 delet 가 안됬다
		
	}

}
package com.exam.dto;

import org.apache.ibatis.type.Alias;

@Alias("TodoDTO")
public class TodoDTO {
	int id;
	String name;
	String author;
	public TodoDTO() {
		super();
		// TODO Auto-generated constructor stub
	}
	public TodoDTO(int id, String name, String author) {
		super();
		this.id = id;
		this.name = name;
		this.author = author;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	@Override
	public String toString() {
		return "TodoDTO [id=" + id + ", name=" + name + ", author=" + author + "]";
	}
	
	
}
package com.exam.repository;

import java.util.List;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.exam.dto.TodoDTO;

@Repository("todoRepository")
public class TodoMyBatisMySQLRepository {
	
//	@Autowired
	SqlSessionTemplate session;

	public TodoMyBatisMySQLRepository(SqlSessionTemplate session) {
		super();
		this.session = session;
	}
	
	// 저장
	public int save(TodoDTO todo) {
		int n = session.insert("com.exam.config.TodoMapper.save",todo);
		
		return n;
	}
	
	// 삭제
	public int delete(int id) {
		int n = session.delete("com.exam.config.TodoMapper.delete", id);
		
		return id;
	}
	
	// 수정
	public int update(TodoDTO todo) {
		int n = session.delete("com.exam.config.TodoMapper.update", todo);
		
		return n;
	}
	
	// 단일조회
	public TodoDTO findById(int id) {
		return session.selectOne("com.exam.config.TodoMapper.findById",id);
	}
	
	// 전체조회
	public List<TodoDTO> findAll() {
		return session.selectList("com.exam.config.TodoMapper.findAll");
	}
	
}
package com.exam.service;

import java.util.List;

import com.exam.dto.TodoDTO;

public interface TodoMyBatisMySQLService {
	public int save(TodoDTO todo); // 저장
	public int delete(int id); // 삭제
	public int update(TodoDTO todo); // 수정
	public TodoDTO findById(int id); // 단일조회
	public List<TodoDTO> findAll(); // 전체조회
	
	// 트랜잭션 실습
	public void tx(int id, TodoDTO todo);
}
package com.exam.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.exam.dto.TodoDTO;
import com.exam.repository.TodoMyBatisMySQLRepository;

@Service("todoService")
public class TodoMyBatisMySQLServiceImpl implements TodoMyBatisMySQLService {
	
//	@Autowired
	TodoMyBatisMySQLRepository repository;
	
	// @Autowired 대신에 생성자로 주입
	public TodoMyBatisMySQLServiceImpl(TodoMyBatisMySQLRepository repository) {
		super();
		this.repository = repository;
	}

	// 저장
	@Override
	public int save(TodoDTO todo) {
		// TODO Auto-generated method stub
		return repository.save(todo);
	}

	// 삭제
	@Override
	public int delete(int id) {
		// TODO Auto-generated method stub
		return repository.delete(id);
	}

	// 수정
	@Override
	public int update(TodoDTO todo) {
		// TODO Auto-generated method stub
		return repository.update(todo);
	}

	// 단일조회
	@Override
	public TodoDTO findById(int id) {
		// TODO Auto-generated method stub
		return repository.findById(id);
	}

	// 전체조회
	@Override
	public List<TodoDTO> findAll() {
		// TODO Auto-generated method stub
		return repository.findAll();
	}

	// 트랜잭션 실습
	// id 로 삭제, todo 로 삽입
	@Override
	@Transactional // 삭제와 삽입이 @Transactional 로 묶인다.
	public void tx(int id, TodoDTO todo) {
		// 삭제
		repository.delete(id);
		
		// 삽입
		repository.save(todo);
	}

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.exam.config.TodoMapper">
	<insert id="save" parameterType="TodoDTO">
		insert into todo (id,name,author)
		values (#{id}, #{name}, #{author})
	</insert>
	
	<delete id="delete" parameterType="int">
		delete from todo
		where id = #{id}
	</delete>
	
	<update id="update" parameterType="TodoDTO">
		update todo
		set name = #{name}, author= #{author}
		where id = #{id}
	</update>
	
	<select id="findById" parameterType="int" resultType="TodoDTO">
		select id,name,author
		from todo
		where id = #{id}
	</select>
	
	<select id="findAll" resultType="TodoDTO">
		select id,name,author
		from todo
	</select>
</mapper>
# application.properties
logging.level.org.springframework=info

# DB 연동위한 4가지 정보 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=1234

# 별칭
mybatis.type-aliases-package=com.exam.dto

# Mapper 등록
# mybatis.mapper-locations=com/exam/config/*Mapper.xml : 모든 Mapper를 등록
# mybatis.mapper-locations=com/exam/config/TodoMapper.xml
mybatis.mapper-locations=com/exam/config/*Mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
	http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.18</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.exam</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		
  <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
  <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.1.4</version>
  </dependency>

  <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.33</version>
  </dependency>		
		

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>