Java JPA Spring忽略@Transactional内部的延迟加载
我有一个spring服务类,通过CRUD加载一个JPA对象(目标)。此目标类具有设置为延迟加载的一对多映射 我想在用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,
@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