3.Ebean的事务管理

(1)隐式事务管理

当没有现存的事务时,你仍然执行一个querysavedelete一个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_NEWMANDATORY

SUPPORTSNOT_SUPPORTSNEVER .这些都是和EJB的事务作用域类型相匹配的。

嵌套事务(Nested Transactions)

事务处理方法可以嵌套,像上面的例子一样,runFirst() 调用runInTrans().

隔离级别和特定异常支持(Isolation level and specific exception support)

@ transactional(Spring)支持隔离级别和显式处理异常(是否回滚为特定的例外)

接口

您可以将transactional放在在接口和类,实现这些接口将获得事务性增强的效果。

spacer.gif

(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() {  

       ...  

}  


4begin, commit, rollbackend

这是更传统的方式,通过尝试界定事务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 的集成

提供集成使用EbeanJAX-RS.

特别是它集成了EbeanJSON(而不是XML)数据编组和数据编出支持和提供了一些集成,使它更容易使用实体beanjax - rs

Com.avaje.ebean.jaxrs包需要注册,以便它发现Ebean jax - rsJaxrsJsonProvider。这提供了JSON数据编组和数据编出的实体bean

如果你使用定制媒体类型,那么你可能需要子类并注册它的JaxrsJsonProvider与那些媒体类型。

通常开发人员将继承AbstractEntityResource对象支持许多典型的功能,find by id,find allinsertupdatedeletedelete 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 (取出id34~35顾客。)

:(name,id,contacts(firstName,lastName))  

// fetch customer name, id the customer contacts firstName and lastName(拿到顾客的nameidcontactsfirstNamelastName

:sort(id desc)  

// sort the customers by descending order of their Id values(拿到的记录按照id排列。)


本文原创,已有几处论坛转载。