안드로이드 개발자의 창고
[44일차 Android] SQLiteDatabase 본문
출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 PPT
📖 SQLiteDatabase
- 안드로이드에서 사용하는 내장 데이터 베이스로 표준 SQL문을 사용하는 관계형 데이터 베이스
- MySQL과 유사한 문법을 사용하고 있으며 일반적인 관계형 데이터 베이스가 가지고 있는 기능을 가지고 있다.
- 임베디드형 데이터베이스로써 데이터베이스를 사용하는 애플리케이션에 셋팅되는 데이터 베이스이다.
- 안드로이드 OS에 내장되어 있으며 개발자가 만드는 애플리케이션은 안드로이드 OS에게 쿼리문을 전달하고 안드로이드 OS가 직접 데이터 베이스에 대한 처리를 하게 된다.
-
안드로이드에서의 SQLite 사용은 쿼리문을 이용하는 방법과 제공되는 클래스를 사용하는 방법 두 가지가 있다.
SQLite OpenHelper
- 안드로이드에서 SQLite 데이터 베이스를 사용하려면 SQLiteOpenHelper를 상속받은 클래스를 만들어야 한다.
- 이 클래스는 사용할 데이터베이스의 이름을 설정하는 것 뿐만 아니라 다음 기능들을 제공하고 있다.
- 지정된 데이터베이스 파일을 사용하려고 할 때 파일이 없으면 파일을 만들고 onCreate 메서드를 호출한다. onCreate 메서드에서는 테이블을 만드는 쿼리를 실행해주면 된다.
- 애플리케이션을 서비스하다가 데이터 베이스 구조를 변경하려면 데이터베이스의 버전을 변경하면 된다. 버전을 변경하면 onUpgrade 메서드가 호출되고 여기에서 테이블을 새로운 구조로 변경해주는 작업을 해주면 된다.
ContentValue
- 클래스를 이용하는 방법을 사용할 때 가장 중요한 클래스
- ContentValue 클래스는 값을 저장할 때 이름을 부여하는 클래스로써 값을 저장할 때 사용하는 이름은 테이블의 컬럼 이름과 매칭된다.
- ContentValue에 저장한 데이터는 테이블의 컬럼과 매칭되어 insert, update 등에 사용된다.
예제 코드
DBHelper.kt
// Test.db : 사용할 데이터 베이스 파일의 이름
// null : NullFactory, Null에 대한 처리를 어떻게 할 것인가에 대한 값
// 1 : 버전
class DBHelper(context: Context) : SQLiteOpenHelper(context, "Test.db", null, 1) {
// 데이터베이스 파일이 없으면 만들고 이 메서드를 호출
// 테이블을 생성 코드 작성
override fun onCreate(db: SQLiteDatabase?) {
// 테이블 구조 정의
// create table 테이블이름
// (컬럼이름 자료형 제약 조건...)
// 자료형 : 정수 - Integer, 문자열 - text, 실수 - real, 날짜 - date
// 제약조건 : 저장할 수 있는 값에 대한 조건
// primary key : null이나 중복된 값을 허용X,각 행을 구분할 수 있는 값을 저장하기 위해 사용
// autoincrement : 컬럼에 저장할 값을 지정하지 않으면 1부터 1씩 증가되는 값이 자동 저장
// not null : null 값 허용X
val sql = """create table TestTable
(idx integer primary key autoincrement,
textData text not null,
intData integer not null,
doubleData real not null,
dateData date not null)
""".trimIndent()
// 쿼리문 수행
db?.execSQL(sql)
}
// 데이터베이스 파일 버전이 변경되어 있을 떼 호출되는 메서드
// 부모 생성자 마지막에 넣어준 버전 번호가 데이터 베이스 파일에 기록 버전보다 높을 때 호출
// 과거에 만들어진 테이블의 구조가 될 수 있도록 테이블을 수정 작업 코드 작성
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
TODO("Not yet implemented")
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
activityMainBinding.run {
// 데이터 저장
button.setOnClickListener {
// 현재 시간을 구해 년-월-일 양식의 문자열 생성
val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val now = sdf.format(Date())
// 저장할 정보를 가지고 있는 TestClass 객체 생성
val obj1 = TestClass(0, "문자열1", 100, 11.11, now)
DAO.insertData(this@MainActivity, obj1)
val obj2 = TestClass(0, "문자열2", 200, 22.22, now)
DAO.insertData(this@MainActivity, obj2)
}
// 특정 데이터 불러오기
button2.setOnClickListener {
val dataList = DAO.selectAllData(this@MainActivity)
// 출력
textView.text = ""
for(obj in dataList){
textView.append("idx : ${obj.idx}\n")
textView.append("textData : ${obj.textData}\n")
textView.append("intData : ${obj.intData}\n")
textView.append("doubleData : ${obj.doubleData}\n")
textView.append("dateData : ${obj.dateData}\n\n")
}
}
// 전체 데이터 불러오기
button3.setOnClickListener {
val obj = DAO.selectData(this@MainActivity,1)
textView.text = "idx : ${obj.idx}\n"
textView.append("textData : ${obj.textData}\n")
textView.append("intData : ${obj.intData}\n")
textView.append("doubleData : ${obj.doubleData}\n")
textView.append("dateData : ${obj.dateData}\n")
}
// 데이터 수정
button4.setOnClickListener {
// 특정 데이터를 선택하여 TestClass 객체로 받는다.
val obj = DAO.selectData(this@MainActivity, 1)
// 객체의 데이터 수정
obj.textData = "새로운 문자열"
// 수정된 객체를 다시 저장하여 데이터 수정
DAO.updateData(this@MainActivity, obj)
}
// 데이터 삭제
button5.setOnClickListener {
DAO.deleteData(this@MainActivity, 1)
}
}
}
}
data class TestClass(var idx:Int,
var textData:String,
var intData:Int,
var doubleData:Double,
var dateData:String)
DAO.kt - 쿼리문 이용 방식
class DAO {
companion object{
// Insert : 저장
fun insertData(context: Context, data:TestClass){
// autoinctement가 있는 컬럼은 제외하고 나머지만 지정
val sql = """insert into TestTable
| (textData, intData, doubleData, dateData)
| values (?, ?, ?, ?)
""".trimMargin()
// ?에 설정할 값을 배열에 담는다.
val arg1 = arrayOf(
data.textData, data.intData, data.doubleData, data.dateData
)
// 데이터베이스 오픈
val sqliteDatabase = DBHelper(context)
// 쿼리 실행(쿼리문 ?에 셋팅할 값 배열)
sqliteDatabase.writableDatabase.execSQL(sql, arg1)
// 데이터 베이스를 닫아준다.
sqliteDatabase.close()
}
// Select : 조건에 맞는 행 가져오기
fun selectData(context: Context, idx:Int):TestClass{
// 쿼리문
val sql = "select * from TestTable where idx=?"
// ?에 들어갈 값(문자열 배열)
val arg1 = arrayOf("$idx")
val dbHelper = DBHelper(context)
// 쿼리 실행
val cursor = dbHelper.writableDatabase.rawQuery(sql, arg1)
cursor.moveToNext()
// 컬럼 이름을 지정하여 컬럼의 순서 값을 가져오기
val idx1 = cursor.getColumnIndex("idx")
val idx2 = cursor.getColumnIndex("textData")
val idx3 = cursor.getColumnIndex("intData")
val idx4 = cursor.getColumnIndex("doubleData")
val idx5 = cursor.getColumnIndex("dateData")
// 데이터 가져오기
val idx = cursor.getInt(idx1)
val textData = cursor.getString(idx2)
val intData = cursor.getInt(idx3)
val doubleData = cursor.getDouble(idx4)
val dateData = cursor.getString(idx5)
// 불러온 데이터로 객체 생성
val testClass = TestClass(idx, textData, intData, doubleData, dateData)
dbHelper.close()
// 데이터로 생성한 객체 반환
return testClass
}
// Select All : 모든 행 가져오기
fun selectAllData(context: Context) : MutableList<TestClass>{
val sql = "select * from TestTable"
// 데이터베이스 오픈
val dbHelper = DBHelper(context)
// 쿼리 실행
val cursor = dbHelper.writableDatabase.rawQuery(sql, null)
val dataList = mutableListOf<TestClass>()
// cursor 객체는 쿼리문에 맞는 행에 접근할 수 있는 객체
// 처음에는 아무 행도 가리키고 있지 않음
// moveToNext 메서드 호출 시 다음 행에 접근 가능
// 이 때 접근할 행이 있으면 true, 없으면 false를 반환
while (cursor.moveToNext()){
// 컬럼 이름을 지정하여 컬럼의 순서 값을 가져오기
val idx1 = cursor.getColumnIndex("idx")
val idx2 = cursor.getColumnIndex("textData")
val idx3 = cursor.getColumnIndex("intData")
val idx4 = cursor.getColumnIndex("doubleData")
val idx5 = cursor.getColumnIndex("dateData")
// 데이터 가져오기
val idx = cursor.getInt(idx1)
val textData = cursor.getString(idx2)
val intData = cursor.getInt(idx3)
val doubleData = cursor.getDouble(idx4)
val dateData = cursor.getString(idx5)
val testClass = TestClass(idx, textData, intData, doubleData, dateData)
dataList.add(testClass)
}
dbHelper.close()
// 데이터로 생성한 객체를 저장한 리스트 반환
return dataList
}
// Update : 조건에 맞는 행의 컬럼 값 수정
fun updateData(context: Context, obj:TestClass){
// 쿼리문
// idx가 ?인 행의 textData, intData, doubleData, dateData 칼럼의 값을 변경한다.
val sql = """update TestTable
| set textData = ?, intData=?, doubleData = ?, dateData = ?
| where idx = ?
""".trimMargin()
// ?에 들어갈 값
val args = arrayOf(obj.textData, obj.intData, obj.doubleData, obj.dateData, obj.idx)
// 쿼리 실행
val dbHelper = DBHelper(context)
dbHelper.writableDatabase.execSQL(sql, args)
dbHelper.close()
}
// Delete : 조건에 맞는 행을 삭제한다.
fun deleteData(context: Context, idx: Int){
// 쿼리문
val sql = "delete from TestTable where idx = ?"
// ?에 들어갈 값
val args = arrayOf(idx)
// 쿼리 실행
val dbHelper = DBHelper(context)
dbHelper.writableDatabase.execSQL(sql, args)
dbHelper.close()
}
}
}
DAO.kt - 제공되는 클래스(ContentValue) 이용 방식
class DAO {
companion object{
// Insert : 저장
fun insertData(context: Context, data:TestClass){
// 컬럼 이름과 데이터를 설정하는 객체
val contentValues = ContentValues()
// 컬럼 이름, 값 지정
contentValues.put("textData", data.textData)
contentValues.put("intData", data.intData)
contentValues.put("doubleData", data.doubleData)
contentValues.put("dateData", data.dateData)
val dbHelper = DBHelper(context)
// 데이터를 저장할 테이블의 이름,
// null값을 어떻게 처리할 것인가,
// 저장할 데이터를 가지고 있는 객체
dbHelper.writableDatabase.insert("TestTable", null, contentValues)
dbHelper.close()
}
// Select : 조건에 맞는 행 하나 가져오기
fun selectData(context: Context, idx:Int):TestClass{
val dbHelper = DBHelper(context)
// 첫 번째 : 테이블명
// 두 번째 : 가져오고자 하는 컬럼의 이름 목록, null을 넣어주면 모두 가져온다.
// 세 번째 : 특정 행을 선택하기 위한 조건절
// 네 번째 : 세 번째에 들어가는 조건절의 ? 에 셋팅될 값 배열
// 다섯 번째 : Group by의 기준 컬럼
// 여섯 번째 : Having절에 들어갈 조건절
// 일곱 번째 : Having절의 ?에 셋팅될 값 배열
val selection = "idx = ?"
val args = arrayOf("$idx")
val cursor = dbHelper.writableDatabase.query("TestTable", null, selection, args, null, null, null)
cursor.moveToNext()
// 컬럼의 이름을 지정하여 컬럼의 순서 값을 가져온다.
val idx1 = cursor.getColumnIndex("idx")
val idx2 = cursor.getColumnIndex("textData")
val idx3 = cursor.getColumnIndex("intData")
val idx4 = cursor.getColumnIndex("doubleData")
val idx5 = cursor.getColumnIndex("dateData")
// 데이터를 가져온다.
val idx = cursor.getInt(idx1)
val textData = cursor.getString(idx2)
val intData = cursor.getInt(idx3)
val doubleData = cursor.getDouble(idx4)
val dateData = cursor.getString(idx5)
val testClass = TestClass(idx, textData, intData, doubleData, dateData)
dbHelper.close()
return testClass
}
// Select All : 모든 행을 가져오기
fun selectAllData(context: Context) : MutableList<TestClass>{
var dbHelper = DBHelper(context)
val cursor = dbHelper.writableDatabase.query("TestTable", null, null, null ,null, null, null)
val dataList = mutableListOf<TestClass>()
// cursor 객체에는 쿼리문에 맞는 행에 접근할 수 있는 객체
// 처음에는 아무 행도 가리키고 있지 않는다.
// moveToNext 메서드를 호출하면 다음 행에 접근 가능
// 이 때 접근할 행이 있으면 true, 없으면 false를 반환
while (cursor.moveToNext()){
// 컬럼 이름을 지정하여 컬럼의 순서 값을 가져오기
val idx1 = cursor.getColumnIndex("idx")
val idx2 = cursor.getColumnIndex("textData")
val idx3 = cursor.getColumnIndex("intData")
val idx4 = cursor.getColumnIndex("doubleData")
val idx5 = cursor.getColumnIndex("dateData")
// 데이터 가져오기
val idx = cursor.getInt(idx1)
val textData = cursor.getString(idx2)
val intData = cursor.getInt(idx3)
val doubleData = cursor.getDouble(idx4)
val dateData = cursor.getString(idx5)
val testClass = TestClass(idx, textData, intData, doubleData, dateData)
dataList.add(testClass)
}
dbHelper.close()
return dataList
}
// Update : 조건에 맞는 행의 컬럼 값을 수정
fun updateData(context: Context, obj:TestClass){
// 컬럼과 값을 지정하는 ContentValues를 생성한다.
val cv = ContentValues()
cv.put("textData", obj.textData)
cv.put("intData", obj.intData)
cv.put("doubleData", obj.doubleData)
cv.put("dateData", obj.dateData)
// 조건절
val condition = "idx = ?"
// ?에 들어갈 값
val args = arrayOf("${obj.idx}")
// 수정
val dbHelper = DBHelper(context)
// 테이블 명, content values, 조건절, ?에 들어갈 값
dbHelper.writableDatabase.update("TestTable", cv, condition, args)
dbHelper.close()
}
// Delete : 조건에 맞는 행 삭제
fun deleteData(context: Context, idx: Int){
// 조건절
val condition = "idx = ?"
// ?에 들어갈 값
val args = arrayOf("$idx")
val dbHelper = DBHelper(context)
dbHelper.writableDatabase.delete("TestTable", condition, args)
dbHelper.close()
}
}
}
'Computer > Android' 카테고리의 다른 글
[50일차 Android] Preferences (0) | 2023.07.17 |
---|---|
[50일차 Android] Content Provider (0) | 2023.07.14 |
[44일차 Android] assets (0) | 2023.07.10 |
[44일차 Android] Raw (0) | 2023.07.10 |
[43일차 Android] 파일 입출력 (0) | 2023.07.10 |