【问题标题】:Play 2.1. WebSocket No EntityManager bound to this thread玩 2.1。 WebSocket 没有 EntityManager 绑定到这个线程
【发布时间】:2013-05-10 13:40:05
【问题描述】:

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

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;
    }

安全的 isOwnerOf() 方法:

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

和 DistrictOperations.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);
}

建议我在代码中添加 @Transactional 注释,所以我的问题是:是否可以通过 WebSocket 的 EntityManager 访问数据库?因为在我看来,除了 EntityManager 之外的其他一切都可以正常工作。

编辑 我什至尝试在 WebSocket 中使用 EntityManager,但我仍然遇到同样的问题。所以也许小的重新制定是我应该如何使用来自 WebSocket 和 JPA 的数据库?是否可以同时使用两者?

提前谢谢你。

【问题讨论】:

    标签: java hibernate websocket playframework-2.0 playframework-2.1


    【解决方案1】:

    在 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 的回调中访问数据库,您也必须这样做。这些回调将在其他线程中执行,JPA.withTransaction() 将负责将 EntityManager 绑定到这些线程。

    【讨论】:

    • 如果我在控制器的方法中编写不同的线程,这是否适用?因为我在创建新线程以加快进程时遇到了同样的异常。例外是“java.lang.RuntimeException: No EntityManager bound to this thread。尝试将此调用包装在 JPAApi.withTransaction 中,或确保 tpi.withTransaction,”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    • 1970-01-01
    • 2019-01-27
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    相关资源
    最近更新 更多