Будьте в спящем режиме + Swing

В Java всякий раз, когда вы вычисляете два числа, вычисление будет выполняться с использованием более крупного типа. Результатом также будет больший тип. Но для этого не имеет значения, каковы значения этих типов.

Например:

1L + 1L

будет производить long со значением 2.

Но ваш пример:

2147483647 + 1

даст int со значением -2147483648. Поскольку оба int, они останутся int.

Таким образом, чтобы сделать long так, как вы хотите, вы должны:

2147483647 + 1L

получить long со значением 2147483648.

12
задан Tordek 18 May 2009 в 01:09
поделиться

12 ответов

Возможно, сеанс обработки каждого события является правильным подходом. В веб-приложениях мы обычно создаем один сеанс для каждого запроса (используя все эти материалы OpenSessionInView и т. Д.). Если подумать, каждый запрос в веб-приложении - это отдельное взаимодействие в приложении, а в приложении Swing каждое инициированное событие - это отдельное взаимодействие в приложении. Если мы применим те же принципы, которые применяем в веб-приложениях в приложениях Swing, тогда мы должны создать сеанс для каждой обработки события.

Но мы должны определить, является ли использование Hibernate лучшим вариантом ... База данных, к которой вы обращаетесь, является локальной или удаленная база данных? Другие приложения используют одну и ту же базу данных? Вам следует подумать о создании серверной части EJB \ HTTP вместо того, чтобы ваши приложения Swing напрямую обращались к базе данных. Использование Hibernate предполагает, что у вас не такая простая база данных,

6
ответ дан 2 December 2019 в 06:45
поделиться

При закрытии сеанса имейте в виду, что это приведет к отсоединению ваших объектов и потребует дополнительных затрат на повторное присоединение объектов к сеансу, чтобы сохранить или обновить их в базе данных.

При этом я согласен с вами в том, что таскать с собой сеанс не имеет большого смысла, и вы должны освобождать сеанс в конце каждой транзакции. Я бы привел к созданию пула сеансов, из которого каждый поток мог бы обращаться к сеансу по мере необходимости и возвращать его обратно в пул, когда это будет сделано. Вы можете использовать Spring, чтобы помочь вам управлять сессиями для этого.

1
ответ дан 2 December 2019 в 06:45
поделиться

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

1
ответ дан 2 December 2019 в 06:45
поделиться

Я не вижу веских причин, по которым вы хотели бы по-другому работать в приложении с интерфейсом Swing, а затем веб-интерфейсом. В последнем случае обычно создается сеанс для каждого запроса, хотя во многих случаях фактическое создание сеанса выполняется прозрачно (например, Spring).

Если ваше приложение Swing реализует шаблон MVC, то почему бы просто не создать Сеанс в начале каждого метода контроллера и закрыть его в конце. Если ваше приложение является многопоточным, вы можете использовать переменную ThreadLocal , чтобы легко ограничить каждый сеанс определенным потоком. Это почти полностью аналогично тому, что происходит в контейнере сервлета (то есть в веб-приложении).

1
ответ дан 2 December 2019 в 06:45
поделиться

Рекомендации (ваш опыт может отличаться ): Наиболее распространенным шаблоном в многопользовательском клиент-серверном приложении является сеанс на запрос. В этой модели запрос от клиента отправляется на сервер (на котором работает уровень сохраняемости Hibernate), открывается новый сеанс Hibernate, и все операции с базой данных выполняются в этой единице работы. После завершения работы (и подготовки ответа для клиента) сеанс очищается и закрывается. Вы также можете использовать одну транзакцию базы данных для обслуживания запроса клиентов, начиная и фиксируя его, когда вы открываете и закрываете сеанс. Связь между ними однозначна, и эта модель идеально подходит для многих приложений.

см .: http: //docs.jboss. org / hibernate / stable / core / reference / en / html_single / # transaction-basics-uow

1
ответ дан 2 December 2019 в 06:45
поделиться

Я предпочитаю сеанс для обновления модели. Это помогает избежать длительных сеансов, а также помогает минимизировать общее количество созданных сеансов.

0
ответ дан 2 December 2019 в 06:45
поделиться

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

Я склонен разделять свой код на нижнем уровне в класс, который имеет дело с таблицей или каким-либо другим объектом, а затем над ним будет контроллер, который знает, как разговаривать с несколькими дао. Например, чтобы разместить заказ на книгу, вы проверяете, есть ли он на складе, затем обрабатываете платеж, затем уменьшаете позицию и размещаете заказ. Это будет транзакция, охватывающая несколько дао, поэтому они должны использовать один и тот же сеанс.

Но использование одного соединения было бы проблематичным, поскольку вы на некоторое время связываете соединение, и вы можете потерять соединение, предполагая, что это все еще существует. Та же проблема будет усугубляться, если один запрос на экран или страницу.

0
ответ дан 2 December 2019 в 06:45
поделиться

Я использовал Hibernate в полнофункциональном интернет-приложении корпоративного размера, которое по технике во многом напоминает комбинацию гибернации + качели. Я потратил довольно много времени на изучение различных шаблонов проектирования для использования гибернации в трехуровневом приложении.

Hibernate не совсем предназначен для такого рода приложений, поэтому информации по этому поводу было не так много. Я пробовал другие шаблоны проектирования, но большинство из них приводят к утечке памяти, проблемам с подключением и отключением объектов в сеансе (ах), проблемам с транзакциями и т. Д. И т. Д. Окончательным решением было использование шаблона сеанс на запрос. По сути, при каждом запросе, который вы делаете от логики пользовательского интерфейса к бизнес-логике, вы создаете новый сеанс гибернации. Затем ваша бизнес-логика выполняет все, что вы хотите, и прямо перед завершением выполнения бизнес-логики вы сбрасываете и закрываете открытый сеанс. Таким образом не будет утечки памяти, объекты будут правильно присоединяться и открепляться от сессий.

Это не идеальное решение, так как вы столкнетесь с некоторыми проблемами, такими как отложенная загрузка и транзакции. Я кратко объясню эти проблемы и способы их решения.

Транзакции
Because you terminate the hibernate session after each request, you cannot have transactions which live beyond one request. This can be somewhat problematic, for example, let's say you want to store 10 objects within the same transaction. You cannot make a save request separately for each object, as the transaction is terminated. Therefore you need to make a method which takes as input a list of objects and saves all those objects within the same transaction. If the transaction fails, then you rollback all the objects.

Lazy loading
Your objects' lazy loading will not work because they most likely not attached to a session (that is, if you lazy load something once the session has been terminated). For the lazy loading to work, you need to reattach the objects to the session. I came up with a workaround for this as well, which is a bit tricky when creating new entity objects, but works nicely in everyday development. The idea is to have duplicated getters and setters for a field which is lazy loaded. One pair is private and the other one is public. The idea is that the private getter/setter pair is what hibernate uses internally and the public getters and setter are transient and used by the developer. So, what happens is that when the developer calls on the public getter, the getter checks if the field has already been loaded, if not, then attach the object to a session, load the field and close the session. Voilá, everything works and the developer never noticed anything. Here's a small code to give you the idea:


@Entity
public class Foo {
  List<Bar> bars = new ArrayList<Bar>();

  @OneToMany
  private List<Bar> getBarsInternal() {
    return bars;
  }

  private void setBarsInternal(List<Bar> bars) {
    this.bars = bars;
  }

  @Transient
  public List<Bar> getBars() {
     // pseudo code
     if(check if bar is still lazy loaded) {
       // the field is still lazy loaded
       // attach the field to a session an initialize it
       // once the field is initialized, it can be returned
    }
    return getBarsInternal();       
  }

  public void setBars(List<Bar> bars) {
    setBarsInternal(bars);
  }
}
6
ответ дан 2 December 2019 в 06:45
поделиться

Мы начали с одного сеанса для каждого приложения, ниже я перечислил мотивы и проблемы,

Как следует из названия все взаимодействие пользователя с приложением будет состоять из одного длительного сеанса, и все (основное) взаимодействие с базой данных будет происходить через этот сеанс. Ваша «единица работы» теперь будет охватывать все взаимодействие пользователя с приложением… что означает, что ваша «транзакция приложения» - это вся жизнь приложения.

Почему ? 1.

Вышеупомянутые преимущества могут нарисовать радужную картину, но использование длительных сеансов без особого обдумывания может вызвать некоторые серьезные проблемы, которые могут не проявиться до тех пор, пока приложение не станет достаточно большим или сложным.

  1. Ваше приложение может страдать от «раздутого кеша сеанса» ”Феномен ... когда каждое ваше приложение становится все медленнее и медленнее, поскольку кеш сеанса становится все больше и больше, поскольку спящий режим должен проходить через все объекты в кеше сеанса для каждого запроса (с огромным сеансом это может замедлить вас, если сеанс становится большой, на промывку уйдет все больше и больше времени, даже если изменений нет). По сути, преимущество № 3 выше может стать недостатком (из-за спящего режима транзакционной записи), если сеансу разрешено увеличиваться. В некоторых случаях может оказаться полезным обходной путь: использовать query.setReadOnly (true), Возможно, вы захотите взглянуть на пример свинга Кристиана Бауэра, в котором используется этот подход.

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

5
ответ дан 2 December 2019 в 06:45
поделиться

What you want to solve is synchronizing two models: You have the in-memory model and the database model. Just propagating each change into the database, as it happens, is too expensive. Also, you want to be able to handle errors (i.e. roll back your model to a consistent state). To be able to do this, you must have a way to say "now, it's consistent".

The current solution is to start a transaction in the database when the model is known to be consistent (usually before you start making changes) and then do all the changes in your in-memory mode, map them somehow to the database, update the database and then commit the transaction.

While this sounds simple, OO programming actively gets in the way. We hide model operations deep in the call structure, we try really hard for users of a piece of code not to know what the code actually does. In a perfect world, your development tools should unroll all the code an operation needs into a single method/function, wrap that in a transaction and be done with it.

This doesn't work. Instead, we decided to introduce a global variable: the session. Which is bad, and we're ashamed of it, so we try to hide this fact but session is global - per operation. Now you need a way to attach the session to the operation. You can say "all code which gets executed in the current thread is one operation". If you do, the natural solution is to make the session global per thread.

Or you have some token. Then you will attach the session to the token and pass that around.

But the fundamental problem is and always was: How to attach a session to a single operation on the model. The hard parts are to know when an operation starts, when it ends and how to handle errors.

For web applications, using a request is the natural way to define an operation: Everything that happens during a request is considered a single step. The app doesn't really keep the model in memory; everything is forgotten at the end of the request and loaded again from the database when the next request comes in. Slow but manageable.

Desktop application are a completely different kind of beast. They usually keep the whole model in memory all the time. We don't persist changes unless the user asks for it (when she "saves" her work) because that would be too slow and, since there is nothing like a request, there is no simple, automatic way to define an "operation".

The idea to attach an operation to an event is good. Only, in desktop apps, you can have multiple threads which communicate with events and now, you need a way to mark all events as "they belong to the operation started with event X received long ago". Events are usually small, immutable pieces of data, so you can't attach your session to them. But you need some kind of token to mark all events which belong together. Which is why most desktop apps either work with a server (which again works like a web app) and without a big in-memory model or they don't use a database but save their model in a custom format (think Office).

2
ответ дан 2 December 2019 в 06:45
поделиться

Since session creation is expensive in Oracle, and I mostly use Oracle as RDBMS, I'd go for "one single session for the whole application". "One session per event handling" seems ridiculous in the context of a GUI application. There are reasons to do that on the web, but those reasons do usualy not apply for a GUI program.

0
ответ дан 2 December 2019 в 06:45
поделиться

Чего вы действительно хотите избежать, так это сценария сеанса для каждой операции, где для каждой отдельной операции с базой данных создается и закрывается новый сеанс Hibernate.

РЕДАКТИРОВАТЬ: Игнорируйте мою предыдущую чушь о один сеанс на все время существования приложения, это вполне возможно (и, вероятно, наиболее эффективно) сделать это. Просто убедитесь, что вы правильно разграничили свои транзакции - будь то декларативно с использованием чего-то вроде Spring @Transaction или программно.

0
ответ дан 2 December 2019 в 06:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: