我有两个实体,即公司和用户。一个公司可以有很多用户。因此,当我保存一个公司时,它也会在一个事务中创建一个用户。如果用户的插入由于某种原因失败了,我想公司的插入应该回滚,这是目前不发生的。
@Entity
public class Company {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotNull
@Size(min = 4, max = 100)
private String name;
@Size(max = 500)
private String description;
@OneToMany(mappedBy = "company", cascade = CascadeType.ALL)
@JsonManagedReference
private List<User> users = new ArrayList<>();
public Company() {
}
;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
@Entity
public class User implements UserDetails {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(length = 50, unique = true)
@NotNull
@Size(min = 4, max = 50)
private String username;
@NotNull
@Size(min = 8)
private String password;
@Column(length = 50)
@NotNull
@Size(min = 4, max = 50)
private String firstName;
@Column(length = 50)
@NotNull
@Size(min = 4, max = 50)
private String lastName;
@Column(length = 50, unique = true)
@NotNull
@Size(min = 4, max = 50)
private String email;
private Boolean enabled = true;
@Temporal(TemporalType.TIMESTAMP)
@UpdateTimestamp
private Date lastPasswordReset;
@Column(nullable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
@CreatedDate
private Date createdAt = new Date();
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
@UpdateTimestamp
@LastModifiedDate
private Date updatedAt = new Date();
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(
name = "user_authority",
joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "authority_id", referencedColumnName = "id")})
private List<Authority> roles;
@ManyToOne(optional = false, fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
@JsonBackReference
private Company company;
@Transient
@JsonIgnore
private Collection<? extends GrantedAuthority> authorities;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
/**
* Indicates whether the user's account has expired. An expired account cannot be
* authenticated.
*
* @return <code>true</code> if the user's account is valid (ie non-expired),
* <code>false</code> if no longer valid (ie expired)
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* Indicates whether the user is locked or unlocked. A locked user cannot be
* authenticated.
*
* @return <code>true</code> if the user is not locked, <code>false</code> otherwise
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* Indicates whether the user's credentials (password) has expired. Expired
* credentials prevent authentication.
*
* @return <code>true</code> if the user's credentials are valid (ie non-expired),
* <code>false</code> if no longer valid (ie expired)
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* Indicates whether the user is enabled or disabled. A disabled user cannot be
* authenticated.
*
* @return <code>true</code> if the user is enabled, <code>false</code> otherwise
*/
@Override
public boolean isEnabled() {
return true;
}
public void setUsername(String username) {
this.username = username;
}
/**
* Returns the authorities granted to the user. Cannot return <code>null</code>.
*
* @return the authorities, sorted by natural key (never <code>null</code>)
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
if (this.getRoles() != null) {
return mapToGrantedAuthorities(this.getRoles());
}
return null;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
if (enabled == null) {
enabled = false;
}
this.enabled = enabled;
}
public Date getLastPasswordReset() {
return lastPasswordReset;
}
public void setLastPasswordReset(Date lastPasswordReset) {
if (lastPasswordReset == null) {
lastPasswordReset = new Date();
}
this.lastPasswordReset = lastPasswordReset;
}
public List<Authority> getRoles() {
return roles;
}
public void setRoles(List<Authority> roles) {
this.roles = roles;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
private List<GrantedAuthority> mapToGrantedAuthorities(List<Authority> authorities) {
return authorities.stream()
.map(authority -> new SimpleGrantedAuthority(authority.getName().name()))
.collect(Collectors.toList());
}
}
@Service
public class CompanyService implements ICompanyService {
@Autowired
CompanyRepository companyRepository;
@Autowired
IUserService userService;
@Override
@Transactional
public Company save(Company company) {
try {
userService.initUserFromCompany(company);
return companyRepository.save(company);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
{
"name" : "Evil Corp 2",
"description" : "Bad company",
"users" : [
{
"username" : "rambo",
"password" : "rambo_123",
"firstName" : "Slilvestor",
"lastName" : "Stelon",
"email" : "rambo@rambo.com"
}
]
}
因此,如果不知何故,在请求中传递的电子邮件已经存在,那么用户实体将不会被保存,所以在这种情况下,我需要公司应该回滚。你知道我怎么才能做到这一点吗?
有几种方法可以克服这个问题。我将提出一种方法,在表中存在具有相同电子邮件的用户的情况下抛出RuntimeException。在userService方法(我猜是initUserFromCompany方法)中,如果有的话,抛出RuntimeException。在save方法中,您应该这样做:
@Override
@Transactional(rollbackFor=Exception.class)
public Company save(Company company) {
userService.initUserFromCompany(company);
return companyRepository.save(company);
}
有几个与回滚相关的帖子和答案。您可以看一下这个以获得详细的解释。
我正在使用MongoDB的springboot 2.3.0。注释对我不起作用。如果发生异常,则无法回滚事务。 任何帮助都将得到高度赞赏。 我的控制器类: 我的serviceImpl类 我的MongoConfig类
本文向大家介绍详解SpringBoot的事务管理,包括了详解SpringBoot的事务管理的使用技巧和注意事项,需要的朋友参考一下 Springboot内部提供的事务管理器是根据autoconfigure来进行决定的。 比如当使用jpa的时候,也就是pom中加入了spring-boot-starter-data-jpa这个starter之后。 Springboot会构造一个JpaTransacti
问题出在@Transactional中,在我的配置中spring应用程序没有使用它。我怎么能修好它? ...REST控制器没有任何事务性方法,它只使用specifiedServices加载实体。依赖集合(如果未加载到服务中)应为空。 应用程序启动程序类: 我还尝试将@Transactional添加到存储库接口中,但对我来说并不起作用 所以我从存储库中删除了@Transactional,创建了其他服
该步骤的writer的逻辑非常简单:它尝试从数据库中读取一行,一旦找到该行,就更新该行。我能够通过在find方法之后设置断点来重现,手动为数据库中的行颠簸列并提交它,然后恢复。 但是,在我的步骤中取消注释重试定义后,没有尝试重试。经过一些调试后,Spring重试逻辑似乎在块的事务中;但是由于不是由编写器中的代码引发的,而是由Spring的块事务提交逻辑引发的,因此根本没有尝试重试。 当我试图在编写
Spring对RDBMS事务管理的支持在Spring WebFlux中也起作用吗? 例如,假设配置正确,用注释注释的方法是否会使用Spring事务管理器并在发生错误时回滚事务? 如果事务管理确实起作用,那么方法是否确实和异常,或者或返回类型是否发出错误信号? 我知道JDBC本质上是阻塞的,因此任何JDBC操作都必须从阻塞桥接到反应桥接,反之亦然。 我的组织有WebFlux和Cassandra的经验
我试图用不同的事务管理器嵌套事务,其中如果嵌套的事务失败,外部主事务也需要回滚 我的spring配置文件有 但是,当失败时,中的事务不会回滚。如何使回滚工作?