데이터베이스 문제
데이터베이스 관련 문제와 해결 방법입니다.
연결 문제
SQLSTATE[HY000] Connection refused
증상:
SQLSTATE[HY000] [2002] Connection refused
원인:
- PostgreSQL 컨테이너가 시작되지 않음
- 잘못된 호스트/포트 설정
- 네트워크 연결 문제
해결 방법:
-
컨테이너 상태 확인
make status NAME=myapp -
PostgreSQL 컨테이너 로그 확인
docker logs myapp-postgres -
.env 설정 확인
# .env
DB_CONNECTION=pgsql
DB_HOST=postgres # 컨테이너 이름 사용
DB_PORT=5432 # 컨테이너 내부 포트
DB_DATABASE=app
DB_USERNAME=app
DB_PASSWORD=secret -
네트워크 확인
docker network ls
docker network inspect myapp-network
SQLSTATE[08006] Unable to connect
증상:
SQLSTATE[08006] [7] could not connect to server: Connection timed out
원인:
- 외부 포트로 접속 시도
- 방화벽 문제
해결 방법:
컨테이너 간 통신은 내부 네트워크 사용:
# 올바른 설정 (컨테이너 간 통신)
DB_HOST=postgres
DB_PORT=5432
# 잘못된 설정 (외부 접속 시도)
DB_HOST=localhost
DB_PORT=5432
마이그레이션 문제
Duplicate column/table
증상:
SQLSTATE[42701]: Duplicate column: column "xxx" of relation "yyy" already exists
원인:
- 마이그레이션 파일 중복 실행
- 마이그레이션 상태 불일치
해결 방법:
-
마이그레이션 상태 확인
docker exec -it myapp-web php artisan migrate:status -
특정 마이그레이션 롤백
docker exec -it myapp-web php artisan migrate:rollback --step=1 -
마이그레이션 테이블 확인
SELECT * FROM migrations ORDER BY batch DESC;
주의
migrate:fresh는 모든 데이터를 삭제합니다. 운영 환경에서 절대 사용하지 마세요.
Nothing to migrate
증상:
Nothing to migrate.
원인:
- 모든 마이그레이션이 이미 실행됨
- 마이그레이션 파일이 없음
해결 방법:
-
마이그레이션 상태 확인
php artisan migrate:status -
새 마이그레이션 파일 확인
ls -la database/migrations/
RLS (Row-Level Security) 문제
데이터가 보이지 않음
증상:
- 데이터를 생성했지만 조회되지 않음
- 빈 결과 반환
원인:
- 테넌트 컨텍스트가 설정되지 않음
- RLS 정책이 접근을 차단
해결 방법:
-
테넌트 컨텍스트 확인
// 현재 테넌트 확인
dd(tenant());
// 또는
dd(app('tenant')); -
RLS 정책 확인
-- PostgreSQL에서 RLS 정책 확인
SELECT * FROM pg_policies WHERE tablename = 'users'; -
테넌트 컨텍스트 설정
// 명시적 설정
tenancy()->initialize($tenant);
// 또는 미들웨어 확인
Route::middleware(['tenant'])->group(...);
다른 테넌트 데이터 접근 (Cross-Tenant)
증상:
- 다른 테넌트의 데이터가 조회됨 (보안 문제)
원인:
- TenantScope 미적용
- 직접 쿼리로 우회
해결 방법:
-
Model에 Scope 적용 확인
class User extends Model
{
use BelongsToTenant;
} -
직접 쿼리 피하기
// 잘못됨: Scope 우회
DB::table('users')->where('tenant_id', 1)->get();
// 올바름: Eloquent 사용
User::all(); -
테스트로 검증
public function test_tenant_isolation()
{
$tenant1 = Tenant::factory()->create();
$tenant2 = Tenant::factory()->create();
tenancy()->initialize($tenant1);
$user1 = User::factory()->create();
tenancy()->initialize($tenant2);
$this->assertFalse(User::where('id', $user1->id)->exists());
}