2026-05-22 14:03:24 +08:00

88 lines
2.2 KiB
Go

package storage
import (
"context"
"database/sql"
"fmt"
"github.com/go-mysql-org/go-mysql/mysql"
"dashboard-cdc-worker/internal/config"
)
const serviceName = "dashboard-cdc-worker"
type MySQLRepository struct {
db *sql.DB
cfg config.Config
}
func NewMySQLRepository(db *sql.DB, cfg config.Config) *MySQLRepository {
return &MySQLRepository{db: db, cfg: cfg}
}
func (r *MySQLRepository) WithTx(ctx context.Context, fn func(*sql.Tx) error) error {
tx, err := r.db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted})
if err != nil {
return err
}
if err := fn(tx); err != nil {
_ = tx.Rollback()
return err
}
return tx.Commit()
}
func (r *MySQLRepository) LoadCheckpoint(ctx context.Context) (mysql.Position, bool, error) {
var file string
var pos uint32
err := r.db.QueryRowContext(ctx, `
SELECT binlog_file, binlog_pos
FROM dashboard_cdc_checkpoint
WHERE service_name = ?
`, serviceName).Scan(&file, &pos)
if err == sql.ErrNoRows {
return mysql.Position{}, false, nil
}
if err != nil {
return mysql.Position{}, false, err
}
return mysql.Position{Name: file, Pos: pos}, true, nil
}
func (r *MySQLRepository) SaveCheckpoint(ctx context.Context, pos mysql.Position) error {
_, err := r.db.ExecContext(ctx, `
INSERT INTO dashboard_cdc_checkpoint (service_name, binlog_file, binlog_pos, updated_at)
VALUES (?, ?, ?, NOW())
ON DUPLICATE KEY UPDATE
binlog_file = VALUES(binlog_file),
binlog_pos = VALUES(binlog_pos),
updated_at = NOW()
`, serviceName, pos.Name, pos.Pos)
return err
}
func (r *MySQLRepository) MarkEventApplied(ctx context.Context, tx *sql.Tx, eventKey string, source string) (bool, error) {
result, err := tx.ExecContext(ctx, `
INSERT IGNORE INTO dashboard_cdc_event_dedup (event_key, source, created_at)
VALUES (?, ?, NOW())
`, eventKey, source)
if err != nil {
return false, err
}
affected, err := result.RowsAffected()
if err != nil {
return false, err
}
return affected > 0, nil
}
func execAll(ctx context.Context, db *sql.DB, statements []string) error {
for _, stmt := range statements {
if _, err := db.ExecContext(ctx, stmt); err != nil {
return fmt.Errorf("exec schema failed: %w; sql=%s", err, stmt)
}
}
return nil
}