我想在我的專案中測驗事務操作。userService.saveUser()基本上,如果拋出例外,我想回滾操作。我已經簡化了這些類,你可以在下面找到它。
用戶必須住在一個地址中。一個地址可以有多個用戶。
地址物體
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Address {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "STREET")
@NotNull
private String street;
@ToString.Exclude
@OneToMany(mappedBy = "address")
private Set<User> users = new HashSet<>();
}
用戶物體
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "USER")
public class User {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "FIRSTNAME", nullable = false)
@NotNull
private String firstName;
@ManyToOne(fetch = FetchType.LAZY)
private Address address;
}
存盤庫
public interface AddressRepository extends CrudRepository<Address, Long> {
}
public interface UserRepository extends CrudRepository<User, Long> {
}
用戶服務類
@Service
@Slf4j
@AllArgsConstructor
public class UserService {
@Autowired
AddressRepository addressRepository;
@Autowired
UserRepository userRepository;
@Transactional
public void saveUser(String firstName, String street) {
var address1 = Address.builder.street(street).build();
// to make sure that I have "id" of the address when I am saving it.
var addressSaved = addressRepository.save(address1);
if ("f1".equals(firstName))
throw new RuntimeException("some exception");
var user = User.builder()
.firstName(firstName)
.address(addressSaved)
.build();
// this operation can also throw DataIntegrityViolationException
userRepository.save(user);
}
}
這是我的測驗課
@SpringBootTest
class UserServiceIT {
@Autowired
AddressRepository addressRepository;
@Autowired
UserRepository userRepository;
@Autowired
UserService userService;
@BeforeEach
void beforeEach() {
userRepository.deleteAll();
addressRepository.deleteAll();
}
@Test
void test_saveUser() {
assertThrows(RuntimeException.class,() -> userService.saveUser("f1", "s1"));
assertEquals(0, userRepository.count());
assertEquals(0, addressRepository.count());
}
@Test
void test_saveUser2() {
// column: nullable = false will throw the exception
assertThrows(DataIntegrityViolationException.class,() -> userService.saveUser(null, "s1"));
assertEquals(0, userRepository.count());
assertEquals(0, addressRepository.count());
}
}
這兩個測驗都給出了地址計數的斷言錯誤(地址已保存但用戶未保存)。我希望地址被回滾(而不是被保存),因為在保存地址后出現錯誤,并且在保存用戶時(違反了某些條件,因此必須回滾 2 次保存)。我究竟做錯了什么?
application.yml用于測驗環境
spring:
devtools:
restart:
enabled: false
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=false
driverClassName: org.h2.Driver
username: sa
password: 123
h2:
console:
enabled: false
jpa:
database-platform: org.hibernate.dialect.H2Dialect
database: H2
show-sql: false
hibernate:
ddl-auto: create
You can reach the whole sample project from this link: https://wetransfer.com/downloads/7cb870266e2e20f610b44d3cc9f229c220220308071438/7b88a2700076a3e53771e389c796cfe420220308071438/c777ab
uj5u.com熱心網友回復:
您在此處發布的代碼與您上傳的原始代碼中實際存在的代碼不同。
原始代碼:
@Transactional
void saveUser(String firstName, String street) {
var address = Address.builder().street(street).build();
var addressSaved = addressRepository.save(address);
if ("f1".equals(firstName))
throw new RuntimeException("f1");
var user = Person.builder()
.firstName(firstName)
.address(addressSaved)
.build();
personRepository.save(user);
}
此方法實際上具有默認訪問修飾符,因此GCLIB無法覆寫它并創建所需的邏輯。將此方法的訪問修飾符更改為public
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/441651.html
