ERP-node/.cursor/rules/database-guide.mdc

207 lines
5.2 KiB
Plaintext
Raw Normal View History

2025-08-21 09:41:46 +09:00
---
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>
```