어떻게 되는 겁니까?
응용 프로그램에서 LiteSync 코드가 포함된 SQLite 라이브러리의 수정된 버전을 사용하여 데이터베이스에 액세스하십시오.
SQLite 라이브러리의 수정사항은 내부적이며 인터페이스는 동일하다.
LiteSync 라이브러리는 트랜잭션 데이터를 교환하면서 서로 통신할 것이다.

복제
앱을 처음 열면 다른 노드에 연결하여 데이터베이스의 새 사본을 다운로드한다.
중앙 위상에서는 기본 노드가 데이터베이스 복사본을 보조 노드로 전송한다.
다운로드되면 노드는 동기화를 시작한다.
동기화
노드가 동일한 기본 데이터베이스를 가지고 있으면 오프라인일 때 실행된 트랜잭션을 교환한다.
이 후 온라인 모드로 전환되고, 노드에서 새로운 트랜잭션이 실행되면 연결된 노드에서 실행되도록 전송된다.
노드가 오프라인 상태일 경우 트랜잭션은 나중에 교환할 로컬 로그에 저장된다.
앱 코드를 변경해야 하는가?
몇 가지 단계가 있지만 기본적으로 데이터베이스 오프닝의 URI 문자열을 다음과 같이 변경해야 한다:
"file:/path/to/app.db"
다음과 같은 경우로:
"file:/path/to/app.db?node=secondary&connect=tcp://server.ip:1234"
좋은 소식은 LiteSync가 네이티브 SQLite3 인터페이스를 사용한다는 것이다. 그것은 우리가 다른 API를 사용할 필요가 없다는 것을 의미한다.
연결
각 노드에는 두 가지 옵션이 있다:
주소에 바인드를 한다
피어 주소에 연결한다
그래서 어느 쪽이 다른 쪽에 연결될 것인지 선택할 수 있다. 이것은 한 쪽이 라우터나 방화벽 뒤에 있을 때 유용하다.
지원되는 토폴로지
중앙 집중식 별 토폴로지

이 토폴로지에는 다른 모든 노드가 연결될 노드가 있으므로 동기화가 이루어지려면 온라인 상태여야 한다.
다음은 몇 가지 구성 예:
기본 노드는 주소에 바인딩할 수 있고 보조 노드는 주소에 연결할 수 있다.
기본 노드:
"file:/home/user/app.db?node=primary&bind=tcp://0.0.0.0:1234"
보조 노드: (각각 별도의 장치에)
"file:/home/user/app.db?node=secondary&connect=tcp://server:1234"
기본 노드는 보조 노드에도 연결할 수 있다.
기본 노드:
"file:/home/user/app.db?node=primary&connect=tcp://address1:port1,tcp://address2:port2"
보조 노드: (각각 별도의 장치에)
"file:/home/user/app.db?node=secondary&bind=tcp://0.0.0.0:1234"
우리는 이 두 가지 옵션을 혼합해서 사용할 수도 있다.
기본 노드:
"file:/home/user/app.db?node=primary&bind=tcp://0.0.0.0:1234&connect=tcp://address1:port1"
보조 노드 1:
"file:/home/user/app.db?node=secondary&connect=tcp://server:1234"
보조 노드 2:
"file:/home/user/app.db?node=secondary&bind=tcp://0.0.0.0:1234"
동기화 상태
다음 명령을 사용하여 동기화 상태를 확인할 수 있음:
PRAGMA sync_status
JSON 문자열을 반환한다.
데이터베이스가 준비되었는지 확인
앱이 장치에서 처음으로 열려 있는 경우 다른 노드에서 데이터베이스의 새 사본을 다운로드할 수 있다. 끝날 때까지 데이터베이스에 접근할 수 없다.
동기화 상태를 검색하고 db_is_ready 변수를 확인할 수 있다.
아래 기본 앱 예제를 확인하십시오.
내 앱에서 어떻게 사용하는가?
세 가지 단계가 있다:
1 SQLiteSync가 포함된 라이브러리로 교체
2 URI 연결 문자열 변경
3 데이터베이스 준비 상태 확인
C 및 C++ 앱을 컴파일할 때는 응용프로그램을 LiteSync 라이브러리에 연결해야 한다.
다른 언어의 경우 적절한 래퍼를 설치해야 한다.
기본 노드 예제
기본 노드는 보조 노드와 정확히 동일한 앱이지만 다른 URI를 사용하는 일반 애플리케이션일 수 있다.
아니면 우리는 기본 노드가 되는 전용 앱을 사용할 수 있다.
중앙 데이터베이스 노드를 유지하기 위한 목적으로만 사용되는 기본 독립형 애플리케이션은 다음과 같다:
언어 선택 -->
#include <sqlite3.h> char *uri = "file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234"; int main() { sqlite3 *db; sqlite3_open(uri, &db); /* open the database */ while(1) sleep(1); /* keep the app open */ }
#include <sqlite_modern_cpp.h> #include <thread> #include <chrono> #include <iostream> using namespace sqlite; int main() { try { // open the database database db("file:app.db?node=primary&bind=tcp://0.0.0.0:1234"); // keep the app open while(1) { std::this_thread::sleep_for(std::chrono::seconds(1)); } } catch (std::exception& e) { std::cerr << e.what() << std::endl; } }
import litesync as sqlite3 conn = sqlite3.connect('file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234') # keep the app open import time while True: time.sleep(60) # in seconds
const uri = 'file:app.db?node=primary&bind=tcp://0.0.0.0:1234'; const options = { verbose: console.log }; const db = require('better-sqlite3-litesync')(uri, options); // keep the app open setInterval(function(){}, 5000);
import java.sql.Connection; import java.sql.DriverManager; public class Sample { public static void main(String[] args) { String uri = "file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234"; Connection connection = DriverManager.getConnection("jdbc:sqlite:" + uri); // keep the app open while (true) { Thread.sleep(5000); } } }
using SQLite; public class Program { public static void Main() { // open the database var uri = "file:app.db?node=primary&bind=tcp://0.0.0.0:1234"; var db = new SQLiteConnection(uri); // keep the app open while(true) { System.Threading.Thread.Sleep(5000); } } }
Imports SQLite Public Class Program Public Shared Sub Main() ' open the database Dim db As New SQLiteConnection("file:app.db?node=primary&bind=tcp://0.0.0.0:1234") ' keep the app open Do System.Threading.Thread.Sleep(5000) Loop End Sub End Class
Option Explicit Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long) Public Sub Main() Dim URI As String Dim Conn As New ADODB.Connection ' Open the connection URI = "file:C:\app\mydb.db?node=primary&bind=tcp://0.0.0.0:1234" Conn.Open "DRIVER=SQLite3 ODBC Driver;Database=" & URI ' Keep the app open Do: Sleep(5000): Loop End Sub
<?php // with sqlite3: $db = new SQLite3("file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234"); // with pdo_sqlite: $pdo = new PDO("sqlite:file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234"); // keep the app open - it should not be used with apache while(1) sleep(5); ?>
use DBI; my $dbh = DBI->connect("dbi:SQLite:uri=file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234"); // keep the app open - it should not be used with apache sleep;
require 'sqlite3' db = SQLite3::Database.new "file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234" # keep the app open loop do sleep(1) end
local sqlite3 = require("lsqlite3") local db = sqlite3.open('file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234') -- keep the app open local lsocket = require("lsocket") while true do lsocket.select(5000) end
package main import ( "database/sql" _ "github.com/litesync/go-sqlite3" "time" ) func main() { db, err := sql.Open("sqlite3", "file:/path/to/app.db?node=primary&bind=tcp://0.0.0.0:1234") // keep the app open for { time.Sleep(1000 * time.Millisecond) } }
기본 앱 예제
로컬 데이터베이스에 쓰는 기본 앱은 다음과 같다:
언어 선택 -->
#include <sqlite3.h> char *uri = "file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234"; int main() { sqlite3 *db; /* open the database */ sqlite3_open(&db, uri); /* check if the db is ready */ while(1){ char *json_str = sqlite3_query_value_str(db, "PRAGMA sync_status", NULL); bool db_is_ready = strstr(json_str, "\"db_is_ready\": true") > 0; sqlite3_free(json_str); if (db_is_ready) break; sleep_ms(250); } /* access the database */ start_access(db); } char * sqlite3_query_value_str(sqlite3 *db, char *sql, char **ppErrMsg) { char *ptr = NULL; sqlite3_stmt *stmt; int rc; if (ppErrMsg) *ppErrMsg = NULL; rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); if (rc != SQLITE_OK) { if (ppErrMsg) *ppErrMsg = sqlite3_strdup(sqlite3_errmsg(db)); return NULL; } if (sqlite3_step(stmt) == SQLITE_ROW) { char *text = (char *)sqlite3_column_text(stmt, 0); if (text) { ptr = sqlite3_strdup(text); } } sqlite3_finalize(stmt); return ptr; }
#include <iostream> #include <sqlite_modern_cpp.h> #include <unistd.h> using namespace sqlite; using namespace std; int main() { try { // open the database database db("file:app.db?node=secondary&connect=tcp://myserver.ddns.net:1234"); // wait until the database is ready while(1) { string status; db << "pragma sync_status" >> status; cout << "status : " << status << endl; if (status.find("\"db_is_ready\": true") != string::npos) break; sleep(1); } // now the application can access the database // check examples here: // https://github.com/SqliteModernCpp/sqlite_modern_cpp ... } catch (exception& e) { cout << e.what() << endl; } }
import litesync as sqlite3 import json import time conn = sqlite3.connect('file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234') # check if the db is ready while not conn.is_ready(): time.sleep(0.250) start_access(conn)
const uri = 'file:test.db?node=secondary&connect=tcp://127.0.0.1:1234'; const options = { verbose: console.log }; const db = require('better-sqlite3-litesync')(uri, options); db.on('ready', function() { // the database is ready to be accessed db.exec('CREATE TABLE IF NOT EXISTS users (name, email)'); ... });
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import org.json.*; public class Sample { public static void main(String[] args) { String uri = "file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234"; Connection connection = DriverManager.getConnection("jdbc:sqlite:" + uri); Statement statement = connection.createStatement(); // check if the db is ready while (true) { ResultSet rs = statement.executeQuery("PRAGMA sync_status"); rs.next(); JSONObject obj = new JSONObject(rs.getString(1)); if (obj.getBoolean("db_is_ready")) break; Thread.sleep(250); } // now we can access the db start_access(connection); } }
using SQLite; public class Program { public static void Main() { // open the database var uri = "file:app.db?node=secondary&connect=tcp://server:port"; var db = new SQLiteConnection(uri); // wait until the db is ready while (!db.IsReady()) { System.Threading.Thread.Sleep(250); } // now we can use the database db.CreateTable<TodoItem>(CreateFlags.AutoIncPK); ... } }
Imports SQLite Public Class Program Public Shared Sub Main() ' open the database Dim db As New SQLiteConnection("file:app.db?node=secondary&connect=tcp://server:port") ' wait until the db is ready While Not db.IsReady() System.Threading.Thread.Sleep(250) End While ' now we can use the database db.CreateTable(Of TodoItem)(CreateFlags.AutoIncPK) ' ... End Sub End Class
Option Explicit Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long) Public Sub Main() Dim Conn As New ADODB.Connection Dim Rst As ADODB.Recordset Dim URI As String URI = "file:C:\app\mydb.db?node=secondary&connect=tcp://myserver.ddns.net:1234" Conn.Open "DRIVER=SQLite3 ODBC Driver;Database=" & URI ' Check if the database is ready Do Set Rst = New ADODB.Recordset Rst.Open "PRAGMA sync_status", Conn, , , adCmdText If InStr(Rst!sync_status, """db_is_ready"": true") > 0 Then Exit Do Sleep 200 Loop ' Now we can access the db StartDbAccess(Conn) End Sub
<?php // with sqlite3: $db = new SQLite3("file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234"); // with pdo_sqlite: $pdo = new PDO("sqlite:file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234"); // check if the db is ready while(1) { $results = $db->query('PRAGMA sync_status'); $row = $results->fetchArray(); $status = json_decode($row[0], true); if ($status['db_is_ready'] == true) break; sleep(0.25); } // now we can access the db start_access($db); ?>
use DBI; use JSON qw( decode_json ); my $dbh = DBI->connect("dbi:SQLite:uri=file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234"); // check if the db is ready - it should not be used with apache while (1) { my ($result) = $dbh->selectrow_array("PRAGMA sync_status"); my $status = decode_json($result); if ($status->{'db_is_ready'}) last; sleep; } // now we can access the db ...
require 'sqlite3' require 'json' db = SQLite3::Database.new "file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234" # check if the db is ready loop do result = db.get_first_value "PRAGMA sync_status" status = JSON.parse(result) break if status["db_is_ready"] == true sleep 0.25 end # now we can access the db start_access(db)
local sqlite3 = require "lsqlite3" local json = require "json" local db = sqlite3.open('file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234') -- check if the db is ready local lsocket = require("lsocket") while true do local result = db:rows("PRAGMA sync_status") local status = json:decode(result[0]) if status["db_is_ready"] == true then break end lsocket.select(250) end -- now we can access the db start_access(db)
package main import ( "database/sql" _ "github.com/litesync/go-sqlite3" "time" ) func main() { db, err := sql.Open("sqlite3", "file:/path/to/app.db?node=secondary&connect=tcp://myserver.ddns.net:1234") // wait until the db is ready for !db.IsReady() { time.Sleep(1000 * time.Millisecond) } // now we can access the db start_access(db) }
보안
LiteSync는 비밀 키를 사용한 암호화를 통해 어떤 노드가 네트워크의 일부가 될 수 있는지 제어하기 위해 "공유 비밀" 방식을 사용합니다
데이터베이스와 노드 간 통신에 대해 암호화를 활성화하는 것이 가능하며 권장됩니다
암호화에 대한 설명을 확인하세요
현재 제한 사항
1 비결정적 함수(호출할 때마다 다른 값을 반환하는 함수)는 random() 및 date('now')와 같이 차단됩니다. 앱에서 생성된 명시적인 값을 사용하세요
2 AUTOINCREMENT 키워드는 지원되지 않습니다 - 하지만 그것이 필요하지 않습니다! (자세한 내용은 비디오를 확인하세요)
3 단일 애플리케이션만이 동시에 데이터베이스에 접근할 수 있습니다. 각 인스턴스는 자신의 데이터베이스를 사용해야 하며, 그런 다음 LiteSync를 사용하여 복제되고 동기화됩니다