当前位置: 首页 > 知识库问答 >
问题:

Spring Boot中事务管理不起作用

鲁旭
2023-03-14

我有两个实体,即公司和用户。一个公司可以有很多用户。因此,当我保存一个公司时,它也会在一个事务中创建一个用户。如果用户的插入由于某种原因失败了,我想公司的插入应该回滚,这是目前不发生的。

@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"
                        }
                    ]
 }

因此,如果不知何故,在请求中传递的电子邮件已经存在,那么用户实体将不会被保存,所以在这种情况下,我需要公司应该回滚。你知道我怎么才能做到这一点吗?

共有1个答案

朱丰
2023-03-14

有几种方法可以克服这个问题。我将提出一种方法,在表中存在具有相同电子邮件的用户的情况下抛出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配置文件有 但是,当失败时,中的事务不会回滚。如何使回滚工作?