๐Ÿ“Œ Spring JDBC & DataSource ์™„๋ฒฝ ์ •๋ฆฌ ๐Ÿš€ ์‹ค์Šต + ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

My Pale Blue Dotยท2025๋…„ 4์›” 24์ผ
0

SPRING

๋ชฉ๋ก ๋ณด๊ธฐ
11/36
post-thumbnail

๐Ÿ“… ๋‚ ์งœ

2024-04-24


๐Ÿ“ ํ•™์Šต ๋‚ด์šฉ


1๏ธโƒฃ DataSource๋ž€?

DataSource๋Š” DB ์—ฐ๊ฒฐ(Connection) ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ JDBC ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.

โœ… ์™œ DataSource๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?

  • DriverManager ๋ฐฉ์‹์€ ๋งค๋ฒˆ ์ƒˆ๋กœ์šด ์—ฐ๊ฒฐ์„ ์ƒ์„ฑ โž” ๋น„ํšจ์œจ์ 
  • DataSource๋Š” ์ปค๋„ฅ์…˜ ํ’€(Connection Pool) ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜์–ด, ์—ฐ๊ฒฐ์„ ์žฌ์‚ฌ์šฉ โž” ์„ฑ๋Šฅ ์ตœ์ ํ™”

๐Ÿ”น ์‹ค๋ฌด ์ ์šฉ ๋ฐฉ์‹

  • ๊ฐœ๋ฐœ ํ™˜๊ฒฝ : DriverManagerDataSource ์‚ฌ์šฉ (๊ฐ„๋‹จ ์„ค์ •)
  • ์šด์˜ ํ™˜๊ฒฝ : ์ปค๋„ฅ์…˜ ํ’€ (DBCP, HikariCP) + JNDI ์—ฐ๋™

2๏ธโƒฃ Spring JDBC ์„ค์ •

๐Ÿ“‚ pom.xml ํ•ต์‹ฌ ์˜์กด์„ฑ

<!-- Spring JDBC -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.7.RELEASE</version>
</dependency>

<!-- MySQL ๋“œ๋ผ์ด๋ฒ„ -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>9.2.0</version>
</dependency>

<!-- ์ปค๋„ฅ์…˜ ํ’€ -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.12.0</version>
</dependency>
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>6.3.0</version>
</dependency>

โš ๏ธ ์ฃผ์˜: MySQL Connector ๋ˆ„๋ฝ ์‹œ DB ์—ฐ๊ฒฐ ๋ถˆ๊ฐ€!


๐Ÿ“‚ root-context.xml ์„ค์ •

<!-- DataSource ๋นˆ ๋“ฑ๋ก -->
<bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost/testDB"/>
    <property name="username" value="root"/>
    <property name="password" value="1234"/>
</bean>

<!-- ํŒจํ‚ค์ง€ ์Šค์บ” -->
<context:component-scan base-package="com.example.app.domain.dao" />
<context:component-scan base-package="com.example.app.domain.service" />

3๏ธโƒฃ DAO, Service, Controller ๊ตฌํ˜„

๐Ÿ“Œ MemoDaoImpl

@Repository
public class MemoDaoImpl {

    @Autowired
    private DataSource dataSource1;  // DataSource ์ฃผ์ž…

    /**
     * ๋ฉ”๋ชจ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
     */
    public int insert(MemoDto memoDto) throws SQLException {
        Connection con = dataSource1.getConnection();  // ์ปค๋„ฅ์…˜ ํš๋“
        PreparedStatement pstmt = con.prepareStatement(
            "INSERT INTO tbl_memo VALUES (?, ?, ?, ?)"
        );
        pstmt.setInt(1, memoDto.getId());
        pstmt.setString(2, memoDto.getText());
        pstmt.setString(3, memoDto.getWriter());
        pstmt.setTimestamp(4, Timestamp.valueOf(memoDto.getCreateAt()));  // LocalDateTime ๋ณ€ํ™˜
        return pstmt.executeUpdate();
    }
}

๐Ÿ“Œ MemoServiceImpl

@Service
public class MemoServiceImpl {

    @Autowired
    private MemoDaoImpl memoDaoImpl;

    public boolean registraionMemo(MemoDto memoDto) throws SQLException {
        int result = memoDaoImpl.insert(memoDto);
        return result > 0;  // ์„ฑ๊ณต ์—ฌ๋ถ€ ๋ฐ˜ํ™˜
    }
}

๐Ÿ“Œ MemoController

@Controller
@RequestMapping("/memo")
@Slf4j
public class MemoController {

    @Autowired
    private MemoServiceImpl memoServiceImpl;

    @PostMapping("/add")
    public void add_post(@Valid MemoDto dto, BindingResult bindingResult, Model model) throws Exception {
        if(bindingResult.hasErrors()) {
            for(FieldError error : bindingResult.getFieldErrors()) {
                model.addAttribute(error.getField(), error.getDefaultMessage());
            }
            return;  // ์œ ํšจ์„ฑ ์‹คํŒจ ์‹œ ์ค‘๋‹จ
        }
        boolean isAdded = memoServiceImpl.registraionMemo(dto);
    }

    @GetMapping("/ex")
    public void ex1_1() throws FileNotFoundException {
        throw new FileNotFoundException("ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
    }
}

4๏ธโƒฃ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ (JUnit5 + ๊ฒ€์ฆ)

@ExtendWith(SpringExtension.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
class DataSourceTests {

    @Autowired
    private MemoDaoImpl memoDaoImpl;

    @Test
    void testInsert() throws Exception {
        int result = memoDaoImpl.insert(new MemoDto(1, "Test", "tester@example.com", LocalDateTime.now(), null));
        assert(result == 1);  // ์‚ฝ์ž… ์„ฑ๊ณต ์—ฌ๋ถ€ ํ™•์ธ
    }
}

5๏ธโƒฃ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… & ์‹คํ–‰ ๋กœ๊ทธ

๐Ÿ”น setTimestamp ์˜ค๋ฅ˜

Cannot convert value of type 'java.time.LocalDateTime' to required type 'java.sql.Timestamp'

โžก๏ธ ํ•ด๊ฒฐ:

pstmt.setTimestamp(4, Timestamp.valueOf(memoDto.getCreateAt()));

๐Ÿ”น SQL ์ž๋ฆฌ์ˆ˜ ์˜ค๋ฅ˜

java.sql.SQLException: Parameter index out of range

โžก๏ธ VALUES (?, ?, ?, ?) ์ž๋ฆฌ์ˆ˜ ์ฒดํฌ!


๐Ÿ“„ ์‹คํ–‰ ๋กœ๊ทธ

INFO : POST /memo/add... MemoDto(id=123, text=asdfasdf, writer=example@example.com, createAt=2025-04-24T17:11, dateTest=null)

dateTest=null : @InitBinder ์ฃผ์„ ์ฒ˜๋ฆฌ๋กœ ๋ฐ”์ธ๋”ฉ ์•ˆ ๋œ ์ƒํƒœ


๐Ÿ”ฅ ์ •๋ฆฌ

  • DataSource ์„ค์ • = ์„ฑ๋Šฅ ์ตœ์ ํ™”์˜ ์‹œ์ž‘
  • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋Š” ๋ฐ˜๋“œ์‹œ return ์ฒ˜๋ฆฌ
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ์•ˆ์ •์„ฑ ํ™•๋ณด
  • ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ๋Š” ์ฒดํฌ๋ฆฌ์ŠคํŠธํ™” ํ•˜์ž!

๐Ÿ”— ์ฐธ๊ณ  ์ž๋ฃŒ


profile
Here, My Pale Blue.๐ŸŒ

0๊ฐœ์˜ ๋Œ“๊ธ€