对REST Web服务的同步访问

use*_*385 3 java rest persistence jpa jersey

使用此代码使用简单的REST服务时出现问题:

@GET
@Path("next/{uuid}")
@Produces({"application/xml", "application/json"})
public synchronized Links nextLink(@PathParam("uuid") String uuid) {
    Links link = null;
    try {
        link = super.next();
        if (link != null) {
            link.setStatusCode(5);
            link.setProcessUUID(uuid);
            getEntityManager().flush(); 
            Logger.getLogger("Glassfish Rest Service").log(Level.INFO, "Process {0} request url : {1} #id  {2} at {3} #", new Object[]{uuid, link.getLinkTxt(), link.getLinkID(), Calendar.getInstance().getTimeInMillis()});
        }
    } catch (NoResultException ex) {
    } catch (IllegalArgumentException ex) {
    }
    return link;
}
Run Code Online (Sandbox Code Playgroud)

这应该提供一个链接对象,并将其标记为已使用(setStatusCode(5))以防止下次访问服务以发送相同的对象.问题是,当有很多快速客户端访问Web服务时,这个客户端向不同客户端提供相同链接对象的2到3倍.我怎么能解决这个问题?

这里是resquest使用:@NamedQuery(name ="Links.getNext",query ="SELECT l FROM Links l WHERE l.statusCode = 2")

和super.next()方法:

public T next() {

    javax.persistence.Query q = getEntityManager().createNamedQuery("Links.getNext");
    q.setMaxResults(1);
    T res = (T) q.getSingleResult();
    return res;
}
Run Code Online (Sandbox Code Playgroud)

谢谢

Car*_*ini 5

(根)JAX-RS资源的生命周期是每个请求,因此synchronizednextLink方法上的(否则正确的)关键字可悲地无效.

您需要的是同步访问/更新的意思.这可以通过多种方式完成:

I)您可以在外部对象上进行同步,由框架注入(例如:CDI注入@ApplicationScoped),如下所示:

@ApplicationScoped
public class SyncLink{
    private ReentrantLock lock = new ReentrantLock();
    public Lock getLock(){
       return lock;
    }
}
....
public class MyResource{
  @Inject SyncLink sync;

  @GET
  @Path("next/{uuid}")
  @Produces({"application/xml", "application/json"})
  public Links nextLink(@PathParam("uuid") String uuid) {
    sync.getLock().lock();
    try{
      Links link = null;
      try {
        link = super.next();
        if (link != null) {
            link.setStatusCode(5);
            link.setProcessUUID(uuid);
            getEntityManager().flush(); 
            Logger.getLogger("Glassfish Rest Service").log(Level.INFO, "Process {0} request url : {1} #id  {2} at {3} #", new Object[]{uuid, link.getLinkTxt(), link.getLinkID(), Calendar.getInstance().getTimeInMillis()});
        }
      } catch (NoResultException ex) {
      } catch (IllegalArgumentException ex) {
      }
      return link;
    }finally{
       sync.getLock().unlock();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

II)你可能在课堂上很懒惰并且同步

public class MyResource{
  @Inject SyncLink sync;

  @GET
  @Path("next/{uuid}")
  @Produces({"application/xml", "application/json"})
  public Links nextLink(@PathParam("uuid") String uuid) {
     Links link = null;
    synchronized(MyResource.class){
      try {
        link = super.next();
        if (link != null) {
            link.setStatusCode(5);
            link.setProcessUUID(uuid);
            getEntityManager().flush(); 
            Logger.getLogger("Glassfish Rest Service").log(Level.INFO, "Process {0} request url : {1} #id  {2} at {3} #", new Object[]{uuid, link.getLinkTxt(), link.getLinkID(), Calendar.getInstance().getTimeInMillis()});
        }
      } catch (NoResultException ex) {
      } catch (IllegalArgumentException ex) {
      }

    }
    return link;
  }
}
Run Code Online (Sandbox Code Playgroud)

III)您可以使用数据库进行同步.在这种情况下,您将调查JPA2中可用的悲观锁定.


Jam*_*mes 0

您需要使用某种形式的锁定,最有可能的是乐观版本锁定。这将确保只有一笔交易成功,另一笔交易将失败。

请参阅 http://en.wikibooks.org/wiki/Java_Persistence/Locking