207 lines
5.2 KiB
Plaintext
207 lines
5.2 KiB
Plaintext
---
|
|
description:
|
|
globs:
|
|
alwaysApply: true
|
|
---
|
|
# 데이터베이스 가이드
|
|
|
|
## 데이터베이스 설정
|
|
|
|
### PostgreSQL 연결
|
|
- **JNDI 리소스명**: `plm`
|
|
- **드라이버**: `org.postgresql.Driver`
|
|
- **설정 파일**: [context.xml](mdc:tomcat-conf/context.xml)
|
|
|
|
### 초기 데이터
|
|
- **스키마 파일**: [ilshin.pgsql](mdc:db/ilshin.pgsql)
|
|
- **역할 설정**: [00-create-roles.sh](mdc:db/00-create-roles.sh)
|
|
|
|
## MyBatis 설정
|
|
|
|
### SqlSession 사용 패턴
|
|
```java
|
|
public List<Map<String, Object>> getData(Map<String, Object> paramMap) {
|
|
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
|
try {
|
|
return sqlSession.selectList("namespace.queryId", paramMap);
|
|
} finally {
|
|
sqlSession.close(); // 반드시 리소스 해제
|
|
}
|
|
}
|
|
```
|
|
|
|
### 트랜잭션 처리
|
|
```java
|
|
public void saveData(Map<String, Object> paramMap) {
|
|
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false); // autoCommit=false
|
|
try {
|
|
sqlSession.insert("namespace.insertQuery", paramMap);
|
|
sqlSession.update("namespace.updateQuery", paramMap);
|
|
sqlSession.commit(); // 명시적 커밋
|
|
} catch (Exception e) {
|
|
sqlSession.rollback(); // 오류 시 롤백
|
|
throw e;
|
|
} finally {
|
|
sqlSession.close();
|
|
}
|
|
}
|
|
```
|
|
|
|
## 매퍼 XML 작성 가이드
|
|
|
|
### 기본 구조
|
|
```xml
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
<mapper namespace="admin">
|
|
<!-- 쿼리 정의 -->
|
|
</mapper>
|
|
```
|
|
|
|
### 파라미터 바인딩
|
|
```xml
|
|
<!-- 안전한 파라미터 바인딩 (권장) -->
|
|
<select id="selectUser" parameterType="map" resultType="map">
|
|
SELECT * FROM users
|
|
WHERE user_id = #{userId}
|
|
AND status = #{status}
|
|
</select>
|
|
|
|
<!-- 동적 조건 처리 -->
|
|
<select id="selectUserList" parameterType="map" resultType="map">
|
|
SELECT * FROM users
|
|
WHERE 1=1
|
|
<if test="userName != null and userName != ''">
|
|
AND user_name LIKE '%' || #{userName} || '%'
|
|
</if>
|
|
<if test="deptCode != null and deptCode != ''">
|
|
AND dept_code = #{deptCode}
|
|
</if>
|
|
</select>
|
|
```
|
|
|
|
### PostgreSQL 특화 문법
|
|
```xml
|
|
<!-- 시퀀스 사용 -->
|
|
<insert id="insertData" parameterType="map">
|
|
INSERT INTO table_name (id, name, reg_date)
|
|
VALUES (nextval('seq_table'), #{name}, now())
|
|
</insert>
|
|
|
|
<!-- 숫자 타입 캐스팅 -->
|
|
<update id="updateData" parameterType="map">
|
|
UPDATE table_name
|
|
SET status = #{status}
|
|
WHERE id = #{id}::numeric
|
|
</update>
|
|
|
|
<!-- 재귀 쿼리 (메뉴 트리 구조) -->
|
|
<select id="selectMenuTree" resultType="map">
|
|
WITH RECURSIVE menu_tree AS (
|
|
SELECT * FROM menu_info WHERE parent_id = 0
|
|
UNION ALL
|
|
SELECT m.* FROM menu_info m
|
|
JOIN menu_tree mt ON m.parent_id = mt.id
|
|
)
|
|
SELECT * FROM menu_tree ORDER BY path
|
|
</select>
|
|
```
|
|
|
|
## 주요 테이블 구조
|
|
|
|
### 메뉴 관리
|
|
- **MENU_INFO**: 메뉴 정보
|
|
- **MENU_AUTH_GROUP**: 메뉴 권한 그룹
|
|
- **AUTH_GROUP**: 권한 그룹 정보
|
|
|
|
### 사용자 관리
|
|
- **USER_INFO**: 사용자 정보
|
|
- **DEPT_INFO**: 부서 정보
|
|
- **USER_AUTH**: 사용자 권한
|
|
|
|
### 코드 관리
|
|
- **CODE_INFO**: 공통 코드
|
|
- **CODE_CATEGORY**: 코드 카테고리
|
|
|
|
## 데이터베이스 개발 모범 사례
|
|
|
|
### 1. 파라미터 검증
|
|
```xml
|
|
<select id="selectData" parameterType="map" resultType="map">
|
|
SELECT * FROM table_name
|
|
WHERE 1=1
|
|
<if test="id != null and id != ''">
|
|
AND id = #{id}::numeric
|
|
</if>
|
|
</select>
|
|
```
|
|
|
|
### 2. 페이징 처리
|
|
```xml
|
|
<select id="selectListWithPaging" parameterType="map" resultType="map">
|
|
SELECT * FROM (
|
|
SELECT *, ROW_NUMBER() OVER (ORDER BY reg_date DESC) as rnum
|
|
FROM table_name
|
|
WHERE 1=1
|
|
<!-- 검색 조건 -->
|
|
) t
|
|
WHERE rnum BETWEEN #{startRow}::numeric AND #{endRow}::numeric
|
|
</select>
|
|
```
|
|
|
|
### 3. 대소문자 처리
|
|
```xml
|
|
<!-- PostgreSQL은 대소문자를 구분하므로 주의 -->
|
|
<select id="selectData" resultType="map">
|
|
SELECT
|
|
user_id as "userId", -- 카멜케이스 변환
|
|
user_name as "userName",
|
|
UPPER(status) as "status"
|
|
FROM user_info
|
|
</select>
|
|
```
|
|
|
|
### 4. NULL 처리
|
|
```xml
|
|
<select id="selectData" resultType="map">
|
|
SELECT
|
|
COALESCE(description, '') as description,
|
|
CASE WHEN status = 'Y' THEN '활성' ELSE '비활성' END as statusName
|
|
FROM table_name
|
|
</select>
|
|
```
|
|
|
|
## 성능 최적화
|
|
|
|
### 인덱스 활용
|
|
```sql
|
|
-- 자주 검색되는 컬럼에 인덱스 생성
|
|
CREATE INDEX idx_user_dept ON user_info(dept_code);
|
|
CREATE INDEX idx_menu_parent ON menu_info(parent_id);
|
|
```
|
|
|
|
### 쿼리 최적화
|
|
```xml
|
|
<!-- EXISTS 사용으로 성능 개선 -->
|
|
<select id="selectUserWithAuth" resultType="map">
|
|
SELECT u.* FROM user_info u
|
|
WHERE EXISTS (
|
|
SELECT 1 FROM user_auth ua
|
|
WHERE ua.user_id = u.user_id
|
|
AND ua.auth_code = #{authCode}
|
|
)
|
|
</select>
|
|
```
|
|
|
|
### 배치 처리
|
|
```xml
|
|
<!-- 대량 데이터 삽입 시 배치 사용 -->
|
|
<insert id="insertBatch" parameterType="list">
|
|
INSERT INTO table_name (col1, col2, col3)
|
|
VALUES
|
|
<foreach collection="list" item="item" separator=",">
|
|
(#{item.col1}, #{item.col2}, #{item.col3})
|
|
</foreach>
|
|
</insert>
|
|
``` |