일전에 지자체에서 운영하는 Android 와 iOS 앱을 개발해준 적이 있다. 지자체 서버에서 제공하는 API를 호출하고 그 결과를 앱에 표현해 주는 앱인데 API호출 회수를 최소화 하기 위해 대부분의 데이터는 휴대폰의 SQLiTE 에 저장하고 사용했다. 또한 서버와의 동기화(Synchronization)를 위해 Update가 필요한 테이블별 Version No를 Check하여 Local 과 Server 의 DB 동기화를 진행해 왔다.
고도화 작업까지 완료된 꽤 긴 기간동안 작업했던 앱이었기에, 초기의 앱과 비교해 보면 디자인부터 기능까지 무척이나 많은 변화를 간직하고 있는 앱이다. 오늘은 수많은 변화 중 Database 의 Table data Update 관련한 몇가지를 얘기하고자 한다.
우선 서버는 Oracle DB (가끔 Ora~~~ 어쩌고 저쩌고 하는 장애가 발생한 적이 있었다) 이며, 필자가 만든 앱 이외에도 기존에 사용해 왔고 현재도 계속 사용중인 몇몇 앱들이 더 있다. 동일한 Data를 바라보는 앱들이 몇몇 있다보니 Rest API를 쉽게 수정하기는 힘들었을 테니 서버의 Data가 변경되면 각각의 앱들이 각자 알아서 Local DB를 업데이트 할 수 있게끔 Version번호라는 것을 상황별로 이용하게끔 마련되어 있다.
개발 초기에 업데이트 모듈을 만들기 위해 첫번째 사용했던 방법은 로컬에 SQLiTE 파일 존재여부에 따라 존재하는 경우에는 버전번호를 비교하여 변경된 데이터만 API로 전달받아 Local DB를 업데이트 하고, SQLiTE파일 없는 경우에는 DDL (Data Definition Language) 을 사용해서 필요한 테이블들을 만들고 난 후 필요한 모든 Data는 서버로부터 API 를 반복 호출하여 테이블에 Insert 했는데 이 과정이 너무 오래걸리고 서버에 부하를 너무 주게되어 바로 두번째 방법으로 프로세스를 변경했다.
그 두번째 방법은 버전번호로 업데이트하는 로직은 그대로 두고, DB 파일이 없을 경우에만 (앱을 최초에 설치할때만 DB파일이 없음) 미리 APK 파일 내부에 현행화 된 최신 버전의 DB 파일을 넣어두고 필요 시 앱 실행폴더로 Copy후 기존의 버전업데이트 작업을 진행했으며 현재 이 방식으로 User들의 앱내 DB Update는 순조롭게 진행 되고 있다.
세번째 업데이트 방식은 DB File 교체방식인데 필자의 개인서버에 구축하고 테스트까지 했는데 주관사 요청에 의해 현재는 사용되지 않고 있다. 간단히 설명하자면 최신 내용의 DB를 유지하기 위해 모든 사용자가 Version Check API 와 Update API를 호출하는 것이 아니라, 최신상태의 SQLiTE DB 파일을 다운로드 받을 수 있도록 별도의 다운로드 서버를 운영하고 (끽해봐야 10MB 내외 사이즈의 DB 파일을 다운로드 할 수 있으면 되며, DIO 가 가장 편리했던 것 같다), 파이썬으로 새벽시간대에 한두번 그리고 오전에 한번 정도 스케쥴링 배치작업으로 최신데이터 현행화한 DB파일을 주기적으로 만들어서 다운로드 폴더에 복사하는 자동화 작업을 하는 것이다. 가장 안정적인 업데이트가 가능하고 지자체 서버에 업데이트 관련 API 호출은 Python 예약한 작업시간에 호출하는 경우 외 일반 사용자 업데이트 호출은 전혀 없기 때문에 서버의 부하도 크게 줄일 수 있는데...... 암튼 지금은 사용하지 않고 있는 업데이트 방식이다.
업데이트 모듈을 구성할때 가장 고심했던 것 중 하나가 바로 사용자 정의 데이터 유지 문제였다. 회원가입이 필요하지도 않고 앱을 제거하면 로컬 디비라든가 모든 정보들이 다 삭제되기 때문에, 재설치를 한다고 해도 이전 사용자 정의 데이터가 남아 있지 않기 때문이다.
뭐 꼭 해결해야 한다면 유지해야 할 Data를 추출해서 파일로 생성해서 앱영역이 아닌 사용자 접근영역에 별도로 옮겨놓거나 하고 필요할때 복원할 수 있게 만들 수도 있겠으나 복잡하게 만들면 또 다른 민원을 불러오게 된다.
필자도 딱 거기까지만 지원해주기로 했다. 재설치를 제외한 업데이트는 사용자가 설정한 정보가 그대로 유지되게끔......
여러가지 방법이 있겠으나 익숙한 것을 사용해야겠다 싶어서 shared_preferences 을 이용해 사용자 설정 정보를 Key:Value 방식으로 잠깐 저장해 두었다가 DB 업데이트가 종료되면 해당 테이블의 내용 Delete 후 임시저장한 내용을 테이블에 Insert 하는 방식을 사용했다.
Format 이 바뀌거나 하면 코드를 재수정해야 한다는 부담이 있지만 바뀔 가능성이 거의 없는 기본 포맷이었고 데이터도 그다지 많지 않기 때문에 마음에는 안들지만 이 문제로 시끄러울 일은 없다고 판단되며 현재까지도 아직 문제 발생은 없었다.
Local에서 SQLiTE 를 사용할 경우 다음과 같은 몇가지 특성은 정확히 인지하고 있어야 할 것 같다.
- SQLiTE File 1 개 = Database 1 개 : MySQL 이나 MariaDB 처럼 하나의 파일안에 여러개의 데이터베이스가 존재할 수 없고, 하나의 파일에는 하나의 데이터베이스만 존재함
- TRUNCATE 명령의 부재 : Truncate명령은 없지만 DELETE 명령으로 Data삭제 후 sequence 값을 초기화하면 TRUNCATE 동일하게 수행
ex) DELETE FROM 테이블명; // Truncate 할 대상 테이블의 데이터 모두 삭제
UPDATE SQLITE_SEQUENCE SET seq = 0 where name = 테이블명; // 대상 테이블의 sequence 값을 초기화
- Dot Command 사용 : SQLiTE에도 .dump 같은 DOT명령을 사용할 수 있으나 OS 터미널에서 사용할 수 있기에 Flutter 의 sqflite 패키지 내에서 사용할 수 있는 방법이 없는 듯 하다. (Dot 명령어는 Query 문장이 아니기 때문에 사용할 수 없는 것 아닐까? Dot명령어를 Flutter 패키지 내에서 사용할 수 있는 방법을 알고 계신 분 계시면 힌트라도 좀...... )
필자의 경우 .dump 명령이 절실했는데 도트명령을 사용할 방법이 없어서 다른 방법을 찾아 해결했다.
=====>>>>> 이 부분은 다음 포스팅 할때 좀 더 자세히 설명 하고자 한다.
다음글 : [ SQLiTE ] Local DB Update process (2)
'Tech Story' 카테고리의 다른 글
[ Flutter / Python ] 좌표 (위도, 경도) 값으로 국내/해외 판단 (0) | 2024.01.22 |
---|---|
[ SQLiTE ] Local DB Update process (2) (0) | 2023.12.22 |
[ Flutter ] Class, List, Map 등의 복사 (깊은복사, 얕은복사) (0) | 2023.12.17 |
[ Environment ] 개발 환경에 대해... (0) | 2023.12.15 |
[ SQL ] Query 작성 시 count() 함수의 함정 (0) | 2023.12.06 |