Альтернативные способы обращения с валютой в системе кинотеатра

Моя группа и я создали систему бронирования в кинотеатре для школьного проекта, где предметом был контроль над валютой. Это сделано с помощью C# и Entity Framework в n-уровневой архитектуре, где презентация состояла из проекта MVC.

Мы решили использовать пессимистическую блокировку (IsolationLevel.ReadCommited) во время фазы "выбора мест для бронирования", чтобы база данных была заблокирована, пока кто-то проверяет, есть ли места и когда места добавляются в бронирование. В настоящее время я смотрю, если бы, например, оптимистичный параллелизм мог бы быть вариантом, если так, как это будет работать.

Вот изображение схемы базы данных: Диаграмма над базой данных

Когда вы нажимаете на конкретное шоу, оно автоматически создаст для вас пустое резервирование, а затем создаст экран (кинозал) с его местами и информацией о том, доступны они или нет.

Вот метод для создания списка мест, связанных с экраном (кинозал):

public static List<SeatReservationInfo> GetSeatInfoForShow(Guid reservationId)
        {
            using (EntityContext db = new EntityContext())
            {
                //Retrieve a reservation on its id
                var reservation = db.Reservations.FirstOrDefault(r => r.Id == reservationId);
                //Retrieve the show linked to the reservation
                var show = db.Shows.First(i => i.Id == reservation.ShowId);
                //Used to check if the reservation is expired
                var expired = DateTime.Now.Subtract(new TimeSpan(0, 0, 15, 0));
                //Henter sæder ud tilhørende en specifik sal og laver Seat modellen om til en SeatReservationInfo model
                //Retrieve all seats linked to a specific screen and turn the Seat model into a SeatReservationModel which containt availablity status of the seat
                return
                    db.Seats.Where(s => s.ScreenId == show.ScreenId)
                        .OrderBy(s => s.RowNumber)
                        .ThenBy(s => s.SeatNumber)
                        .Select(s => new SeatReservationInfo
                        {
                            Id = s.Id,
                            Type = s.Type,
                            RowNumber = s.RowNumber,
                            SeatNumber = s.SeatNumber,
                            Availability = s.ReservationSeats.Any(a => a.ReservationId == reservationId)
                                ? SeatAvailability.ReservedSelf
                                : s.ReservationSeats.Any(
                                    a =>
                                        a.Reservation.ShowId == reservation.ShowId &&
                                        (a.Reservation.Status == ReservationStatus.Completed ||
                                         (a.Reservation.Status == ReservationStatus.Started &&
                                          DateTime.Compare(a.Reservation.Created, expired) >= 0)))
                                    ? SeatAvailability.Reserved
                                    : SeatAvailability.Available
                        }).ToList();
            }
        }

С помощью этого метода экран (кинозал) строится с местами в качестве флажков, где вы можете выбрать несколько сидячих мест одновременно. Затем выбранные вами места будут отправлены с помощью bookingId посредством вызова AJAX в метод TryBookSeats, который сначала увидит, пытался ли кто-нибудь зарезервировать ваши места, а если нет, то зарезервировал их, поместив их в таблицу ReservationSeats.

Вот метод TryBookSeats:

public static bool TryBookSeats(List<Guid> seatIds, Guid reservationId)
        {
            //bool who will become true if seats are available
            bool success;
            //Starts a database connection
            using (var db = new EntityContext())
            //Starts a transaction where the isolationlevel is set to ReadCommitted (pessimistic concurrency)
            using (var scope = db.Database.BeginTransaction(IsolationLevel.ReadCommitted))
            {
                //Used to check if the reservation is expired
                var expired = DateTime.Now.Subtract(new TimeSpan(0, 0, 15, 0));
                //Retrieve a reservation that hasnt expired
                var reservation = db.Reservations.First(x => x.Id == reservationId && DateTime.Compare(x.Created, expired) >= 0);
                //Checks if the selected seats are available. if so set success to true
                success = !db.ReservationSeats.Any(
                    i =>
                        i.ReservationId != reservationId && i.Reservation.ShowId == reservation.ShowId &&
                        seatIds.Contains(i.SeatId) &&
                        (i.Reservation.Status == ReservationStatus.Completed ||
                         (i.Reservation.Status == ReservationStatus.Started &&
                          DateTime.Compare(i.Reservation.Created, expired) >= 0)));

                if (success)
                {
                    //Remove last selected seats connected to the current reservation
                    db.ReservationSeats.RemoveRange(db.ReservationSeats.Where(i => i.ReservationId == reservationId));
                    //Add seats to the database
                    foreach (var id in seatIds)
                    {
                        db.ReservationSeats.Add(new ReservationSeat
                        {
                            Id = Guid.NewGuid(),
                            ReservationId = reservationId,
                            SeatId = id
                        });
                    }
                }
                db.SaveChanges();
                scope.Commit();
            }
            return success;
        }

Как вы можете заметить, мы использовали ReadCommited изоляцию уровня, которая, как мы предполагаем, является пессимистичной блокировкой и будет гарантировать отсутствие конфликтов при добавлении мест в ReservationSeats.

И я предполагаю, что мы не встретим никаких тупиков, поскольку мы блокируем только одну таблицу.

Я понимаю, что одним из способов работы оптимистичного конкуррента является то, что перед тем как вы обновите базу данных, вы проверите, была ли база данных изменена с момента извлечения записи. Могли бы мы до того, как добавить места (и bookingId) в таблицу bookingSeats, проверить, были ли они зарезервированы для шоу.

0 ответов

Другие вопросы по тегам