> For the complete documentation index, see [llms.txt](https://www.pentestwiki.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.pentestwiki.com/web-application/java/java-data-access/database-access-methods.md).

# Database Access Methods

Java 환경에서 DBMS에 접근하는 방식은 통상적으로 아래 중 하나의 방식을 사용합니다.

* JDBC / JDBC Template
* iBATIS, MyBatis
* JPA / Hibernate

### JDBC

JDBC(Java Database Connectivity)는 Java 언어로 데이터베이스에 접속할 수 있는 API를 의미합니다.

```java
@Override
public Member save(Member member) {
    String sql = "INSERT INTO MEMBER(member_id, money) VALUES (?, ?)";

    Connection con = null;
    PreparedStatement pstmt = null;

    try {
        con = getConnection();
        pstmt = con.prepareStatement(sql);
        pstmt.setString(1, member.getMemberId());
        pstmt.setInt(2, member.getMoney());
        pstmt.executeUpdate();
        return member;
    } catch (SQLException e) {
        throw exceptionTranslator.translate("save", sql, e);
    } finally {
        close(con, pstmt, null);
    }
}
```

위 코드는 사용자가 입력한 Member 객체의 memberId, money 값을 테이블에 저장하는 기능을 수행합니다.

현재는 PreparedStatement 구문을 사용하여 사용자의 입력값을 안전하게 처리하지만, 아래의 코드를 사용할 경우 SQL 인젝션에 취약할 수 있습니다.

```java
String sql = "SELECT * FROM BOARD WHERE TITLE LIKE '%" + keyword + "%'";
```

### JDBC Template

JDBC Template은 JDBC를 더 편하게 사용하고 코드의 간결성을 위해서 사용하는 Spring 클래스입니다.

아래 코드는 위에서 사용했던 JDBC 코드의 기능을 그대로하여 호출하는 코드입니다.

```java
private final JdbcTemplate template;

public MemberRepository(DataSource dataSource) {
    this.template = new JdbcTemplate(dataSource);
}

@Override
public Member save(Member member) {
    String sql = "INSERT INTO MEMBER(member_id, money) VALUES (?, ?)";
    template.update(sql, member.getMemberId(), member.getMoney());
    return member;
}
```

JDBC와 JDBC Template의 원리는 완전히 동일하지만 개발자가 코드로 직접 구현하는지에 대한 차이점입니다.

JDBC Template을 사용할 경우 Connection, PreparedStatement, 자원 해제, 예외처리 등을 자동으로 템플릿이 처리하여 개발자가 직접 관리할 필요가 없습니다.

### SQL Mapper

SQL Mapper는 SQL 쿼리를 직접 xml 파일로 작성해두고, 네임스페이스와 아이디 기반으로 사전에 정의한 쿼리들을 Java에서 실행하는 방식입니다.

대표적으로 iBATIS와 MyBatis가 있으며 현재는 둘 중 MyBatis가 주로 사용됩니다.

#### iBATIS

SQL Mapper를 사용할 때는 namespace가 클래스, id가 메소드인 것과 같이 호출되어 사용됩니다.

아래 코드에서는 `id:findMemberById`, `namespace:Member` 형태이므로 호출시 `Member.findMemberById`로 호출할 수 있습니다.

{% code title="sql.xml" %}

```xml
<sqlMap namespace="Member">
    <select id="findMemberById" parameterClass="string" resultClass="Member">
        SELECT member_id, money
        FROM MEMBER
        WHERE member_id = #memberId#
    </select>
</sqlMap>
```

{% endcode %}

{% code title="service.java" %}

```java
Member member = (Member) sqlMapClient.queryForObject(
    "Member.findMemberById",
    memberId
);
```

{% endcode %}

iBATIS 환경에서는 PreparedStatement를 처리할 때 `#param#` 을 사용하고, 처리하지 않을 경우 `$param$` 를 사용합니다.

따라서 Java 환경에서 iBATIS를 사용하는 것이 식별될 경우, 소스 파일 경로에서 `$param$` 처리된 인자값을 찾고 그 값이 사용자로부터 전달되는지 확인하는 것이 빠른 코드 분석 방법이 될 수 있습니다.

#### MyBatis

MyBatis는 iBATIS의 후속 프로젝트이기 때문에 일부 문법에서의 차이를 제외하고는 유사합니다.

{% code title="sql.xml" %}

```xml
<mapper namespace="com.example.mapper.MemberMapper">

    <select id="findMemberById" parameterType="string" resultType="Member">
        SELECT member_id, money
        FROM MEMBER
        WHERE member_id = #{memberId}
    </select>

</mapper>
```

{% endcode %}

{% code title="service.java" %}

```java
Member member = session.selectOne(
    "com.example.mapper.MemberMapper.findMemberById",
    memberId
);
```

{% endcode %}

동일한 동작을 하는 코드를 iBATIS와 MyBatis로 구분했을 때, 큰 차이는 다음과 같습니다.

* 태그 이름 (sqlMap vs mapper)
* 네임스페이스 양식 (Member vs com.example.mapper.MemberMapper)
* 파라미터 전달 (`#param#` vs `#{param}`)

MyBatis도 iBATIS처럼 `namespace.id` 기반으로 SQL 쿼리를 직접 호출할 수 있지만, Java 인터페이스 기능이 공식적으로 지원되기 때문에 실무에서는 인터페이스로 구현해두는 경우가 일반적입니다.

예를 들어 개발자가 아래의 인터페이스의 FQCN(Fully Qualified Class Name)을 MyBatis로 정의한 xml의 네임스페이스에 그대로 적용시킨다면, 인터페이스를 통해 쿼리를 실행할 수 있습니다.

xml의 namespace 전체 경로와 동일하게 한다면, 인터페이스를 통해 MyBatis에 등록해둔 쿼리를 실행할 수 있습니다.

```java
public interface MemberMapper {
    Member findMemberById(String memberId);
}
```

```java
@Service
public class MemberService {

    private final MemberMapper memberMapper;

    public MemberService(MemberMapper memberMapper) {
        this.memberMapper = memberMapper;
    }

    public Member findMember(String memberId) {
        Member member = memberMapper.findMemberById(memberId);
        return member;
    }
}
```

## References

{% embed url="<https://velog.io/@nimoh/Spring-JdbcTemplate%EC%9D%98-%EA%B8%B0%EB%B3%B8>" %}

{% embed url="<https://back-end-developer.tistory.com/entry/ibatis-mybatis-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%B4%9D%EC%A0%95%EB%A6%AC>" %}

{% embed url="<https://mininkorea.tistory.com/39>" %}
