Перенос/копирование базы данных с помощью automap_base и перегонного куба

У меня есть база данных x с некоторым объемом данных, заполненных в каждой таблице. Я хочу создать копию этой базы данных (с той же схемой и точными данными). Сначала я создаю декларативный базовый класс x, используя automap_base.

from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session as s

def name_for_scalar_relationship(base, local_cls, referred_cls, constraint):
    name = referred_cls.__name__.lower() + "_ref"
    return name

Base = automap_base()

# engine, refering to the original database
engine = create_engine("mysql+pymysql://root:password1@localhost:3306/x")

# reflect the tables
Base.prepare(engine, reflect=True, name_for_scalar_relationship=name_for_scalar_relationship)

Router = Base.classes.router
########check the data in Router table
session = s(engine)
r1 = session.query(Router).all()
for n in r1:
    print(n.name)   #This returns all the router names

Получение помощи от здесь Я использую alembic для обновления базы данных y находится в другом месте mysql+pymysql://anum:Anum-6630@localhost:3306/y.

from sqlalchemy.orm import sessionmaker as sm
from sqlalchemy import create_engine
from alembic import op

# revision identifiers, used by Alembic.
revision = 'fae98f65a6ff'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    bind = op.get_bind()
    session = sm(bind=bind)
    Base.metadata.create_all(bind=bind)

    # session._add_bind(session, bind=bind)
    session.add(Router(id=uuid.uuid().bytes, serial="Test1"))
    session.commit()

Строка Base.metadata.create_all(bind=bind) фактически добавляет все таблицы (включая соответствующие ограничения FK) в базу данных y, но все таблицы пусты, кроме одной записи в таблице Router, которую я добавил вручную. Я пытался использовать create_all(), но это тоже не сработало. Есть ли способ скопировать все данные из базы данных x в базу данных y?


person Anum Sheraz    schedule 22.11.2018    source источник


Ответы (1)


Поскольку никто не ответил, вот мой дикий метод, который выполняет копирование: поскольку таблицы необходимо создавать по порядку (чтобы избежать ошибок ограничений FK), я должен определить упорядоченный список, содержащий каждую таблицу

Медленное и НЕнадежное решение:

allTables = ["tableA", 
             "tableB", # <table B points to FK constraint of tableA>
             "tableC", # <table C points to FK constraint of tableB>
             ...]

def copyAllContent():
    global allTables
    s = Session(bind=origEngine)  # session bind to original table
    se = Session(bind=op.get_bind()) # session bind to cloned table (currently empty)
try:
    for table in allTables:
        # print(table)
        rows = s.query(Base.classes._data[table]).all()
        for row in rows:
            local_object = se.merge(row)  #merging both sessions
            se.add(local_object)
            se.commit()
except Exception as e:
    print(e)

Описанный выше метод работал для большинства таблиц, но не для всех. например таблица router существовала в исходной базе данных, но все же я получаю ошибки в s.query(Base.classes._data[table]).all() ключ с именем router не существует. У меня нет достаточно времени, чтобы докопаться до решения для этого.

БЫСТРОЕ и надежное решение:

Позже я нашел отсюда другое БЫСТРОЕ и надежное решение с использованием mysqldump

#copy sql dump from x database
mysqldump --column-statistics=0 -P 8000 -h localhost -u root -p --hex-blob x > x_dump.sql

Приведенная выше команда командной строки mysqldump создает файл дампа sql с именем x_dump.sql, который содержит все необходимые сценарии SQL, необходимые для повторного создания базы данных. Теперь все, что нам нужно сделать, это применить этот файл дампа sql к другой базе данных y

#clone the database contents into y database
mysql -P 3306 -h localhost -u anum -p y < x_dump.sql

Вот питоническая версия того же самого

import subprocess

#copy sql dump from x database - blocking call (use Popen for non-blocking)
print(subprocess.call(["mysqldump", "--column-statistics=0", '-P', '8000', '-h', 'localhost', '-u', '<user>', '-p<password>',
                        '--hex-blob', 'x', '>', 'x_dump.sql'], shell=True))

print("done taking dump.")

#clone the database contents into y database - blocking call
print(subprocess.call(["mysql", '-P', '3306', '-h', 'localhost', '-u', '<user>', '-p<password>',
                        'y', '<', 'x_dump.sql'], shell=True))

print("done cloning the sqlDump.")
person Anum Sheraz    schedule 23.11.2018
comment
Версия mysqldump, которую я использую, — 8.0.12. Принимая во внимание, что если вы пробуете более новую версию 10.x.xx. не указывайте --column-statistics=0 аргумент. Также удалите shell=True из скрипта Python. - person Anum Sheraz; 13.12.2018