У меня есть сервлет, который выполняет некоторую работу для пользователя, а затем уменьшает кредит пользователя. Когда я просматриваю кредит пользователя в базе данных в режиме реального времени, если есть много параллельных запросов от одного и того же пользователя, кредит вычитается неправильно из-за контроля параллелизма. T Предположим, что для управления сервером и базой данных используется спящий режим. Я использую управление транзакциями для охвата всего запроса, пожалуйста, см. Код для подробностей. У меня есть несколько вопросов:параллелизм в hibernate
Почему кредитный счетчик в db прыгает повсюду, столкнувшись со многими параллельными запросами одного и того же пользователя? почему мой контроль транзакций не работает?
Если базовые данные были изменены после того, как я получил учетную запись пользователя, а затем попытаюсь ее обновить, почему я не получил
HibernateException(eg.StaleObjectException)
?У меня есть транзакция по полному запросу пользователя, есть ли лучший способ? Пожалуйста, критикуйте. Не стесняйтесь переписывать структуру кода кода, если чувствуете, что я делаю все это неправильно.
Main servlet class: protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try{ Manager.beginTransaction(); cmdDowork(request, response); Manager.commitTransaction(); }catch(Exception exp){ Manager.rollbackTransaction(); exp.printStackTrace(); } finally{ Manager.closeSession(); } } public void cmdDowork(){ try{ UserAccount userAccount = lazyGetUserAccount(request.getParameter("userName")); doWorkForUser(userAccount);//time and resource consuming process if(userAccount!=null) { decUserAccountQuota(userAccount); } }catch (HibernateException e){ e.printStackTrace(); } } public static UserAccount lazyGetUserAccount(String userName) { UserAccount userAccount = Manager.getUserAccount(userName); if(userAccount == null){ userAccount = new UserAccount(userName); userAccount.setReserve(DEFAULT_USER_QUOTA); userAccount.setBalance(DEFAULT_USER_QUOTA); Manager.saveUserAccount(userAccount); } return userAccount; } private boolean decUserAccountQuota(UserAccount userAccount) { if(userAccount.getBalance()Edit: code I used to test optimistic locking as suggested by the answer, I am not getting a any StaleObjectException, the update were committed successfully.. Session em1=Manager.sessionFactory.openSession(); Session em2=Manager.sessionFactory.openSession();
em1.getTransaction().begin(); em2.getTransaction().begin(); UserAccount c1 = (UserAccount)em1.get(UserAccount.class, "jonathan"); UserAccount c2 = (UserAccount)em2.get(UserAccount.class, "jonathan"); c1.setBalance(c1.getBalance() -1); em1.flush(); em1.getTransaction().commit(); System.out.println("balance1 is "+c2.getBalance()); c2.setBalance(c2.getBalance() -1); em2.flush(); // fail em2.getTransaction().commit(); System.out.println("balance2 is "+c2.getBalance());
отличный ответ, чтобы использовать оптимистичную блокировку, поэтому я просто создаю дополнительное поле в таблице и аннотировать его с помощью @version? будет ли спящий режим автоматически генерировать номер версии? – user217631
Это идея, да. «Приложение не должно изменять номер версии, настроенный Hibernate каким-либо образом», из ссылки на hib. аннотаций. – ewernli
Он по-прежнему не работает, версии никогда не превышают 1, даже когда существует много одновременных запросов. и кредит учетной записи пользователя все еще прыгает повсюду. – user217631