Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA Spring忽略@Transactional内部的延迟加载_Java_Hibernate_Jpa_Spring Data Jpa_Spring Data - Fatal编程技术网

Java JPA Spring忽略@Transactional内部的延迟加载

Java JPA Spring忽略@Transactional内部的延迟加载,java,hibernate,jpa,spring-data-jpa,spring-data,Java,Hibernate,Jpa,Spring Data Jpa,Spring Data,我有一个spring服务类,通过CRUD加载一个JPA对象(目标)。此目标类具有设置为延迟加载的一对多映射 我想在用@Transactional注释的spring服务方法中查询这个对象,并避免加载child 当我执行以下代码时,所有子数据都被加载,惰性被忽略 @Override @Transactional public boolean changeState(boolean enabled, final EventType eventType,

我有一个spring服务类,通过CRUD加载一个JPA对象(目标)。此目标类具有设置为延迟加载的一对多映射

我想在用
@Transactional
注释的spring服务方法中查询这个对象,并避免加载child

当我执行以下代码时,所有子数据都被加载,惰性被忽略

        @Override
        @Transactional
        public boolean changeState(boolean enabled, final EventType eventType, final String deviceSerialNumber) {
            final UniqueUser user = userService.getUser();
            final Target target = targetRepository.findEventsByUserIdAndTenantIdAndTargetDeviceId(user.getUserId(), user.getTenantId(), deviceSerialNumber);
//here everything gets loaded
            if (target == null) {
                return false;
            }
            final List<EventHistory> events = target.getEvents().stream()
                    .filter(event -> event.getEventType() == eventType)
                    .filter(event -> event.isActive() != enabled)
                    .collect(Collectors.toList());
            events.forEach(event -> event.setActive(enabled));
            if (events.isEmpty()) {
                return false;
            }
            return true;
        }
@覆盖
@交易的
公共布尔更改状态(布尔启用、最终事件类型EventType、最终字符串设备SerialNumber){
final UniqueUser user=userService.getUser();
最终目标Target=targetRepository.findeventsbyuserialandtenantid和targetdeviceid(user.getUserId(),user.getTenantId(),deviceSerialNumber);
//这里什么都装上了
if(target==null){
返回false;
}
最终列表事件=target.getEvents().stream()
.filter(事件->事件.getEventType()==eventType)
.filter(事件->事件.isActive()!=已启用)
.collect(Collectors.toList());
events.forEach(event->event.setActive(enabled));
if(events.isEmpty()){
返回false;
}
返回true;
}
映射:

    @ToString
    @Entity
    @Table(name = "target")
    public class Target {

        @Id
        @GeneratedValue(generator = "uuid")
        @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
        @Column(name = "id", unique = true)
        private UUID id;

        @Column(name = "user_id")
        private String userId;

        @Column(name = "tenant_id")
        private String tenantId;

        @Column(name = "target_device_id")
        private String targetDeviceId;

        @Column(name = "target_type")
        private TargetType targetType;

        @OneToMany(mappedBy = "target", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
        @JsonManagedReference
        private List<EventHistory> events = new ArrayList<>();

        public void addEvents(EventHistory event) {
            events.add(event);
            event.setTarget(this);
        }

    }

    @Entity
    @Data
    @Table(name = "event_history")
    public class EventHistory {

        @Id
        @GeneratedValue(generator = "uuid")
        @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
        @Column(name = "id", unique = true)
        private UUID id;

        @Column(name = "active")
        private boolean active;


        @OneToMany(mappedBy = "event", cascade = CascadeType.ALL, orphanRemoval = true)
        @JsonManagedReference
        private List<EventTimestamp> timestamps = new ArrayList<>();

        @ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
        @JoinColumn(name = "target_id", nullable = false)
        @OnDelete(action = OnDeleteAction.CASCADE)
        @JsonBackReference
        private Target target;

        public void addTimestamps(EventTimestamp eventTimestamp) {
            timestamps.add(eventTimestamp);
            eventTimestamp.setEvent(this);
        }

    }

    @Entity
    @Data
    @Table(name = "event_timestamp")
    public class EventTimestamp {
        @Id
        @GeneratedValue(generator = "uuid")
        @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
        @Column(name = "id", unique = true)
        private UUID id;


        @Column(name = "due_timestamp")
        private Timestamp dueTimestamp;

        @Column(name = "period")
        private String period;

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "event_id", nullable = false)
        @JsonBackReference
        private EventHistory event;
@ToString
@实体
@表(name=“target”)
公共类目标{
@身份证
@GeneratedValue(generator=“uuid”)
@GenericGenerator(name=“uuid”,strategy=“org.hibernate.id.UUIDGenerator”)
@列(name=“id”,unique=true)
私有UUID;
@列(name=“user\u id”)
私有字符串用户标识;
@列(name=“租户id”)
私人字符串租户;
@列(name=“target\u device\u id”)
私有字符串targetDeviceId;
@列(name=“target\u type”)
私有TargetType TargetType;
@OneToMany(mappedBy=“target”,cascade=CascadeType.ALL,orphanRemoving=true,fetch=FetchType.LAZY)
@JsonManagedReference
私有列表事件=新的ArrayList();
公共事件(事件历史事件){
事件。添加(事件);
事件。设置目标(此);
}
}
@实体
@资料
@表(name=“事件历史”)
公共课事件历史{
@身份证
@GeneratedValue(generator=“uuid”)
@GenericGenerator(name=“uuid”,strategy=“org.hibernate.id.UUIDGenerator”)
@列(name=“id”,unique=true)
私有UUID;
@列(name=“active”)
私有布尔活动;
@OneToMany(mappedBy=“event”,cascade=CascadeType.ALL,orphan=true)
@JsonManagedReference
私有列表时间戳=新的ArrayList();
@ManyToOne(可选=false,cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinColumn(name=“target\u id”,null=false)
@OnDelete(action=OnDeleteAction.CASCADE)
@JsonBackReference
私人目标;
public void addtimestamp(EventTimestamp EventTimestamp){
timestamp.add(eventTimestamp);
eventTimestamp.setEvent(此);
}
}
@实体
@资料
@表(name=“事件\时间戳”)
公共类事件时间戳{
@身份证
@GeneratedValue(generator=“uuid”)
@GenericGenerator(name=“uuid”,strategy=“org.hibernate.id.UUIDGenerator”)
@列(name=“id”,unique=true)
私有UUID;
@列(name=“到期日时间戳”)
私有时间戳;
@列(name=“period”)
私有字符串周期;
@manytone(fetch=FetchType.LAZY)
@JoinColumn(name=“event\u id”,nullable=false)
@JsonBackReference
私人事件历史事件;

因此,我的问题是如何在事务注释函数中保持延迟加载?

我找到了答案。问题出在存储库代码中。findBy方法需要的是列表而不是单个对象。 我的原始存储库是这样的

@Repository
public interface TargetRepository extends CrudRepository<Target, UUID> {

  Target findEventsByUserIdAndTenantIdAndTargetDeviceId(String userId, String tenantId, String targetId);

}
@存储库
公共接口TargetRepository扩展了crudepository{
Target findeventsbyuseriandtentId和targetDeviceId(字符串userId、字符串tenantId、字符串targetId);
}
将其更改为以下版本修复了它

@Repository
public interface TargetRepository extends CrudRepository<Target, UUID> {
    List<Target> findEventsByUserIdAndTenantIdAndTargetDeviceId(String userId, String tenantId, String targetId);
}
@存储库
公共接口TargetRepository扩展了crudepository{
列出FindEventsBySeriedTenantId和TargetDeviceId(字符串用户ID、字符串tenantId、字符串targetId);
}

我认为根本原因是错误实现的存储库函数的第一个假设是错误的。真正的问题是@ToString注释。这将一对多事件集合添加到了ToString()。在事务内部并访问对象时,调用了ToString并加载了集合

解决方案是通过将集合从toString中排除

@OneToMany(mappedBy = "target", cascade = CascadeType.ALL, orphanRemoval = true)
@ToString.Exclude
private List<EventHistory> events;
@OneToMany(mappedBy=“target”,cascade=CascadeType.ALL,orphan=true)
@ToString.Exclude
私人列表活动;

你能发布DAO代码吗?通常我认为没有必要将服务类注释为事务性的,特别是当它只调用始终是事务性的DAO时。
findById
首先在持久性缓存中执行查找。只有当它找不到现有实例时,才会点击database.你确定之前没有加载Foo吗?你能验证此操作是否命中数据库吗?你在该服务方法中还做了什么?发布完整的代码密钥问题:你是如何验证集合确实已加载的?我看到正在执行的sql