JPA正在更新@transactional内部的子实体



我有双向的一对多关系,并尝试在事务方法内部更新子级。我的母公司:

@Entity
@Table(name = "user")
@Getter
@Setter
@EqualsAndHashCode(exclude ={ "subscription","messages","creditCards","privilege"})
@ToString
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull(message = "User name should'not be null")
@Length(min = 5, max = 35)
@Column(name = "full_name", unique = true)
@NaturalId
private String fullName;
@NotNull(message = "User password should'not be null")
@Length(min = 8, max = 16)
private String password;
@Email(message = "Email should be in valid format!")
private String email;
@Column(name = "phone_number",unique = true)
private long phoneNumber;
@Enumerated(EnumType.STRING)
private Role role;
@OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
orphanRemoval = true)
@JoinColumn(name = "subscription_id", referencedColumnName = "id")
private Subscription subscription;
@Enumerated(EnumType.STRING)
private Privilege privilege;
@OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true)
private List <Message> messages;
@OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true)
private List <Card> creditCards;
public User() {
this.creditCards = new ArrayList <>();
this.messages = new ArrayList <>();
}
public User(Long id, String fullName, String password, Long phoneNumber, String email,
Role role, Subscription subscription, Privilege privilege) {
this.id = id;
this.fullName = fullName;
this.password = password;
this.phoneNumber = phoneNumber;
this.email = email;
this.role = role;
this.subscription = subscription;
this.privilege = privilege;
this.messages = new ArrayList <>();
this.creditCards = new ArrayList <>();
}
public void addMessage(Message message) {
messages.add( message );
message.setUser( this );
}
public void removeMessage(Message message) {
messages.remove( message );
message.setUser( null );
}
public void addCreditCard(Card card) {
creditCards.add( card );
card.setUser( this );
}
public void removeCreditCard(Card card) {
creditCards.remove( card );
card.setUser( null );
}
public void setSubscription(Subscription subscription){
if(subscription==null){
if(this.subscription!=null){
this.subscription.setUser( null );
}
}
else {
subscription.setUser( this );
}
this.subscription=subscription;
}
}

我的孩子:

@Entity
@Table(name = "card")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(exclude = {"availableFunds","blockedFunds"})
@ToString  (exclude = "user")
public class Card {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "expiration_date", columnDefinition = "DATE")
private LocalDate expirationDate;
@Column(name = "valid_date", columnDefinition = "DATE")
private LocalDate validFromDate;
@NotNull(message = "credit card shouldn't be null!")
@Column(name = "credit_card_number",unique = true)
private long creditCardNumber;
@Column(name = "available_funds")
private double availableFunds;
@Column(name = "blocked_funds")
private double blockedFunds;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "full_name",
referencedColumnName = "full_name"
)
private User user;
public void addFunds(double amount) {
availableFunds += amount;
}
public void writeOff(double amount) {
if (amount > availableFunds) {
throw new IllegalArgumentException( "Incorrect amount to write-off!" );
}
availableFunds -= amount;
}
public void blockFunds(double amount) {
writeOff( amount );
blockedFunds += amount;
}
public void unBlockFunds(double amount) {
blockedFunds -= amount;
addFunds( amount );
}
}

服务层中失败的方法:

@TransactionalEventListener
@Transactional(readOnly = false)  
public void onOrderCreatedEvent(OrderCreatedEvent event)
{
User retrieved = userDao.findByUserName( event.getOrderDto().getUserDto().getFullName() );

Card card = retrieved.getCreditCard();
log.debug("lots of info about cards balance" );

card.blockFunds( Double.parseDouble( event.getOrderDto().getBlockedFunds() ) );

/*userDao.update( retrieved ); --not working*/

log.debug("lots of info about cards balance" );

}

所以,它按预期进行,捕捉已发布的事件,按其编号获取Card,阻止资金,但DB中没有任何变化:

2020-12-01 19:29:53 DEBUG UserService:150 - Card retrieved: 1
card's available funds: 2000.0
2020-12-01 19:29:53 DEBUG UserService:157 - Card retrieved: 1
card's available funds: 2100.0

没有Hibernate的更新日志,也没有mysql中的新数据。陷阱在哪里?

因此,就Spring的@transactional是一个臭名昭著的陷阱而言,我没有在服务方法中检查新事务的需求。据我所知,由于第一笔交易已关闭

User retrieved = userDao.findByUserName

在检索实体之后,我必须启动新的实体来实现实体管理器并合并所有更改。所以,在添加之后

传播=传播.REQUIRES_NEW

JPA开始存储子级的状态。

最新更新