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 문법 없이도 충분히 효율적인 데이터 관리가 가능합니다.