Как предотвратить одновременное создание дублирующих элементов? - PullRequest
2 голосов
/ 27 ноября 2010

У меня есть объект модели SQLAlchemy, который выглядит следующим образом:

ResultModelBase = declarative_base()
class Task(ResultModelBase):
    """Task result/status."""

    id = sa.Column(sa.Integer, sa.Sequence("task_id_sequence"),
                   primary_key=True,
                   autoincrement=True)
    task_id = sa.Column(sa.String(255))

В двух отдельных клиентских процессах этот код запускается для создания нового экземпляра с уникальным идентификатором task_id; должен быть только один экземпляр task_id:

task = session.query(Task).filter(Task.task_id == task_id).first()
if not task:
    task = Task(task_id)
    session.add(task)
    session.flush()

Как мне переписать этот код, чтобы он атомарно создавал задачу с указанным идентификатором?

Ответы [ 2 ]

2 голосов
/ 27 ноября 2010

Ваша проблема плохо определена. У вас есть недостаток дизайна в вашей базе данных. Вы не можете определить уникальность строки по ее автоматически увеличивающемуся идентификатору. У вас должны быть другие поля, которые определяют его как уникальное (например, имя_задачи + работник), а затем создайте задачу по следующим полям: Task(task_name=smt, worker=smt) - не ставьте task_id вручную - она ​​будет автоматически назначена как следующий идентификатор таблицы. Используйте первичные ключи autoinc только для поиска и связей - но всегда ставьте уникальный ключ, составленный из других таблиц. Если вы не можете выяснить, какие поля - чем ваша таблица не нормируется.

Теперь к проблеме обработки вставки дубликатов: session.flush () # выполняет предыдущую работу

session.flush()
try: 
    t = Task(task_name=smt, worker=smt)
    session.add()
    session.flush()
except sqlalchemy.exc.IntegrityError:
    # task already exists 
else:
    # task added to db
0 голосов
/ 27 ноября 2010

Используйте блокировки вокруг блока кода.

# lock here
task = session.query(Task).filter(Task.task_id == task_id).first()
if not task:
    task = Task(task_id)
    session.add(task)
    session.flush()
# unlock here
...