Motty
터미널·SFTP·포트 포워딩·VNC·RDP·AI 도우미를 하나의 창에 통합, Go 기반 무료 오픈소스
Go로 만든 가벼운 임베디드 관계형 데이터베이스, 단일 파일에 의존성 없이 전체 SQL·트랜잭션·인덱스와 서버 제공
A lightweight embedded relational database written in Go. No dependencies and a single data file, with full SQL, transactions and indexes, plus a server…
개발 도구Go · HTMLGitHub @MinaryHub온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
소규모 프로젝트를 위한 다목적 경량 관계형 DB (순수 Go, 의존성 0) — 임베디드·서버·웹 콘솔, 인메모리·시계열 테이블 / A multipurpose relational database for small projects in pure Go
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Go로 작성된 경량 임베디드 관계형 데이터베이스입니다. 외부 의존성 0개, 단일 파일 저장, 프로젝트에 라이브러리로 바로 넣어 쓰는 것을 목표로 합니다 (SQLite와 같은 사용 방식).
go.mod에 require 없음)<파일>-wal) 기반 원자적·내구성 있는 커밋과 크래시 복구, 페이지 체크섬, 무결성 검사(IntegrityCheck):memory: 인메모리 모드CREATE/DROP TABLE, ALTER TABLE ADD/RENAME/DROP COLUMN, RENAME TO, CREATE [UNIQUE] INDEX(복합·부분 WHERE), CREATE TRIGGER, CREATE VIEW, INSERT/SELECT/UPDATE/DELETE, JOIN(INNER/LEFT/CROSS), GROUP BY/HAVING, ORDER BY, LIMIT/OFFSET, DISTINCT, CASE, IN, BETWEEN, LIKE, COLLATE, 집계/스칼라/날짜 함수, EXPLAIN, VACUUM
EXISTS·IN (SELECT)·FROM (SELECT), 상관 포함), UNION [ALL]/INTERSECT/EXCEPTON CONFLICT … DO NOTHING / DO UPDATE), INSERT OR IGNORE/REPLACE, INSERT … SELECT, RETURNINGPRIMARY KEY/UNIQUE, NOT NULL, DEFAULT, CHECK, FOREIGN KEY(CASCADE/SET NULL/RESTRICT)?, ?N, :name, @name, $nameOVER (PARTITION BY … ORDER BY … ROWS/RANGE …)), JSON 함수와 ->/->> 연산자CREATE TRIGGER … BEFORE|AFTER INSERT|UPDATE [OF cols]|DELETE ON t [WHEN cond] BEGIN … END, NEW/OLD, RAISE(ABORT, '메시지')·RAISE(IGNORE)ANALYZE 통계 기반 조인 순서internal/store, CREATE TABLE … USING <kind>) — 기본은 B+트리, USING memory 인메모리 테이블, USING timeseries 시계열 테이블BEGIN/COMMIT/ROLLBACK, 문장 단위 원자성, 스냅샷 읽기 — 읽기와 쓰기가 서로를 기다리지 않음context 기반 쿼리 취소·타임아웃, 그룹 커밋database/sql 드라이버(bangdb) 및 대화형 CLI 제공, 서버 모드(TCP/TLS, 인증, bangdb:// DSN)db.Stats(), 슬로우 쿼리 훅, EXPLAIN ANALYZE, SQL 덤프·SQLite 덤프 가져오기·CSV, 저장 데이터 암호화(AES-256-XTS), 반동기 복제·펜싱·특정 시점 복구(PITR)go get github.com/knoxxr/bangdb
안드로이드 앱에 내장: docs/ANDROID.md (.aar, Kotlin/Java API com.knoxxr.bangdb).
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/knoxxr/bangdb"
)
func main() {
db, err := bangdb.Open("app.db") // 인메모리: bangdb.Open(":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE,
age INT DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_users_age ON users (age);
`)
if err != nil {
log.Fatal(err)
}
res, _ := db.Exec(`INSERT INTO users (name, email, age) VALUES (?, ?, ?)`, "kim", "[email protected]", 31)
fmt.Println("new id:", res.LastInsertID)
// 트랜잭션: fn이 nil을 반환하면 커밋, 에러면 롤백
err = db.Update(func(tx *bangdb.Tx) error {
_, err := tx.Exec(`UPDATE users SET age = age + 1 WHERE id = ?`, res.LastInsertID)
return err
})
// 결과는 스트리밍됩니다. 끝까지 읽지 않을 때는 반드시 Close 하세요.
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
rows, err := db.QueryContext(ctx, `SELECT id, name, age FROM users WHERE age > ? ORDER BY age DESC`, 20)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int64
var name string
var age int
rows.Scan(&id, &name, &age)
fmt.Println(id, name, age)
}
if err := rows.Err(); err != nil { // 예: 타임아웃
log.Fatal(err)
}
var count int
db.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&count)
}
applied, err := db.Migrate(ctx, []bangdb.Migration{
{Version: 1, SQL: `CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)`},
{Version: 2, SQL: `ALTER TABLE users ADD COLUMN email TEXT`},
{Version: 3, Func: func(tx *bangdb.Tx) error { _, err := tx.Exec(`UPDATE users SET email = ''`); return err }},
})
PRAGMA user_version에 마지막으로 적용한 버전이 기록되고, 각 단계는 자기 트랜잭션에서 실행되어 실패하면 그 단계만 취소됩니다. 그 밖의 PRAGMA: table_info(t), index_list(t), index_info(i), table_list, integrity_check, foreign_keys, journal_mode, page_count, page_size.
get, _ := db.Prepare("SELECT name FROM users WHERE id = ?") // 파싱 1회, 플랜 보관 (동시 사용 가능)
var name string
get.QueryRow(42).Scan(&name)
import (
"database/sql"
_ "github.com/knoxxr/bangdb/driver"
)
db, err := sql.Open("bangdb", "app.db")
같은 *sql.DB의 모든 커넥션은 하나의 엔진 인스턴스를 공유합니다 (:memory:도 커넥션 간 공유됨).
db.Backup("backup.db") // 온라인 백업 (결과는 그대로 열 수 있는 DB 파일)
// primary
p := replication.NewPrimary(db, replication.PrimaryOptions{Token: "secret"})
go p.ListenAndServe(":7070")
// replica (다른 서버): 처음엔 스냅샷을 받고, 이후 커밋을 실시간 미러링
rdb, _ := bangdb.Open("replica.db")
r := replication.StartReplica(rdb, "primary:7070", replication.ReplicaOptions{Token: "secret"})
rdb.Query("SELECT ...") // 읽기 분산; 쓰기는 ErrReadOnly
r.Promote() // 장애 조치: 쓰기 가능한 primary로 승격
자세한 내용: docs/REPLICATION.md
// 서버: DB를 연 프로세스가 TCP/TLS로 제공
srv := server.New(db, server.Options{Password: "s3cret", MaxConns: 100, IdleTimeout: 10 * time.Minute})
go srv.ListenAndServe("127.0.0.1:7432") // 또는 ListenAndServeTLS(addr, tlsConfig)
// 클라이언트: 직접
c, _ := client.Dial(ctx, "db.internal:7432", &client.Options{User: "app", Password: "s3cret"})
rows, _ := c.Query(ctx, "SELECT id, name FROM users WHERE age > ?", 30)
// 클라이언트: database/sql (커넥션 풀)
sdb, _ := sql.Open("bangdb", "bangdb://app:[email protected]:7432?tls=1")
BEGIN/COMMIT이 그대로 동작하고, 연결이 끊기면 열린 트랜잭션은 롤백됩니다. 결과는 스트리밍되며 Rows.Close나 ctx 취소가 서버의 실행 중인 문장을 중단합니다. 오류 종류는 유지됩니다(errors.Is(err, bangdb.ErrConstraint) 등).Options.Authenticate(user, password) 콜백, 암호화는 TLS. 루프백 왕복 지연은 단건 조회 약 44 µs.bangdb -listen :7432 -password s3cret [-tls-cert c.pem -tls-key k.pem] app.db, 원격 셸 bangdb -connect bangdb://app:s3cret@host:7432.여기까지가 README 앞부분입니다. 나머지는 원문에서 읽을 수 있습니다. README 전문 보기 ↗