feat: 添加SQLite数据库支持并迁移数据转换脚本
- 新增init_sqlite.py脚本,用于将MySQL转储文件转换为SQLite数据库 - 实现MySQL到SQLite的语法转换,包括数据类型映射、表结构清理等功能 - 在pom.xml中替换MySQL驱动为SQLite驱动,并添加JDBC依赖 - 更新application.yml配置文件,切换数据库连接从MySQL到SQLite - 配置HikariCP连接池参数以适配SQLite数据库特性
This commit is contained in:
124
init_sqlite.py
Normal file
124
init_sqlite.py
Normal file
@@ -0,0 +1,124 @@
|
||||
"""Convert MySQL dump to SQLite database using executescript."""
|
||||
import re
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
MYSQL_DUMP = os.path.join(os.path.dirname(__file__), '..', 'psychologicaltreatment.sql')
|
||||
MYSQL_DUMP = os.path.normpath(MYSQL_DUMP)
|
||||
DB_PATH = os.path.join(os.path.dirname(__file__), 'psychologicaltreatment.db')
|
||||
|
||||
|
||||
def preprocess(sql):
|
||||
"""Remove MySQL-specific syntax, returns SQLite-compatible SQL."""
|
||||
# Remove lines that are MySQL meta commands
|
||||
lines = []
|
||||
for line in sql.splitlines():
|
||||
stripped = line.strip().upper()
|
||||
if any(stripped.startswith(x) for x in
|
||||
['SET NAMES', 'SET FOREIGN_KEY_CHECKS', 'SET SQL_MODE',
|
||||
'SET TIME_ZONE', 'SET CHARACTER_SET']):
|
||||
continue
|
||||
lines.append(line)
|
||||
sql = '\n'.join(lines)
|
||||
|
||||
# Process each CREATE TABLE separately
|
||||
# Strategy: find each CREATE TABLE block, clean it, replace it
|
||||
def clean_create(match):
|
||||
block = match.group(0)
|
||||
|
||||
# Remove table-level options: ENGINE=..., AUTO_INCREMENT=N, etc.
|
||||
block = re.sub(r'\)\s*ENGINE.*?;', ');', block, flags=re.IGNORECASE | re.DOTALL)
|
||||
|
||||
# Remove inline CHARACTER SET / COLLATE (column-level)
|
||||
block = re.sub(r'\s*CHARACTER\s+SET\s+\S+(?:\s+COLLATE\s+\S+)?', '', block, flags=re.IGNORECASE)
|
||||
block = re.sub(r'\s+COLLATE\s+\S+', '', block, flags=re.IGNORECASE)
|
||||
|
||||
# Remove inline COMMENT '...'
|
||||
block = re.sub(r"\s+COMMENT\s+'[^']*'", '', block, flags=re.IGNORECASE)
|
||||
|
||||
# Remove USING BTREE
|
||||
block = re.sub(r'\s+USING\s+BTREE', '', block, flags=re.IGNORECASE)
|
||||
|
||||
# Remove ON UPDATE CURRENT_TIMESTAMP
|
||||
block = re.sub(r'\s+ON\s+UPDATE\s+CURRENT_TIMESTAMP\s*(?:\([^)]*\))?', '', block, flags=re.IGNORECASE)
|
||||
|
||||
# MySQL types -> SQLite
|
||||
block = re.sub(r'\b(tinyint|smallint|mediumint|bigint|int)\s*\(\s*\d+\s*\)', 'INTEGER', block, flags=re.IGNORECASE)
|
||||
block = re.sub(r'\b(tinyint|smallint|mediumint|bigint|int)\b', 'INTEGER', block, flags=re.IGNORECASE)
|
||||
block = re.sub(r'\bvarchar\s*\(\s*\d+\s*\)', 'TEXT', block, flags=re.IGNORECASE)
|
||||
block = re.sub(r'\bdatetime\s*(?:\([^)]*\))?', 'TEXT', block, flags=re.IGNORECASE)
|
||||
block = re.sub(r'\bdate\b', 'TEXT', block, flags=re.IGNORECASE)
|
||||
block = re.sub(r'\b(tinytext|mediumtext|longtext)\b', 'TEXT', block, flags=re.IGNORECASE)
|
||||
|
||||
# AUTO_INCREMENT -> AUTOINCREMENT as INTEGER PRIMARY KEY
|
||||
block = re.sub(
|
||||
r'(`\w+`)\s+INTEGER\s+NOT\s+NULL\s+AUTO_INCREMENT',
|
||||
r'\1 INTEGER PRIMARY KEY AUTOINCREMENT',
|
||||
block, flags=re.IGNORECASE
|
||||
)
|
||||
block = re.sub(r'\bAUTO_INCREMENT\b', 'AUTOINCREMENT', block, flags=re.IGNORECASE)
|
||||
|
||||
if 'AUTOINCREMENT' in block:
|
||||
block = re.sub(r'\s*,\s*PRIMARY\s+KEY\s*\(`\w+`\)', '', block, flags=re.IGNORECASE)
|
||||
|
||||
# Remove standalone INDEX/KEY lines
|
||||
lines2 = block.splitlines()
|
||||
result2 = []
|
||||
for ln in lines2:
|
||||
s = ln.strip()
|
||||
if re.match(r'^\s*(INDEX|KEY)\s+', s, re.IGNORECASE) and \
|
||||
not re.match(r'^\s*(PRIMARY|UNIQUE)\s', s, re.IGNORECASE):
|
||||
# Remove trailing comma from previous line
|
||||
if result2 and result2[-1].strip().endswith(','):
|
||||
result2[-1] = result2[-1].rstrip(',')
|
||||
continue
|
||||
result2.append(ln)
|
||||
block = '\n'.join(result2)
|
||||
|
||||
# Remove trailing comma before )
|
||||
block = re.sub(r',\s*\)', '\n)', block)
|
||||
|
||||
return block
|
||||
|
||||
# Apply clean_create to all CREATE TABLE blocks
|
||||
sql = re.sub(r'CREATE\s+TABLE.*?;', clean_create, sql, flags=re.IGNORECASE | re.DOTALL)
|
||||
|
||||
return sql
|
||||
|
||||
|
||||
def main():
|
||||
with open(MYSQL_DUMP, 'r', encoding='utf-8') as f:
|
||||
raw = f.read()
|
||||
|
||||
sqlite_sql = preprocess(raw)
|
||||
|
||||
if os.path.exists(DB_PATH):
|
||||
os.remove(DB_PATH)
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.execute("PRAGMA journal_mode=WAL;")
|
||||
conn.execute("PRAGMA foreign_keys=OFF;")
|
||||
|
||||
# Use executescript which handles statement splitting properly
|
||||
try:
|
||||
conn.executescript(sqlite_sql)
|
||||
except sqlite3.Error as e:
|
||||
print(f"Error during executescript: {e}")
|
||||
|
||||
conn.commit()
|
||||
|
||||
# Verify
|
||||
cursor = conn.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
|
||||
tables = [row[0] for row in cursor.fetchall()]
|
||||
print(f"Database: {DB_PATH}")
|
||||
print(f"Tables created: {len(tables)}")
|
||||
for t in tables:
|
||||
if t == 'sqlite_sequence':
|
||||
continue
|
||||
count = conn.execute(f'SELECT COUNT(*) FROM "{t}"').fetchone()[0]
|
||||
print(f" {t}: {count} rows")
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
13
pom.xml
13
pom.xml
@@ -25,11 +25,22 @@
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--mysql-->
|
||||
<!--mysql
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
-->
|
||||
<!-- sqlite -->
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
|
||||
@@ -2,12 +2,22 @@ server:
|
||||
port: 9090
|
||||
|
||||
# 数据库配置
|
||||
# MySQL原始配置
|
||||
#spring:
|
||||
# datasource:
|
||||
# driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
# username: root
|
||||
# password: 123456
|
||||
# url: jdbc:mysql://localhost:3306/psychologicaltreatment?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=true
|
||||
|
||||
# SQLite
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: 123456
|
||||
url: jdbc:mysql://localhost:3306/psychologicaltreatment?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=true
|
||||
driver-class-name: org.sqlite.JDBC
|
||||
url: jdbc:sqlite:psychologicaltreatment.db
|
||||
hikari:
|
||||
maximum-pool-size: 1
|
||||
minimum-idle: 1
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 100MB
|
||||
|
||||
Reference in New Issue
Block a user