o. Transaction Management(미완) - kimxavi/spring_tutorial GitHub Wiki
데이터베이스 트랜잭션은 작업을 하나의 단위로 다루려는 일련의 행동이다. 그러한 작업들은 완전히 완료되거나 모든 것에 아무런 영향을 끼치지 않거나이다. 데이터베이스 트랜잭션은 데이터의 완전성과 일관성을 보장하는 대규모 어플리케이션 RDBMS의 중요한 부분이다. 트랜잭션의 컨셉은 아래와 같이 표현된다.
- Atomicity : 트랜잭션은 연산의 한 단위로 다뤄져야한다. 이것이 의미하는 것은 전체 연산이 완전히 성공하던가 실패하던가이다.
- Consistency : 이것은 데이터베이스의 참조 무결성의 일관성을 나타낸다. 테이블의 고유한 기본키 등등.
- Isolation : 같은 집합, 같은 시간에 진행되는 많은 트랜잭션들이 서로 데이터 변형을 방지하며 격리되어야 한다는 것이다.
- Durability : 트랜잭션이 완료 됐을 때, 이 트랜잭션의 결과는 영구적이고 시스템의 고장 때문에 데이터베이스로부터 삭제되지 않아야한다.
실제 RDBMS 데이터베이스 시스템은 트랜잭션 각각에 대해서 네가지 속성을 보장해준다. 단순한 트랜잭션의 관점은 데이터베이스에서 SQL을 사용하며 아래와 같이 발생한다.
- begin transaction command를 사용해서 트랜잭션을 사용한다.
- deleted, update, insert 등 다양한 작업이 SQL을 써서 이뤄진다.
- 만약 모든 작업이 성공적이라면 commit 아니라면 모든 작업이 rollback이 이뤄진다.
스프링 프레임 워크는 다른 기본 트랜잭션 관리 API의 상단에 추상화 계층을 제공한다. 스프링의 트랜잭션 지원은 POJOs에 트랜잭션 능력을 더함으로써 EJB transactions를 대체하는 걸 제공하도록 돕는다. 스프링은 프로그램적이고 선언적인 트랜잭션을 지원한다. EJBs는 어플리케이션 서버를 요구한다. 그러나 스프링 트랜잭션 관리는 어플리케이션이 필요 없이 추가되어진다.
로컬 트랜잭션은 JDBC 연결과 같이 하나의 트랜잭션적인 리소스에 명시적이다. 그에 반해, 글로벌 트랜잭션은 분산 시스템의 트랜잭션 같은 여러 트랜잭션 자원에 걸쳐 수 있습니다.
로컬 트랜잭션 관리는 컴퍼넌트와 리소스가 한 곳에 있는 중앙 집중형 컴퓨팅 환경에 효율적이다 그리고 트랜잭션 관리는 단일 시스템에서 실행중인 로컬 데이터 매니저를 포함한다. 로컬 트랜잭션은 추가하기가 더 쉽다.
글로벌 트랜잭션 관리는 모든 자원이 여러 시스템에서 분산되는 분산 시스템 환경에서 요구된다. 이 경우 트랜잭션 관리는 로컬 및 글로벌 수준에서 모두 수행해야합니다. 분산 또는 전역 트랜잭션은 여러 시스템에서 실행되고, 그것의 실행은 글로벌 트랜잭션 관리 시스템과 모든 관련 시스템의 모든 로컬 데이터 관리자 간의 조정이 필요합니다.
- Programmatic : 이것은 프로그래밍인 도움으로 트랜잭션을 관리하는 것을 의미한다. 이것은 유연적이나 유지보수가 힘들다.
- Declarative : 이것이 의미하는 것은 트랜잭션 관리를 비즈니스 코드와 분리하는 것 이다. 어노테이션과 XML 설정 파일로 트랜잭션을 관리한다.
Declarative 트랜잭션이 Programmatic 보다 덜 유연하더라도 더 선호된다. crosscutting 관심사로써 declarative 트랜잭션 관리는 AOP 접근과 함께 모듈화된다. 스프링은 스프링 AOP 프레임워크를 통해서 Declarative 트랜잭션 관리를 지원한다.
Declarative 트랜잭션 관리 접근은 소스에 하드코딩을 대신해 설정의 도움으로 트랜잭션을 관리하도록 해준다. 이 것이 의미하는 것은 트랜잭션 관리를 비즈니스 코드와 분리할 수 있다는 것이다. 어노테이션이나 XML 설정을 사용해서 트랜잭션을 관리한다. bean 설정에 트랜잭션일 메소드를 명시해준다.
- tx:advice 태그를 사용한다. 이것은 트랜잭션 처리 advice 를 생성하고 이와 동시에 트랜잭션으로 만들고 트랜잭션 advice를 참조하는 모든 메소드를 매치해서 pointcut를 정의한다.
- 만약 메소드 이름이 트랜잭션 설정에 포함되어 있다면, 생성된 advice에 메소드 호출 전에 트랜잭션이 실행될 것이다.
- 대상 메소드는 try/catch 블록 안에서 실행되어진다.
- 만약 일반적으로 메소드가 끝나면 AOP advice는 트랜잭션을 성공적으로 commit 할 것이다. 아니면 rollback을 실행한다.
CREATE TABLE Student(
ID INT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
AGE INT NOT NULL,
PRIMARY KEY (ID)
);
CREATE TABLE Marks(
SID INT NOT NULL,
MARKS INT NOT NULL,
YEAR INT NOT NULL
);
SID는 Student의 ID . 외래키.
StudentDAO.java
package com.tutorialspoint;
import java.util.List;
import javax.sql.DataSource;
public interface StudentDAO {
/**
* This is the method to be used to initialize
* database resources ie. connection.
*/
public void setDataSource(DataSource ds);
/**
* This is the method to be used to create
* a record in the Student and Marks tables.
*/
public void create(String name, Integer age, Integer marks, Integer year);
/**
* This is the method to be used to list down
* all the records from the Student and Marks tables.
*/
public List<StudentMarks> listStudents();
}
StudentMarks.java
package com.tutorialspoint;
public class StudentMarks {
private Integer age;
private String name;
private Integer id;
private Integer marks;
private Integer year;
private Integer sid;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public void setMarks(Integer marks) {
this.marks = marks;
}
public Integer getMarks() {
return marks;
}
public void setYear(Integer year) {
this.year = year;
}
public Integer getYear() {
return year;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public Integer getSid() {
return sid;
}
}
StudentMarksMapper.java
package com.tutorialspoint;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
public class StudentMarksMapper implements RowMapper<StudentMarks> {
public StudentMarks mapRow(ResultSet rs, int rowNum) throws SQLException {
StudentMarks studentMarks = new StudentMarks();
studentMarks.setId(rs.getInt("id"));
studentMarks.setName(rs.getString("name"));
studentMarks.setAge(rs.getInt("age"));
studentMarks.setSid(rs.getInt("sid"));
studentMarks.setMarks(rs.getInt("marks"));
studentMarks.setYear(rs.getInt("year"));
return studentMarks;
}
}
StudentJDBCTemplate.java
package com.tutorialspoint;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
public class StudentJDBCTemplate implements StudentDAO{
private JdbcTemplate jdbcTemplateObject;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public void create(String name, Integer age, Integer marks, Integer year){
try {
String SQL1 = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL1, name, age);
// Get the latest student id to be used in Marks table
String SQL2 = "select max(id) from Student";
int sid = jdbcTemplateObject.queryForInt( SQL2 );
String SQL3 = "insert into Marks(sid, marks, year) " +
"values (?, ?, ?)";
jdbcTemplateObject.update( SQL3, sid, marks, year);
System.out.println("Created Name = " + name + ", Age = " + age);
// to simulate the exception.
throw new RuntimeException("simulate Error condition") ;
} catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
throw e;
}
}
public List<StudentMarks> listStudents() {
String SQL = "select * from Student, Marks where Student.id=Marks.sid";
List <StudentMarks> studentMarks=jdbcTemplateObject.query(SQL,
new StudentMarksMapper());
return studentMarks;
}
}
MainApp.java
package com.tutorialspoint;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("Beans.xml");
StudentDAO studentJDBCTemplate =
(StudentDAO)context.getBean("studentJDBCTemplate");
System.out.println("------Records creation--------" );
studentJDBCTemplate.create("Zara", 11, 99, 2010);
studentJDBCTemplate.create("Nuha", 20, 97, 2010);
studentJDBCTemplate.create("Ayan", 25, 100, 2011);
System.out.println("------Listing all the records--------" );
List<StudentMarks> studentMarks = studentJDBCTemplate.listStudents();
for (StudentMarks record : studentMarks) {
System.out.print("ID : " + record.getId() );
System.out.print(", Name : " + record.getName() );
System.out.print(", Marks : " + record.getMarks());
System.out.print(", Year : " + record.getYear());
System.out.println(", Age : " + record.getAge());
}
}
}
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Initialization for data source -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/TEST"/>
<property name="username" value="root"/>
<property name="password" value="cohondob"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="create"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="createOperation"
expression="execution(* com.tutorialspoint.StudentJDBCTemplate.create(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
</aop:config>
<!-- Initialization for TransactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Definition for studentJDBCTemplate bean -->
<bean id="studentJDBCTemplate"
class="com.tutorialspoint.StudentJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
------Records creation--------
Created Name = Zara, Age = 11
Exception in thread "main" java.lang.RuntimeException: simulate Error condition
throw new RuntimeException를 제거하면 트랜잭션이 완료되고 데이터가 들어간다.