Повторно из списка рассылки Lift для потомков (source here):
я могу пролить немного света на то, как мы используем JPA. Я не уверен, какой контейнер вы используете, но мы используем JBoss 4.2.2 и , используя средства пула соединений.
Мы используем библиотеку scalajpa для инициализации материала JPA и сохраняем ссылку на диспетчер сущности в локальной переменной потока. Мы специально не используем Request RequestVarEM, потому что жизненный цикл RequestVar несколько сложнее обычного HTTP-запроса, , и это может привести к тому, что соединения не будут возвращены в пул в своевременно.
Первый шаг заключается в создании «модели», и направьте его на имя блока из вашего persistence.xml:
object MyDBModel extends LocalEMF("unitName", false) with
ThreadLocalEM
И мы создали немного кода, чтобы сделать некоторые операции просто. Каждый из наших постоянных классов смесей в том, что обеспечивает некоторые основные JPA операции:
trait Persistent {
def persist = DBModel.persist(this)
def merge = DBModel.merge(this)
def remove = DBModel.remove(this)
}
Например,
@Entity
@Table{val name="person"}
class Person extends Persistent {
@Id
var id:String = _
@Column {val name="first_name", val nullable = false, val
updatable=false}
var firstName:String = _
@Column {val name="last_name", val nullable = false, val
updatable=false}
var lastName:String = _
@OneToMany{ ... }
var roles:Set[Role] = new HashSet[Role]()
// etc.
}
Мы в первую очередь использовать отображенные коллекции для навигации по объектной модели, и положить больше сложные методы базы данных на сопутствующем объекте, так что у нас нет ссылок на MyDBModel, разбросанных по всему коду (как вы отметили, нежелательная практика).Например:
object Person {
def findByLastName = MyDBModel.createQuery[Person]
("...").findAll.toList
// etc.
}
Наконец, наша интеграция с Лифтом в виде фрагмента кода, который компрессы каждый запрос:
S.addAround(new LoanWrapper {
def apply[T](f: => T):T = {
try {
f
}
catch {
case e => MyDBModel.getTransaction.setRollbackOnly
}
finally {
MyDBModel.cleanup
}
}
})
Я оставил некоторую обработку ошибок здесь, чтобы сделать Идея понятна, но состоит в том, что каждый HTTP-запрос выполняется в транзакции, которая либо преуспевает, либо полностью отказывается. Поскольку MyDBModel инициализируется при первом касании, в вашем тестовом коде вы можете установить EM, как вы сочтете нужным, и объекты данных изолированы от этой конфигурации .
Надеюсь, это полезно.
Шон
Как вы проверить код, который зависит так сильно от глобальных переменных (например, 'MyDBModel' в вашем примере). Не сложно ли обойтись без использования всего стека? – Theo