JPA懒加载异常求助:无法初始化代理-无Session问题
解决Hibernate懒加载导致的JSON序列化异常问题
问题描述
从数据库对象检索列表时,仅在调用mapper.writeValueAsString(pieces)将棋子序列化为JSON发送给前端时,触发failed to lazily initialize a collection of role could not initialize proxy - no Session错误,其他场景运行正常。
相关代码
事件处理方法
@Transactional private DataListener<String> onGetPieceInfoEvent() { return (senderClient, data, ack) -> { ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(data); String roomId = jsonNode.get("roomId").textValue(); String color = jsonNode.get("color").textValue(); Game game = this.gameService.findByRoomId(roomId); List<Piece> pieces = color.equals("white") ? game.getWhitePieces() : game.getBlackPieces(); Collection<SocketIOClient> clientsCollection = this.server.getRoomOperations(roomId).getClients(); ArrayList<SocketIOClient> clients = new ArrayList<>(clientsCollection); SocketIOClient client = clients.get(0).getSessionId().equals(senderClient.getSessionId()) ? clients.get(1) : clients.get(0); socketService.sendMessage(roomId, "colorOnMount", mapper.writeValueAsString(pieces), client); }; }
Game实体类
@Entity @Table(name="game_data") public class Game { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="game_id") private Integer gameId; @Column(name="room",nullable = false) private String roomId; GameState state; @ElementCollection @ColumnDefault("[]") @CollectionTable(name = "white_pieces", joinColumns = @JoinColumn(name = "game_id")) @Basic(fetch = FetchType.EAGER) private List<Piece> whitePieces = new ArrayList<>(); @ElementCollection @ColumnDefault("[]") @CollectionTable(name = "black_pieces", joinColumns = @JoinColumn(name = "game_id")) @Basic(fetch = FetchType.EAGER) private List<Piece> blackPieces = new ArrayList<>(); }
Piece实体类
@Embeddable @JsonIgnoreProperties(ignoreUnknown = true) public class Piece { @JsonProperty("image") @Column private String image; @JsonProperty("x") @Column private Integer x; @JsonProperty("y") @Column private Integer y; @JsonProperty("type") @Column private String type; @JsonProperty("team") @Column private String team; @JsonProperty("enPassant") @Column private Boolean enPassant; }
解决方案
确保事务与Session覆盖序列化操作
异步回调场景下,@Transactional可能无法有效维持Session到序列化阶段。在gameService.findByRoomId方法内提前初始化集合:// 在GameService实现中修改findByRoomId方法 public Game findByRoomId(String roomId) { Game game = entityManager.createQuery("SELECT g FROM Game g WHERE g.roomId = :roomId", Game.class) .setParameter("roomId", roomId) .getSingleResult(); // 强制初始化集合,确保Session未关闭时加载数据 Hibernate.initialize(game.getWhitePieces()); Hibernate.initialize(game.getBlackPieces()); return game; }修正集合加载策略配置
集合类型的加载策略应直接在@ElementCollection上指定,而非@Basic注解:@ElementCollection(fetch = FetchType.EAGER) @ColumnDefault("[]") @CollectionTable(name = "white_pieces", joinColumns = @JoinColumn(name = "game_id")) private List<Piece> whitePieces = new ArrayList<>(); @ElementCollection(fetch = FetchType.EAGER) @ColumnDefault("[]") @CollectionTable(name = "black_pieces", joinColumns = @JoinColumn(name = "game_id")) private List<Piece> blackPieces = new ArrayList<>();使用DTO转换隔离实体与前端数据
创建与前端需求匹配的DTO类,避免直接序列化Hibernate实体:public class PieceDTO { private String image; private Integer x; private Integer y; private String type; private String team; private Boolean enPassant; public PieceDTO(Piece piece) { this.image = piece.getImage(); this.x = piece.getX(); this.y = piece.getY(); this.type = piece.getType(); this.team = piece.getTeam(); this.enPassant = piece.getEnPassant(); } // 生成getter方法 }在业务逻辑中完成转换后再序列化:
List<PieceDTO> pieceDTOs = pieces.stream().map(PieceDTO::new).collect(Collectors.toList()); socketService.sendMessage(roomId, "colorOnMount", mapper.writeValueAsString(pieceDTOs), client);配置Jackson兼容Hibernate懒加载
添加Jackson的Hibernate模块依赖,自动处理代理对象:<!-- Maven依赖 --> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-hibernate5</artifactId> </dependency>初始化ObjectMapper时注册该模块:
ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new Hibernate5Module());
内容的提问来源于stack exchange,提问作者Ankit Kumar
相关产品推荐
相关产品推荐

