-
Notifications
You must be signed in to change notification settings - Fork 300
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[JDBC 라이브러리 구현하기 - 3단계] 베베(최원용) 미션 제출합니다. (#483)
* refactor: MySqlDao -> JdbcDao * feat: 트랜잭션 구현 * refactor: PreparedStatement 메모리 누수 방지 * feat: 트랜잭션 commit, rollback 후처리 메서드 구현 * refactor: Transactional과 TransactionManager 통합
- Loading branch information
1 parent
99f5548
commit 48d2d9c
Showing
12 changed files
with
167 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
app/src/main/java/com/techcourse/dao/JdbcUserHistoryDao.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.techcourse.dao; | ||
|
||
import com.techcourse.domain.UserHistory; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
|
||
public class JdbcUserHistoryDao implements UserHistoryDao { | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
|
||
public JdbcUserHistoryDao(JdbcTemplate jdbcTemplate) { | ||
this.jdbcTemplate = jdbcTemplate; | ||
} | ||
|
||
@Override | ||
public void log(final UserHistory userHistory) { | ||
final var sql = "insert into user_history (user_id, account, password, email, created_at, created_by) values (?, ?, ?, ?, ?, ?)"; | ||
jdbcTemplate.update(sql, | ||
userHistory.getUserId(), | ||
userHistory.getAccount(), | ||
userHistory.getPassword(), | ||
userHistory.getEmail(), | ||
userHistory.getCreatedAt(), | ||
userHistory.getCreateBy() | ||
); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,9 @@ | ||
package com.techcourse.dao; | ||
|
||
import com.techcourse.domain.UserHistory; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
public interface UserHistoryDao { | ||
|
||
public class UserHistoryDao { | ||
void log(final UserHistory userHistory); | ||
|
||
private static final Logger log = LoggerFactory.getLogger(UserHistoryDao.class); | ||
|
||
private final DataSource dataSource; | ||
|
||
public UserHistoryDao(final DataSource dataSource) { | ||
this.dataSource = dataSource; | ||
} | ||
|
||
public UserHistoryDao(final JdbcTemplate jdbcTemplate) { | ||
this.dataSource = null; | ||
} | ||
|
||
public void log(final UserHistory userHistory) { | ||
final var sql = "insert into user_history (user_id, account, password, email, created_at, created_by) values (?, ?, ?, ?, ?, ?)"; | ||
|
||
Connection conn = null; | ||
PreparedStatement pstmt = null; | ||
try { | ||
conn = dataSource.getConnection(); | ||
pstmt = conn.prepareStatement(sql); | ||
|
||
log.debug("query : {}", sql); | ||
|
||
pstmt.setLong(1, userHistory.getUserId()); | ||
pstmt.setString(2, userHistory.getAccount()); | ||
pstmt.setString(3, userHistory.getPassword()); | ||
pstmt.setString(4, userHistory.getEmail()); | ||
pstmt.setObject(5, userHistory.getCreatedAt()); | ||
pstmt.setString(6, userHistory.getCreateBy()); | ||
pstmt.executeUpdate(); | ||
} catch (SQLException e) { | ||
log.error(e.getMessage(), e); | ||
throw new RuntimeException(e); | ||
} finally { | ||
try { | ||
if (pstmt != null) { | ||
pstmt.close(); | ||
} | ||
} catch (SQLException ignored) {} | ||
|
||
try { | ||
if (conn != null) { | ||
conn.close(); | ||
} | ||
} catch (SQLException ignored) {} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,15 +9,15 @@ | |
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
class MySqlUserDaoTest { | ||
class JdbcUserDaoTest { | ||
|
||
private UserDao userDao; | ||
|
||
@BeforeEach | ||
void setup() { | ||
DatabasePopulatorUtils.execute(DataSourceConfig.getInstance()); | ||
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceConfig.getInstance()); | ||
userDao = new MySqlUserDao(jdbcTemplate); | ||
userDao = new JdbcUserDao(jdbcTemplate); | ||
final User user = new User("gugu", "password", "[email protected]"); | ||
userDao.insert(user); | ||
} | ||
|
6 changes: 3 additions & 3 deletions
6
...echcourse/service/MockUserHistoryDao.java → ...ourse/service/MockJdbcUserHistoryDao.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,28 @@ | ||
package com.techcourse.service; | ||
|
||
import com.techcourse.config.DataSourceConfig; | ||
import com.techcourse.dao.MySqlUserDao; | ||
import com.techcourse.dao.UserHistoryDao; | ||
import com.techcourse.dao.JdbcUserDao; | ||
import com.techcourse.dao.JdbcUserHistoryDao; | ||
import com.techcourse.dao.UserDao; | ||
import com.techcourse.domain.User; | ||
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Disabled; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.dao.DataAccessException; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
@Disabled | ||
class UserServiceTest { | ||
|
||
private JdbcTemplate jdbcTemplate; | ||
private MySqlUserDao userDao; | ||
private UserDao userDao; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
this.jdbcTemplate = new JdbcTemplate(DataSourceConfig.getInstance()); | ||
this.userDao = new MySqlUserDao(jdbcTemplate); | ||
this.userDao = new JdbcUserDao(jdbcTemplate); | ||
|
||
DatabasePopulatorUtils.execute(DataSourceConfig.getInstance()); | ||
final var user = new User("gugu", "password", "[email protected]"); | ||
|
@@ -32,8 +31,8 @@ void setUp() { | |
|
||
@Test | ||
void testChangePassword() { | ||
final var userHistoryDao = new UserHistoryDao(jdbcTemplate); | ||
final var userService = new UserService(userDao, userHistoryDao); | ||
final var userHistoryDao = new JdbcUserHistoryDao(jdbcTemplate); | ||
final var userService = new UserService(DataSourceConfig.getInstance(), userDao, userHistoryDao); | ||
|
||
final var newPassword = "qqqqq"; | ||
final var createBy = "gugu"; | ||
|
@@ -47,8 +46,8 @@ void testChangePassword() { | |
@Test | ||
void testTransactionRollback() { | ||
// 트랜잭션 롤백 테스트를 위해 mock으로 교체 | ||
final var userHistoryDao = new MockUserHistoryDao(jdbcTemplate); | ||
final var userService = new UserService(userDao, userHistoryDao); | ||
final var userHistoryDao = new MockJdbcUserHistoryDao(jdbcTemplate); | ||
final var userService = new UserService(DataSourceConfig.getInstance(), userDao, userHistoryDao); | ||
|
||
final var newPassword = "newPassword"; | ||
final var createBy = "gugu"; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
jdbc/src/main/java/org/springframework/jdbc/transaction/TransactionExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.springframework.jdbc.transaction; | ||
|
||
import java.sql.Connection; | ||
|
||
public interface TransactionExecutor<T> { | ||
|
||
T execute(final Connection connection); | ||
|
||
} |
80 changes: 80 additions & 0 deletions
80
jdbc/src/main/java/org/springframework/jdbc/transaction/TransactionManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package org.springframework.jdbc.transaction; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.SQLException; | ||
|
||
public class TransactionManager { | ||
|
||
private static final ThreadLocal<Connection> connectionInThread = new ThreadLocal<>(); | ||
|
||
private final DataSource dataSource; | ||
|
||
public TransactionManager(DataSource dataSource) { | ||
this.dataSource = dataSource; | ||
} | ||
|
||
public <T> T execute(final TransactionExecutor<T> transactionExecutor) { | ||
try { | ||
Connection connection = begin(); | ||
T response = transactionExecutor.execute(connection); | ||
commit(); | ||
return response; | ||
} catch (RuntimeException e) { | ||
rollback(); | ||
throw e; | ||
} | ||
} | ||
|
||
public Connection begin() { | ||
Connection connection = getConnection(); | ||
try { | ||
connection.setAutoCommit(false); | ||
} catch (SQLException e) { | ||
throw new RuntimeException(e); | ||
} | ||
connectionInThread.set(connection); | ||
return connection; | ||
} | ||
|
||
public void commit() { | ||
Connection connection = getConnection(); | ||
try { | ||
connection.commit(); | ||
} catch (SQLException e) { | ||
throw new RuntimeException(e); | ||
} | ||
init(connection); | ||
} | ||
|
||
public void rollback() { | ||
Connection connection = getConnection(); | ||
try { | ||
connection.rollback(); | ||
} catch (SQLException e) { | ||
throw new RuntimeException(e); | ||
} | ||
init(connection); | ||
} | ||
|
||
private void init(final Connection connection) { | ||
try { | ||
connection.close(); | ||
} catch (SQLException e) { | ||
throw new RuntimeException(e); | ||
} | ||
connectionInThread.remove(); | ||
} | ||
|
||
public Connection getConnection() { | ||
if (connectionInThread.get() == null) { | ||
try { | ||
return dataSource.getConnection(); | ||
} catch (SQLException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
return connectionInThread.get(); | ||
} | ||
|
||
} |