طريقة إنشاء نسخة إحتياطية من قاعدة بيانات MySQL و استرجاع النسخة الإحتياطية في بايثون؟
عملت بقاعدة بيانات SQLite3 لكن لم أستطع تأمينها. و أعتقد أن MySQL آمنة.
المشكلة أنني عندما أريد عمل نسخة إحتياطية من أجل نسخ كل البيانات الموجودة فيها و أنقلها لجهاز آخر كتحديث لقاعدة البيانات.
عند محاولة إسترجاع البيانات من نسخة موجودة تظهر لي المشكلة كالتالي:
1136 (21S01): Column count doesn't match value count at row 1
كود إسترجاع النسخة:
def restore_database(self): # Encryption key key = b'wWU9Yh3Q7JN5XXpbK43YuMYQtA9yUI3wdDzmADMUOzk=wq' # Initialize the Fernet cipher with the key cipher = Fernet(key) try: conn = mysql.connector.connect( host="localhost", user="root", password=self.hashed_password1, database="color_group" ) c = conn.cursor() c.execute("CREATE DATABASE IF NOT EXISTS color_group") c.execute("USE color_group") # Define the table structure without the image column table_structure = """CREATE TABLE IF NOT EXISTS color_numbers ( id INTEGER PRIMARY KEY AUTO_INCREMENT, id_name varchar(255), ingred1 varchar(255), ingred2 varchar(255), ingred3 varchar(255), ingred4 varchar(255), ingred5 varchar(255), ingred6 varchar(255), ingred7 varchar(255), ingred8 varchar(255), ingred9 varchar(255), info1 varchar(255), info2 varchar(255), info3 varchar(255), info4 varchar(255), info5 varchar(255), info6 varchar(255), info7 varchar(255), info8 varchar(255), info9 varchar(255), quantity_no1 float, quantity_no2 float, quantity_no3 float, quantity_no4 float, quantity_no5 float, quantity_no6 float, quantity_no7 float, quantity_no8 float, quantity_no9 float, puplic_name varchar(255), client1 varchar(255), client2 varchar(255), client3 varchar(255), client4 varchar(255), client5 varchar(255), client6 varchar(255), image LONGBLOB, word VARCHAR(255), tof TINYINT, colorid VARCHAR(255) )""" backup_file_path = filedialog.askopenfilename() # Prompt user to select a database file if backup_file_path: c.execute("DROP TABLE IF EXISTS color_numbers") c.execute(table_structure) with open(backup_file_path, "rb") as backup_file: encrypted_data = backup_file.read() # Decrypt the data decrypted_data = cipher.decrypt(encrypted_data).decode('"ISO-8859-1"') # Remove the image column from the SQL commands sql_commands = re.sub(r'`image` LONGBLOB,?', '', decrypted_data) sql_commands = sql_commands.split(';') for command in sql_commands: if command.strip() and "INSERT INTO color_numbers" in command: c.execute(command) c.execute("ALTER USER 'root'@'localhost' IDENTIFIED BY %s", (self.hashed_password1,)) c.execute("update color_numbers set tof = 0") else: self.create_database() return conn.commit() c.close() conn.close() msg.showinfo("قاعدة البيانات", " تم استعادة قاعدة البيانات بنجاح. سيتم الخروج الان") self.on_closing() except Exception as e: msg.showerror("خطأ", f"{e}") print(e)
سؤال ثاني
مستقبلاً لو أردت إضافة COLUMN جديد و عملت نسخة جديدة من أجل تحديث قاعدة البيانات فهل سيستقبل التحديث الجديد أم سيظهر لي أخطاء جديدة؟
أنا أستخدم تشفير Fernet من أجل تشفير ملف المنشئ من النسخة.
كود إنشاء النسخة: الكود التالي يعمل نسخة إحتياطية، أولاً ينشئ ملف إمتداده .sql
غير مشفر بعدها يشفر هذا الملف بصيغة .enc
و بعدها يحذف الملف الغير مشفر نهائياً.
def create_copy_of_database(self): try: conn = self.connect_to_database() cursor = conn.cursor() # Prompt the user to select a backup location backup_folder = filedialog.askdirectory() if backup_folder: # Ensure a folder was selected # Generate backup file name with timestamp backup_file_name = f"Database_Backup_{datetime.now().strftime('%Y-%m-%d_%H-%S')}.sql" backup_location = os.path.join(backup_folder, backup_file_name) # Creating backup file with open(backup_location, "w") as backup_file: # rest of the function remains the same cursor.execute("SHOW TABLES") tables = cursor.fetchall() for table in tables: table_name = table[0] cursor.execute(f"SELECT * FROM {table_name}") rows = cursor.fetchall() backup_file.write(f"\n-- Table structure for table {table_name}\n") cursor.execute(f"SHOW CREATE TABLE {table_name}") create_table = cursor.fetchone()[1] backup_file.write(f"{create_table};\n") backup_file.write(f"\n-- Data for table {table_name}\n") for row in rows: values = [] for value in row: if isinstance(value, str): values.append(f"'{value}'") elif isinstance(value, bytes): values.append(f"x'{value.hex()}'") elif value is None: values.append("NULL") elif isinstance(value, float): values.append(repr(value)) else: values.append(str(value)) insert_query = f"INSERT INTO {table_name} VALUES ({', '.join(values)});\n" backup_file.write(insert_query) # Perform encryption encryption_key = b'wWU9Yh3Q7JN5XXpbK43YuMYQtA9yUI3wdDzmADMUOzk=wq' # Encryption key with open(backup_location, 'rb') as f: data = f.read() fernet = Fernet(encryption_key) encrypted_data = fernet.encrypt(data) encrypted_backup_file_name = f"Encrypted_Database_Backup_{datetime.now().strftime('%Y-%m-%d_%H-%S')}.enc" encrypted_backup_location = os.path.join(backup_folder, encrypted_backup_file_name) with open(encrypted_backup_location, 'wb') as f: f.write(encrypted_data) os.unlink(backup_location) # Permanently delete the unencrypted .sql file cursor.close() conn.close() msg.showinfo("Success", "تمت العملية بنجاح.") os.startfile(backup_folder) else: self.general_manager() return except Exception as e: msg.showerror("خطأ في إجراء العملية", f"{e}")
إذا أحد عنده فكرة حول تشفير الملف قبل حفظه، و ليس حفظه كملف غير مشفر و بعدها يتم تشفيره ثم يتم حذفه، أتمنى ذكرها.
إن شاء الله وصلت الفكرة.