Я работаю в веб-приложении какое-то время, и впервые осознаю эту проблему, я думаю, что это может быть связано с тем, как обрабатываются сеансы SQLAlchemy, поэтому некоторые пояснения в простом виде были бы полезны. Моя конфигурация для работы с flask sqlAlchemy:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
Моя проблема: db.session.commit () иногда не сохраняет изменения. Я написал несколько flask конечных точек, которые достигаются через запросы внешнего интерфейса в браузере пользователя. В этом конкретном случае я редактирую объект «Бронирование» отеля, изменяя столбцы «Номера», которые являются текстовым полем.
функция выполняет следующие действия:
1 - запрашивает объект Booking по датам в запросе
2 - Редактирует столбец Rooms этого объекта Booking
3- Зафиксируйте изменения "db.session.commit ()"
4- Если у пользователя активна функция X, я провожу несколько проверок, вызывая вторую функцию:
· 4.1- Эти функции выполняют некоторые проверки, запрашивают и редактируют другой объект в базе данных, отличный от объекта «Бронирование», который я редактировал ранее.
· 4.2- В конце этой вторичной функции я вызываю db.session.commit () «Обратите внимание, что эти изменения всегда правильно сохраняются в базе данных»
· 4.3 - Вернуть результаты предыдущей функции
5 - Вернуть результаты во внешний интерфейс («непосредственно перед этим возвратом я распечатайте Booking.Rooms, чтобы убедиться, что он выглядит так, как должен, и это так ... Я даже пытался сделать вторую фиксацию после печати, но до возврата ... Но после этого иногда Booking.Rooms обновляются, как ожидалось но некоторые другие Иногда это не так ... Я заметил, что если повторить действие много раз, оно, наконец, сработает, но, учитывая, что промежуточная функция, "описанная в пункте 4", правильно сохраняет все его изменения, это вызывает несогласованность данных и сводит меня с ума, потому что если я повторяю действие и процедуру в функции пункта 4, я не могу повторить действие мода Rooms ...
Итак, теперь я действительно запутался, если это то, что я не понимаю из flask сеансов, насколько я понимаю, всякий раз, когда я делаю новый запрос к flask, это изолированный сеанс, верно? Я имею в виду, что если 2 одновременных пользователя сохраняют некоторые изменения в базе данных, db.session.commit () от одного из пользователей не фиксирует изменения от другого, верно?
То же самое, если я вызываю db.session.commit () в одном запросе, эти изменения сохраняются в базе данных, и если после этого «в том же запросе» я продолжаю изменять вещи, это похоже на другой сеанс, верно? И зафиксированные изменения там уже надежно сохранены? И я все еще могу использовать предыдущие объекты для дальнейших модификаций.
В любом случае, все это не должно быть проблемой, потому что после commit () я распечатываю Booking.Rooms и выглядит так, как ожидалось ... А иногда это работает правильно, а иногда нет ...
Также обратите внимание: когда я возвращаю этот результат клиенту, клиент мгновенно делает второй запрос к серверу, чтобы запросить обновленные данные бронирования, а затем данные возвращаются без фиксации ожидаемых изменений ... Я полагаю, что flask обработал все commit () до того, как получит второй запрос, «иначе он бы не вернул результат ранее ...»
Может ли это быть ограничением сервера разработки flask, который не может правильно обрабатывать множество запросов и что при развертывании с помощью Gunicorn этого не происходит?
Любые подсказки или разъяснения по поводу сеансов были бы хороши, потому что это довольно странное поведение, особенно это иногда работает, а другие нет ...
И как запрос ed вот код, я знаю, что его невозможно воспроизвести, у него много настроек и потребуется много данных для работы, как задумано, при тех же обстоятельствах, что и в моем случае, но это должно дать обзор того, как выглядят функции как и где коммиты, о которых я упоминал выше. Любые идеи о том, где может быть проблема, очень полезны.
#Main function hit by the frontend
@users.route('/url_endpoint1', methods=['POST'], strict_slashes=False)
@login_required
def add_room_to_booking_Api():
try:
bookingData = request.get_json()
roomURL=bookingData["roomSafeURL"]
targetBooking = bookingData["bookingURL"]
startDate = bookingData["checkInDate"]
endDate = bookingData["checkOutDate"]
roomPrices=bookingData["roomPrices"]
booking = Bookings.query.filter_by(SafeURL=targetBooking).first()
alojamiento = Alojamientos.query.filter_by(id=reserva.CodigoAlojamiento).first() #owner of the booking
room=Rooms.query.filter_by(SafeURL=roomURL).first()
roomsInBooking=ast.literal_eval(reserva.Habitaciones) #I know, should be json.loads() and json.dumps() for better performance probably...
#if room is available for given days add it to the booking
if CheckIfRoomIsAvailableForBooking(alojamiento.id, room, startDate, endDate, booking) == "OK":
roomsInBooking.append({"id": room.id, "Prices": roomPrices, "Guests":[]}) #add the new room the Rooms column of the booking
booking.Habitaciones = str(roomsInBooking)#save the new rooms data
print(booking.Habitaciones) # check changes applied
room.ReservaAsociada = booking.id # associate booking and room
for ocupante in room.Ocupantes: #associate people in the room with the booking
ocupante.Reserva = reserva.id
#db.session.refresh(reserva) # test I made to check if something changes but didn't worked
if some_X_function() == True: #if user have some functionality enabled
#db.session.begin() #another test which didn't worked
RType = WuBook_Rooms.query.filter_by(ParentType=room.Tipo).first()
RType=[RType] #convert to list because I resuse the function in cases with multiple types
resultAdd = function4(RType, booking.Entrada.replace(hour=0, minute=0, second=0), booking.Salida.replace(hour=0, minute=0, second=0))
if resultAdd["resultado"] == True: # "resultado":error, "casos":casos
return (jsonify({"resultado": "Error", "mensaje": resultAdd["casos"]}))
print(booking.Habitaciones) #here I still get expected result
db.session.commit()
#I get this return of averything correct in my frontend but not really stored in the database
return jsonify({"resultado": "Ok", "mensaje": "Room " + str(room.Identificador) + " added to the booking"})
else:
return (jsonify({"resultado": "Error", "mensaje": "Room " + str(room.Identificador) + " not available to book in target dates"}))
except Exception as e:
#some error handling which is not getting hit now
db.session.rollback()
print(e, ": en linea", lineno())
excepcion = str((''.join(traceback.TracebackException.from_exception(e).format()).replace("\n","</br>"), "</br>Excepcion emitida ne la línea: ", lineno()))
sendExceptionEmail(excepcion, current_user)
return (jsonify({"resultado":"Error","mensaje":"Error"}))
#function from point 4
def function4(RType, startDate, endDate):
delta = endDate - startDate
print(startDate, endDate)
print(delta)
for ind_type in RType:
calendarUpdated=json.loads(ind_type.updated_availability_by_date)
calendarUpdatedBackup=calendarUpdated
casos={}
actualizar=False
error=False
for i in range(delta.days):
day = (startDate + timedelta(days=i))
print(day, i)
diaString=day.strftime("%d-%m-%Y")
if day>=datetime.now() or diaString==datetime.now().strftime("%d-%m-%Y"): #only care about present and future dates
disponibilidadLocal=calendarUpdated[diaString]["local"]
yaReservadas=calendarUpdated[diaString]["local_booked"]
disponiblesChannel=calendarUpdated[diaString]["avail"]
#adjust availability data
if somecondition==True:
actualizar=True
casos.update({diaString:"Happened X"})
else:
actualizar=False
casos.update({diaString:"Happened Y"})
error="Error"
if actualizar==True: #this part of the code is hit normally and changes stored correctly
ind_type.updated_availability_by_date=json.dumps(calendarUpdated)
wubookproperty=WuBook_Properties.query.filter_by(id=ind_type.PropertyCode).first()
wubookproperty.SyncPending=True
ind_type.AvailUpdatePending=True
elif actualizar==False: #some error occured, revert changes
ind_type.updated_availability_by_date = json.dumps(calendarUpdatedBackup)
db.session.commit()#this commit persists
return({"resultado":error, "casos":casos}) #return to main function with all this chnages stored