Java LazyInitializationException与Spring消息传递和GsonMessageConverter

Java LazyInitializationException与Spring消息传递和GsonMessageConverter,java,spring,spring-session,spring-messaging,Java,Spring,Spring Session,Spring Messaging,我正在使用Spring Boot和Spring消息传递和Gson进行websocket连接并向客户端发送消息。现在,在向模型中添加新字段并将其发送到客户端之后,我面临着LazyInitializationException错误 这是我的模型课: @Entity public class Vehicle { @Expose @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id;

我正在使用
Spring Boot
Spring消息传递
Gson
进行websocket连接并向客户端发送消息。现在,在向模型中添加新字段并将其发送到客户端之后,我面临着
LazyInitializationException
错误

这是我的模型课:

@Entity
public class Vehicle {
    @Expose
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Expose
    private String name;

    //...
    //some other simple fields
    //...

    @Expose
    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "vehicle_property_values", joinColumns = @JoinColumn(name = "vehicle_id"))
    @MapKeyColumn(name = "key")
    @Column(name="value")
    private Map<String, String> properties = new HashMap<>();
}
GsonMessageConverter

this.gson.toJson(payload, writer);
以下是我在服务类中发送消息的方式:

@Service
@Transactional
class VehicleServiceImpl implements VehicleService {
    @Autowired
    VehicleRepository vehicleRepository; //JpaRepository
    @Autowired
    SimpMessagingTemplate simpMessagingTemplate;

    private final ConcurrentLinkedDeque<Vehicle> pendingVehicles = new ConcurrentLinkedDeque<>(); 

    //..some other fields and methods irrelevant in this case

    //method called from controller
    @Override
    void addPendingVehicle(Vehicle vehicle) {
        //set some variables in vehicle
        vehicle = vehicleRepository.save(vehicle);
        pendingVehicles.add(vehicle);
    }

    @Scheduled(initialDelay = 60000, fixedRate = 60000)
    @Transactional
    void sendPendingVehicles() {
        if(pendingVehicles.size() > 0) {
            simpMessagingTemplate.convertAndSend("/topic/vehicles", pendingVehicles);
            pendingVehicles.clear();
        }
    }
}
@服务
@交易的
类VehicleServiceImpl实现VehicleService{
@自动连线
车辆存储车辆存储;//j存储
@自动连线
SimpMessageTemplate SimpMessageTemplate;
私有最终ConcurrentLinkedQue pendingVehicles=新ConcurrentLinkedQue();
//…其他一些与本案例无关的领域和方法
//从控制器调用的方法
@凌驾
无效添加挂起车辆(车辆){
//在车辆中设置一些变量
车辆=车辆存储。保存(车辆);
挂起车辆。添加(车辆);
}
@计划(初始延迟=60000,固定延迟=60000)
@交易的
无效发送待定车辆(){
如果(悬挂车辆.size()>0){
SimpMessageTemplate.convertAndSend(“/topic/vehicles”,pendingVehicles);
悬挂车辆。清除();
}
}
}
以下是我的WebSocket配置(仅限于非空方法):

@配置
@EnableWebSocketMessageBroker
公共类WebSocketConfig实现WebSocketMessageBrokerConfiger{
@凌驾
public void配置MessageBroker(MessageBrokerRegistry配置){
config.enableSimpleBroker(“/queue”,“/topic”);
}
@凌驾
公共无效注册表TompendPoints(StompEndpointRegistry注册表){
registry.addEndpoint(“/testapp”).setAllowedOrigins(“*”).withSockJS();
}
@凌驾
公共布尔配置消息转换器(列表转换器){
Gson Gson=new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
添加(新的GsonMessageConverter().setGson(gson));
返回true;
}
}

我不知道如何修理它。如何使其具有事务性?

我不需要在websocket消息中发送属性,所以我创建了注释

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcludeWebSocketSerialization { }
并将
排除策略
添加到我的
Gson

.addSerializationExclusionStrategy(new ExclusionStrategy() {
    @Override
    public boolean shouldSkipField(FieldAttributes fieldAttributes) {
    return fieldAttributes.getAnnotation(ExcludeWebSocketSerialization.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> aClass) {
    return false;
    }
})
.addSerializationExclutionStrategy(新的ExclutionStrategy()){
@凌驾
公共布尔值shouldSkipField(FieldAttributes FieldAttributes){
返回fieldAttributes.getAnnotation(ExcludeWebSocketSerialization.class)!=null;
}
@凌驾
公共布尔值shouldSkipClass(类aClass){
返回false;
}
})

我不需要在websocket消息中发送属性,所以我创建了注释

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcludeWebSocketSerialization { }
并将
排除策略
添加到我的
Gson

.addSerializationExclusionStrategy(new ExclusionStrategy() {
    @Override
    public boolean shouldSkipField(FieldAttributes fieldAttributes) {
    return fieldAttributes.getAnnotation(ExcludeWebSocketSerialization.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> aClass) {
    return false;
    }
})
.addSerializationExclutionStrategy(新的ExclutionStrategy()){
@凌驾
公共布尔值shouldSkipField(FieldAttributes FieldAttributes){
返回fieldAttributes.getAnnotation(ExcludeWebSocketSerialization.class)!=null;
}
@凌驾
公共布尔值shouldSkipClass(类aClass){
返回false;
}
})

车辆对象如何到达您的队列?你能分享这段代码吗?@Leffchik我在我的
@Service
中又添加了一些代码。你将东西添加到队列中(从事务x开始),然后在事务y中尝试发送它。事务x不再存在(因此相应的实体管理器也不存在),这就是为什么会出现此错误。要修复此问题,请在将惰性集合添加到队列之前读取该集合,或者使该集合成为非惰性集合,或者如果它不需要序列化,请从序列化中忽略它
@JsonIgnore
@M.Deinum我尝试在
pendingVehicles.add(vehicle)
之前添加
vehicle.getProperties()
,但错误相同。如何使收集不懒惰?准确地说,在websocket消息中,我不需要发送
属性
,但在其他情况下(例如,获取所有车辆的端点),我需要它,因此当我添加排除时,它将在任何序列化中工作。您只需将
@ElementCollection(fetch=FetchType.EAGER)
放在
属性
字段中,使其非惰性。它可能会导致一些性能问题,比如
车辆
对象如何到达您的队列?你能分享这段代码吗?@Leffchik我在我的
@Service
中又添加了一些代码。你将东西添加到队列中(从事务x开始),然后在事务y中尝试发送它。事务x不再存在(因此相应的实体管理器也不存在),这就是为什么会出现此错误。要修复此问题,请在将惰性集合添加到队列之前读取该集合,或者使该集合成为非惰性集合,或者如果它不需要序列化,请从序列化中忽略它
@JsonIgnore
@M.Deinum我尝试在
pendingVehicles.add(vehicle)
之前添加
vehicle.getProperties()
,但错误相同。如何使收集不懒惰?准确地说,在websocket消息中,我不需要发送
属性
,但在其他情况下(例如,获取所有车辆的端点),我需要它,因此当我添加排除时,它将在任何序列化中工作。您只需将
@ElementCollection(fetch=FetchType.EAGER)
放在
属性
字段中,使其非惰性。但这可能会导致一些性能问题