2.1.WebSocket没有EntityManager绑定到这个线程



我正在尝试在Play 2.1中实现WebSocket。框架与JPA一起使用Hibernate,当我从WebSocket访问DB时,我得到以下异常:

java.lang.RuntimeException: No EntityManager bound to this thread. Try to annotate your action method with @play.db.jpa.Transactional
at play.db.jpa.JPA.em(JPA.java:42)
at model.operations.DistrictOperations.isOwner(DistrictOperations.java:15)
at controllers.security.Secured.isOwnerOf(Secured.java:28)
at controllers.DistrictCommunication.initWebSocket(DistrictCommunication.java:157)
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$20$$anonfun$apply$20.apply(routes_routing.scala:277)
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$20$$anonfun$apply$20.apply(routes_routing.scala:277)
at play.core.j.JavaWebSocket$$anonfun$webSocketWrapper$1$$anonfun$apply$1.apply(JavaWebSocket.scala:20)
at play.core.j.JavaWebSocket$$anonfun$webSocketWrapper$1$$anonfun$apply$1.apply(JavaWebSocket.scala:14)
at play.core.server.netty.PlayDefaultUpstreamHandler.liftedTree1$1(PlayDefaultUpstreamHandler.scala:324)
at play.core.server.netty.PlayDefaultUpstreamHandler.messageReceived(PlayDefaultUpstreamHandler.scala:322)
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565)
at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:793)
at org.jboss.netty.handler.codec.http.HttpContentDecoder.messageReceived(HttpContentDecoder.java:104)
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565)
at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:793)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296)
at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:455)
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:538)
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:437)
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:560)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:84)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.processSelectedKeys(AbstractNioWorker.java:472)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:333)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:35)
at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:102)
at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:680)
下面是我的代码:
@Transactional(readOnly = true)
public static WebSocket<JsonNode> initWebSocket(final long id) {
    if (Secured.isOwnerOf(id)) {
        return new WebSocket<JsonNode>() {
            // Called when the Websocket Handshake is done.
            public void onReady(WebSocket.In<JsonNode> in,
                    WebSocket.Out<JsonNode> out) {

                // For each event received on the socket,
                in.onMessage(new Callback<JsonNode>() {
                    public void invoke(JsonNode event) {

                        System.out.println(event);
                    }
                });
                // When the socket is closed.
                in.onClose(new Callback0() {
                    public void invoke() {
                        System.out.println("Disconnected");
                    }
                });
                // Send a single 'Hello!' message
                ObjectNode on = Json.newObject();
                on.put("greeting", "hello");
                out.write(on);
            }
        };
    }else{
        return null;
    }

secure isOwnerOf()方法:

public static boolean isOwnerOf(Long district) {
    return DistrictOperations.isOwner(district, Context.current().request().username());
}

和distritoperations . isowner()方法:

@Transactional(readOnly = true)
public static boolean isOwner(long district, String login){
    Query query = JPA.em().createQuery("SELECT d FROM  District d WHERE d.id = :districtId");   
    District d = (District) query.setParameter("districtId", district).getSingleResult();
    return d.getName().equals(login);
}

它建议我添加@事务性注释,我在我的代码,所以我的问题是:是否有可能通过EntityManager从WebSocket访问数据库?因为在我看来,除了EntityManager,其他一切都可以在这里正常工作。

编辑我甚至试图在WebSocket中使用EntityManager,但我仍然有同样的问题。所以也许小的重新制定是我应该如何从WebSocket和JPA使用数据库工作?是否有可能两者同时使用?

提前感谢。

在Play中,WebSocket不是Action@Transactional注释不考虑,因为play.db.jpa.TransactionalAction只截取Action呼叫。

在您的情况下,您必须手动将代码放置在事务中,例如:

boolean isOwnerOf = JPA.withTransaction(new play.libs.F.Function0<Boolean>{
    public Boolean apply() throws Throwable {
        return Secured.isOwnerOf(id);
    }
})

如果你需要在其他websocket的回调中访问DB,你将不得不做同样的事情。这些回调将在其他线程中执行,JPA.withTransaction()将负责将EntityManager绑定到这些线程。

相关内容

  • 没有找到相关文章

最新更新