Найти - Пользователи
Полная версия: Работа с одной БД из двух программ
Начало » Python для новичков » Работа с одной БД из двух программ
1 2 3
AngelFrei
Добрый всем вечер, не могу решить задачу и найти на неё ответа, возможно кто-то сможет мне в этом помочь, вопрос следующий:
возможно ли в созданной базе данных с помощью модуля shelve вносить изменения одновременно из двух программ; то есть может возникнуть момент, когда запрос на открытие этой БД произойдёт в одно и то же время в обоих программах и тогда возникает ошибка, как её можно избежать?
4kpt_III
shelve это не совсем база данных. Смотрите в сторону SQL баз данных. Для начала рекомендуется использовать sqlite. Она идет в комплекте с питоном и очень легковесная. Сразу рациональным можно считать изучения ORM. Рекомендую sqlalchemy.
Iskatel
Ну а по сути вопроса - одновременно НЕТ (ни одна БД не даст одновременно, ибо это бред), а по очереди да… Перед открытием базы из программы создавай файл на диске (любой, лишь бы был), так линуксы поступают… закончил - удаляй. Из другой проги тоже самое. Соответственно обе проги ждут пока файла не станет…

А sqlite, те же грабли, разве что SQL поддерживает. Один фиг файловая и однопоточная. MySQL например или другая серверная БД в этом проще, но все равно по очереди. Разве что они, серверные, многое с доступом автоматически рулят.
AngelFrei
А если не переходить на mySQL, можно как-то перед использованием файла с БД проверить его состояние: открыт он уже другой программой или нет? Чтобы подобие очереди создать… Или совет с созданием файла это как раз единствееный выход для этой проверки? В любом случае, уже спасибо за идею!
FishHook
По-моему, вам тут глупости говорят. SQLite вроде как давно уже по умолчанию поддерживает многопоточный режим, поэтому никаких проблем с конкурентным доступом быть не должно. Вот такой простой тест:
#!/usr/bin/env python
# -* coding: utf-8 -*-
import sqlite3
import time
import random
import sys
conn = sqlite3.connect('example.db')
c = conn.cursor()
proccess = sys.argv[1]
for i in range(10):
    c.execute("INSERT INTO test VALUES (?, ?)", ["process %s" % proccess, random.randint(0, 10000)])
    conn.commit()
    time.sleep(random.randint(1, 8))
c.execute("select * from test")
print "result = "
for i in c.fetchall():
    print i
conn.close()

запускаем этот скрипт одновременно в двух разных терминалах, эмулируя одновременную работу двух программ,
python test_insert.py 1
python test_insert.py 2
получаем 20 вставок в БД

(u'process 1', 3787.0)
(u'process 1', 6370.0)
(u'process 2', 2569.0)
(u'process 2', 6926.0)
(u'process 1', 5498.0)
(u'process 2', 275.0)
(u'process 1', 2108.0)
(u'process 1', 4542.0)
(u'process 2', 3892.0)
(u'process 1', 3357.0)
(u'process 2', 6789.0)
(u'process 2', 3863.0)
(u'process 1', 9464.0)
(u'process 2', 2749.0)
(u'process 1', 1060.0)
(u'process 1', 3435.0)
(u'process 1', 9713.0)
(u'process 2', 7232.0)
(u'process 2', 7931.0)
(u'process 2', 812.0)

Или это не то, что нужно топикстартеру?
Iskatel
FishHook
умолчанию поддерживает многопоточный режим
поддерживает, всмысле целостность данных не нарушиться, а вот реализована эта поддержка методом полной блокировки.

сделай так: в одной консольке подвесь открытое соединение, например так
import sqlite3
import time
conn = sqlite3.connect('example.db')
res = conn.execute("select * from test")
res.fetchone()
time.sleep(100)

а в другой запусти это
import sqlite3
conn = sqlite3.connect('example.db')
conn.execute("INSERT INTO test VALUES (?, ?)", ['test', 1])
conn.commit()

у меня (второй питон) стабильно

Traceback (most recent call last):
File "D:\ !\untitled136.py", line 15, in <module>
conn.commit()
sqlite3.OperationalError: database is locked
FishHook
Ну это если хочется назло бабушке уши отморозить. Я тебе и в оракле таблицу намертво заблокирую.
А если нужно нормально работать, не городите длинных транзакций.
Iskatel
FishHook
Ну это если хочется назло бабушке уши отморозить. Я тебе и в оракле таблицу намертво заблокирую.
А если нужно нормально работать, не городите длинных транзакций.

Намертво это для примера. Вот ваш пример работает только потому, что вставки успевают “проскочить” между друг другом. А если встретятся - краш. Оно конечно будет работать, до какогото вошебного момента, может вообще всю жизнь не упадет. Но знать о проблеме и оставлять бомбу в программе ИМХО не стоит.

Iskatel
AngelFrei
то есть может возникнуть момент, когда запрос на открытие этой БД произойдёт в одно и то же время в обоих программах и тогда возникает ошибка, как её можно избежать?

Я сумбурно написал - попробую подробней.
перед тем как полезть в базу, проверь нет ли на диске файла с именем “не лезь в базу”.

1. если нет, создай такой, работай с базой, удали файл.
2. если есть, жди полсекунды и снова пробуй.
В другой программе тоже самое.

Соответственно файл живет всего долю секунды (или сколько там вставка происходит)

Стандартное решение таких задач…
FishHook
Iskatel
А если встретятся - краш

sqlite.connect("database.sql", timeout=30000.0)
И пусть они себе встречаются
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB