Android 앱에서 SQLite 데이터베이스 활용하기

SQLite란?

모든 모바일 애플리케이션은 데이터를 저장하고 관리할 필요가 있으며, Android 플랫폼에서는 이를 위해 SQLite를 기본 내장형 데이터베이스로 제공합니다. SQLite는 C 언어로 개발된 경량 오픈소스 데이터베이스 엔진으로, 서버 구조 없이 파일 기반으로 동작하여 메모리 사용량이 매우 적고(수백 KB 수준), 별도의 설치나 관리가 필요 없습니다. 이 특성 덕분에 안드로이드, iOS는 물론 Firefox, Chrome 등의 브라우저에서도 설정 정보 저장에 활용됩니다.

SQLite의 주요 특징

  • 경량화: 별도의 서버 프로세스 없이 앱 내부에서 직접 실행되며, 작은 크기로 리소스 소모가 최소화됩니다.
  • 단일 파일: 전체 데이터베이스가 하나의 파일에 저장되어 백업 및 이식이 간편합니다.
  • 跨플랫폼 지원: Windows, Linux, macOS, Android, iOS 등 대부분의 운영체제에서 작동합니다.
  • ACID 준수: 트랜잭션이 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 지속성(Durability)을 보장합니다.
  • 다양한 언어 연동: Java, Kotlin, Python, C++, JavaScript 등과의 인터페이스가 잘 정의되어 있습니다.

Android에서 SQLite 사용 방법

안드로이드 SDK는 SQLite를 쉽게 사용할 수 있도록 SQLiteOpenHelper 클래스를 제공합니다. 이 클래스를 상속받아 데이터베이스 생성 및 버전 관리를 처리할 수 있습니다.

1. 데이터베이스 헬퍼 클래스 작성

학생 정보를 저장하는 테이블을 예시로 데이터베이스를 구성해보겠습니다.

public class StudentDbHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "student_data.db";
    private static final int DB_VERSION = 1;
    private static final String TABLE_STUDENT = "students";

    public StudentDbHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String createTable = "CREATE TABLE " + TABLE_STUDENT + " (" +
                "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                "name TEXT NOT NULL, " +
                "grade TEXT, " +
                "subject TEXT)";
        db.execSQL(createTable);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (oldVersion < 2) {
            // 버전 2에서 새로운 컬럼 추가
            db.execSQL("ALTER TABLE " + TABLE_STUDENT + " ADD COLUMN email TEXT");
        }
    }
}

2. 데이터 모델 클래스 정의

학생 정보를 담을 POJO 클래스를 생성합니다.

public class Student {
    private int id;
    private String name;
    private String grade;
    private String subject;

    public Student() {}

    public Student(int id, String name, String grade, String subject) {
        this.id = id;
        this.name = name;
        this.grade = grade;
        this.subject = subject;
    }

    // Getter 및 Setter 메서드
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getGrade() { return grade; }
    public void setGrade(String grade) { this.grade = grade; }

    public String getSubject() { return subject; }
    public void setSubject(String subject) { this.subject = subject; }
}

3. 데이터 조작 기능 구현

CRUD(Create, Read, Update, Delete) 작업을 위한 DAO(Data Access Object) 클래스를 작성합니다. Android는 SQL 쿼리 문자열 대신 ContentValues와 내장 메서드를 사용해 보다 안전하게 데이터를 조작할 수 있게 해줍니다.

public class StudentRepository {

    private SQLiteDatabase database;
    private StudentDbHelper dbHelper;

    public StudentRepository(Context context) {
        dbHelper = new StudentDbHelper(context);
    }

    public void open() {
        database = dbHelper.getWritableDatabase();
    }

    public void close() {
        dbHelper.close();
    }

    // 데이터 삽입
    public long insertStudent(Student student) {
        ContentValues values = new ContentValues();
        values.put("name", student.getName());
        values.put("grade", student.getGrade());
        values.put("subject", student.getSubject());
        return database.insert(StudentDbHelper.TABLE_STUDENT, null, values);
    }

    // 데이터 삭제
    public int deleteStudent(int id) {
        return database.delete(
            StudentDbHelper.TABLE_STUDENT,
            "id = ?",
            new String[]{String.valueOf(id)}
        );
    }

    // 데이터 수정
    public int updateStudent(Student student) {
        ContentValues values = new ContentValues();
        values.put("name", student.getName());
        values.put("grade", student.getGrade());
        values.put("subject", student.getSubject());
        return database.update(
            StudentDbHelper.TABLE_STUDENT,
            values,
            "id = ?",
            new String[]{String.valueOf(student.getId())}
        );
    }

    // 단일 레코드 조회
    public Student getStudentById(int id) {
        Cursor cursor = database.query(
            StudentDbHelper.TABLE_STUDENT,
            null,
            "id = ?",
            new String[]{String.valueOf(id)},
            null, null, null
        );

        if (cursor != null && cursor.moveToFirst()) {
            Student student = new Student(
                cursor.getInt(0),
                cursor.getString(1),
                cursor.getString(2),
                cursor.getString(3)
            );
            cursor.close();
            return student;
        }
        return null;
    }

    // 전체 목록 조회 (페이지네이션 포함)
    public List<Student> getAllStudents(int offset, int limit) {
        List<Student> students = new ArrayList<>();
        Cursor cursor = database.query(
            StudentDbHelper.TABLE_STUDENT,
            null, null, null, null, null,
            "id ASC",
            offset + ", " + limit
        );

        while (cursor.moveToNext()) {
            Student student = new Student(
                cursor.getInt(0),
                cursor.getString(1),
                cursor.getString(2),
                cursor.getString(3)
            );
            students.add(student);
        }
        cursor.close();
        return students;
    }

    // 레코드 수 카운트
    public int getCount() {
        Cursor cursor = database.rawQuery("SELECT COUNT(*) FROM " + StudentDbHelper.TABLE_STUDENT, null);
        cursor.moveToFirst();
        int count = cursor.getInt(0);
        cursor.close();
        return count;
    }
}

4. 액티비티에서 사용 예시

MainActivity에서 버튼 클릭 이벤트를 통해 데이터를 조작하는 예제입니다.

public class MainActivity extends AppCompatActivity {

    private StudentRepository repo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        repo = new StudentRepository(this);
        repo.open();

        findViewById(R.id.btn_insert).setOnClickListener(v -> addSampleData());
        findViewById(R.id.btn_query).setOnClickListener(v -> queryData());
    }

    private void addSampleData() {
        Student s = new Student(0, "김철수", "3학년", "수학");
        repo.insertStudent(s);
        Toast.makeText(this, "데이터 추가 완료", Toast.LENGTH_SHORT).show();
    }

    private void queryData() {
        List<Student> list = repo.getAllStudents(0, 10);
        for (Student s : list) {
            Log.d("Student", s.getName() + " - " + s.getGrade());
        }
    }

    @Override
    protected void onDestroy() {
        repo.close();
        super.onDestroy();
    }
}

주의사항 및 팁

  • getWritableDatabase() vs getReadableDatabase(): 전자는 읽기/쓰기 모두 가능하며, 후자는 디스크가 가득 찼을 때 읽기 전용으로 열 수 있어 더 안정적입니다.
  • 커서 닫기: 모든 Cursor 객체는 사용 후 반드시 close() 호출이 필요합니다.
  • 버전 관리: onUpgrade() 메서드에서 이전 스키마와 호환되도록 마이그레이션 로직을 작성해야 합니다.
  • SQL Injection 방지: 문자열 연결 대신 ? 플레이스홀더를 사용하세요.

이처럼 Android는 SQLite를 간편하고 안정적으로 사용할 수 있는 구조를 제공하며, 복잡한 SQL 문법 없이도 충분히 효율적인 데이터 관리가 가능합니다.

태그: SQLite Android 데이터베이스 CRUD SQLiteOpenHelper

6월 25일 20:59에 게시됨