zik*_*y90 4 java hibernate websocket playframework-2.0 playframework-2.1
我正在尝试在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)
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
@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;
}
Run Code Online (Sandbox Code Playgroud)
secure isOwnerOf()方法:
public static boolean isOwnerOf(Long district) {
return DistrictOperations.isOwner(district, Context.current().request().username());
}
Run Code Online (Sandbox Code Playgroud)
和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);
}
Run Code Online (Sandbox Code Playgroud)
它建议我在我的代码中添加@Transactional注释,所以我的问题是:是否有可能从WebSocket通过EntityManager访问数据库?因为在我看来,除了EntityManager之外的其他一切工作正常.
编辑 我甚至尝试在WebSocket中使用EntityManager,但我仍然有同样的问题.所以也许小的重构是我应该如何使用WebSocket和JPA使用数据库?以某种方式可以同时使用它们吗?
先感谢您.
在Play中,a 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);
}
})
Run Code Online (Sandbox Code Playgroud)
如果您需要在其他websocket的回调中访问数据库,则必须执行相同的操作.这些回调将在其他线程中执行,并将负责JPA.withTransaction()将EntityManager绑定到这些线程.
| 归档时间: |
|
| 查看次数: |
2787 次 |
| 最近记录: |