3.Ebean的事务管理
(1)隐式事务管理
当没有现存的事务时,你仍然执行一个query、save、delete一个bean
当这种情况发生时Ebean将创建一个隐式的事务和提交或回滚(如果有一个失败)
// execute a query without an existing transaction...
// ... a "implicit" transaction will be created
// ... and be commited (or rolled back) for you
List<User> users = Ebean.find(User.class).join("customer") .where().eq("state", UserState.ACTIVE).findList();
// execute a save without an existing transaction...
// ... will create an implicit transaction(隐式事务)
// ... and be commited (or rolled back) for you
Ebean.save(user);
(2)@Transactional
Ebean可以增强你的pojo添加事务支持。这样做将@Transaction注释方法或类。Ebean增强将添加支持事务逻辑((begin transaction, commit, rollback, suspend and resuming transactions 等)。
...
// any old pojo
public class MyService {
@Transactional
public void runFirst() throws IOException {
// run in a Transaction (REQUIRED is the default)
// find a customer
Customer customer = Ebean.find(Customer.class, 1);
// call another "transactional" method
runInTrans();
}
@Transactional(type=TxType.REQUIRES_NEW)
public void runInTrans() throws IOException {
// run in its own NEW transaction
// ... suspend an existing transaction if required
// ... and resume it when this method ends
// find new orders
...
List<Order> orders = Ebean.find(Order.class) .where().eq("status",OrderStatus.NEW).findList();
...
将@ Transactional注释在你的方法和Ebean可以增强类添加事务管理。
标准事务作用域类型
支持标准的传播规则 REQUIRED(默认的)、REQUIRES_NEW、MANDATORY
、SUPPORTS、NOT_SUPPORTS、NEVER .这些都是和EJB的事务作用域类型相匹配的。
嵌套事务(Nested Transactions)
事务处理方法可以嵌套,像上面的例子一样,runFirst() 调用runInTrans().
隔离级别和特定异常支持(Isolation level and specific exception support)
@ transactional(如Spring)支持隔离级别和显式处理异常(是否回滚为特定的例外)。
接口
您可以将transactional放在在接口和类,实现这些接口将获得事务性增强的效果。
(3)TxRunnable & TxCallable
TxRunnable & TxCallable和@Transactional作用上是等价的。如果喜欢的话,也可以将两种写法混合起来使用,它们有很好的兼容性。
public void myMethod() {
...
System.out.println(" Some code in myMethod...");
// run in Transactional scope...
Ebean.execute(new TxRunnable() {
public void run() {
// code running in "REQUIRED" transactional scope
// ... as "REQUIRED" is the default TxType
System.out.println(Ebean.currentTransaction());
// find stuff...
User user = Ebean.find(User.class, 1);
...
// save and delete stuff...
Ebean.save(user);
Ebean.delete(order);
...
}
});
System.out.println(" more code in myMethod...");
}
通常您将使用TxRunnable像上述匿名内部类。
在run()方法里的代码将执行一个Ebean为你控制的事务传播的事务性范围。(就像@Transactional)
// programmatic control over the scope such as
// ... isolation level
// ... and to rollback or not for specific exceptions
TxScope txScope = TxScope
.requiresNew()
.setIsolation(TxIsolation.SERIALIZABLE)
.setNoRollbackFor(IOException.class);
Ebean.execute(txScope, new TxRunnable() {
public void run() {
...
}
(4)begin, commit, rollback,end
这是更传统的方式,通过尝试界定事务finally块。
Ebean.beginTransaction();
try {
// fetch some stuff...
User u = Ebean.find(User.class, 1);
...
// save or delete stuff...
Ebean.save(u);
...
Ebean.commitTransaction();
} finally {
Ebean.endTransaction();
}
注:上面的代码通常会使用ThreadLocal保持事务开始、提交和结束事务(如果需要的话,最终将执行rollback)。
Ebean.endTransaction()将检查是否已提交的事务,如果是,那么它什么都不做,否则它将回滚该事务。它通常总是在最后。
4.JAX-RS 的集成
提供集成使用Ebean和JAX-RS.
特别是它集成了Ebean的JSON(而不是XML还)数据编组和数据编出支持和提供了一些集成,使它更容易使用实体bean与jax - rs。
Com.avaje.ebean.jaxrs包需要注册,以便它发现Ebean jax - rs的JaxrsJsonProvider。这提供了JSON数据编组和数据编出的实体bean。
如果你使用定制媒体类型,那么你可能需要子类并注册它的JaxrsJsonProvider与那些媒体类型。
通常开发人员将继承AbstractEntityResource对象来支持许多典型的功能,如:find by id,find all、insert、update、delete和delete many by ids。
...
// Extend AbstractEntityResource to get:
// Insert, Update, Delete, Delete Many, Find by Id and Find all
//
// Use uriOptions to allow client to customise exactly
// the properties to fetch and render (rather than get
// the server to provide more API).
//
@Path("/customer{uriOptions:(:[^/]+?)?}/")
@Produces({MediaType.APPLICATION_JSON, "text/json"})
public class CustomerJsonResource extends AbstractEntityResource {
public CustomerJsonResource() {
super(Customer.class);
}
}
AbstractEntityResource 的源码
AbstractEntityResource提供了上述方法的实现,它使用定义了的UriOptions。
/**
* Insert a bean.
*
* @param bean
* the bean to insert
*/
@POST
public Response insert(@Context UriInfo uriInfo, T bean) {
/**
* Update a bean.
*
* @param id
*the unique id of the bean
* @param bean
* the bean to update
*/
@PUT
@Path("/{id}")
public void update(@PathParam("id") String id, T bean) {
/**
* Delete multiple beans using Id's from the "UriOptions".
*
* @param options
* The UriOptions in the form "::(id1,id2,...)"
*/
@DELETE
public void deleteMultiple(@PathParam("uriOptions") String options) {
/**
* Delete a bean using its id.
*
* @param id
* the unique id of the bean.
*/
@DELETE
@Path("/{id}")
public void delete(@PathParam("id") String id) {
/**
* Find a bean given its Id.
*
* @param id
* the id of the bean.
*/
@GET
@Path("/{id}")
public T find(@PathParam("id") String id, @PathParam("uriOptions") String uriOptions) {
/**
* Find all the beans for this beanType.
* <p>
* This can use URL query parameters such as order and maxrows to configure
* the query.
* <p>
*/
@GET
public List<T> findAll(@Context UriInfo ui, @PathParam("uriOptions") String uriOptions){
什么是UriOptions
用于解析一个字符串(通常从一个URL的一部分)到PathProperties,列表的Id和排序条款,然后可以应用到JSON / XML封送和ORM查询优化构建和渲染的一个对象图的一部分。
UriOptions的灵感来自于JavaOne表示从LinkedIn在构建高性能的restful api的。
UriOptions提供给调用者权限,使得可以指定他们需要的属性,这使服务器实现能够优化编组,和使得ORM查询没有额外的服务器的API。
UriOptions包括三个片段需要去指定:
(1)取出或删除 Id的集合。
(2)属性的获取(也可以被内嵌)。
(3)一个sort子句。
例如:
Example URL:
.../v1/customer::(34,35):(name,id,contacts(firstName,lastName)):sort(id desc)
其中的三个片段是:
::(34,35)
// fetch customer 34 and 35 (取出id从34~35的顾客。)
:(name,id,contacts(firstName,lastName))
// fetch customer name, id the customer contacts firstName and lastName(拿到顾客的name、id、contacts的firstName和lastName。)
:sort(id desc)
// sort the customers by descending order of their Id values(拿到的记录按照id排列。)
本文原创,已有几处论坛转载。