为后代从电梯邮件列表重新发布(来源在这里):
我可以稍微说明一下我们如何使用 JPA。我不确定您使用的是哪种容器,但我们使用的是 JBoss 4.2.2,并使用它的连接池设施。
我们利用 scalajpa 库来初始化 JPA 的东西,并在线程局部变量中保留对实体管理器的引用。我们特别不使用 Lift 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.
}
最后,我们与 Lift 的集成是以一些代码的形式来包装每个请求:
S.addAround(new LoanWrapper {
def apply[T](f: => T):T = {
try {
f
}
catch {
case e => MyDBModel.getTransaction.setRollbackOnly
}
finally {
MyDBModel.cleanup
}
}
})
我在这里省略了一些错误处理以使想法更清晰,但目的是每个 HTTP 请求都在事务中执行,该事务要么成功,要么全部失败。由于 MyDBModel 在第一次被触摸时被初始化,因此在您的测试代码中,您可以按照您认为合适的方式装配 EM,并且数据对象与此配置隔离。
希望这是有用的。
肖恩