У меня есть usecase в whch Мне нужно читать rows
имеющие status = 0
из mysql.
Схема таблицы:
CREATE TABLE IF NOT EXISTS in_out_analytics(
id INT AUTO_INCREMENT PRIMARY KEY,
file_name VARCHAR(255),
start_time BIGINT,
end_time BIGINT,
duration INT,
in_count INT,
out_count INT,
status INT
)
Я использую этот ниже код для чтения данных из mysql.
persistance.py
import mysql
import mysql.connector
import conf
class DatabaseManager(object):
# global vars to storing db connection details
connection = None
def __init__(self):
self.ip = conf.db_ip
self.user_name = conf.db_user
self.password = conf.db_password
self.db_name = conf.db_name
# Initialize database only one time in application
if not DatabaseManager.connection:
self.connect()
self.cursor = DatabaseManager.connection.cursor()
self.create_schema()
def connect(self):
try:
DatabaseManager.connection = mysql.connector.connect(
host= self.ip,
database = self.db_name,
user = self.user_name,
password = self.password
)
print(f"Successfully connected to { self.ip } ")
except mysql.connector.Error as e:
print(str(e))
def create_schema(self):
# Create database
# sql = f"CREATE DATABASE { self.db_name} IF NOT EXIST"
# self.cursor.execute(sql)
# Create table
sql = """
CREATE TABLE IF NOT EXISTS in_out_analytics(
id INT AUTO_INCREMENT PRIMARY KEY,
file_name VARCHAR(255),
start_time BIGINT,
end_time BIGINT,
duration INT,
in_count INT,
out_count INT,
status INT
)"""
self.cursor.execute(sql)
def read_unprocessed_rows(self):
sql = "SELECT id, start_time, end_time FROM in_out_analytics WHERE status=0;"
self.cursor.execute(sql)
result_set = self.cursor.fetchall()
rows = []
for row in result_set:
id = row[0]
start_time = row[1]
end_time = row[2]
details = {
'id' : id,
'start_time' : start_time,
'end_time' : end_time
}
rows.append(details)
return rows
test.py
import time
from persistance import DatabaseManager
if __name__ == "__main__":
# Rows which are inserted after application is started do not get processed if
# 'DatabaseManager' is defined here
# dm = DatabaseManager()
while True:
# Rows which are inserted after application is started do get processed if
# 'DatabaseManager' is defined here
dm = DatabaseManager()
unprocessed_rows = dm.read_unprocessed_rows()
print(f"unprocessed_rows: { unprocessed_rows }")
time.sleep(2)
Проблема:
Проблема заключается в том, что когда я определяю объект базы данных dm = DatabaseManager()
над циклом while, любая новая строка, вставленная после запуска приложения, не обрабатывается, и если я определяю dm = DatabaseManager()
внутри цикла while, строки, которые вставлены даже после запуска приложения, обрабатываются.
В чем проблема с вышеуказанным кодом?
В идеале мы должны сделать только один объект DatabaseManager
как этот класс создает соединение с MySQL. Следовательно, создание соединения с любой базой данных должно быть идеальным.
Сделав здесь предположение, поскольку я не могу проверить его сам.
tl; dr: Добавить DatabaseManager.connection.commit()
в ваш read_unprocessed_rows
Когда вы выполняете оператор SELECT, транзакция создается неявно, используя уровень изоляции по умолчанию REPEATABLE READ. Это создает моментальный снимок базы данных в этот момент времени, и все последовательные чтения в этой транзакции будут считываться из моментального снимка, установленного во время первого чтения. Влияние различных уровней изоляции описаны здесь. Чтобы обновить моментальный снимок в REPEATABLE READ, вы можете перенести свою текущую транзакцию перед выполнением следующего оператора.
Поэтому, когда вы создаете экземпляр DatabaseManager
внутри цикла, каждый SELECT запускает новую транзакцию в новом соединении, поэтому каждый раз имеет новый снимок. При создании экземпляра вашего Databasemanager
вне цикла транзакция, созданная первым SELECT, сохраняет тот же снимок для всех последовательных SELECT и обновлений извне, транзакция остается невидимой.