下午好,
使用 Spring Boot + JPA + Hibernate,我在尝试删除仍被另一个实体引用的实体时预计会出现异常(违反我的 FK 约束)。我正在使用CRUDRepository,我希望能够从删除或deleteById调用中捕获DataIntegrityViolationException。
但是,没有任何反应,日志仅显示选择查询:
Hibernate: select jpauserpas0_.id as id1_4_0_, jpauserpas0_.cdate as cdate2_4_0_, jpauserpas0_.password as password3_4_0_, jpauser1_.id as id1_3_1_, jpauser1_.cdate as cdate2_3_1_, jpauser1_.pid as pid4_3_1_, jpauser1_.username as username3_3_1_ from user_password jpauserpas0_ left outer join "user" jpauser1_ on jpauserpas0_.id=jpauser1_.pid where jpauserpas0_.id=?
有人知道为什么会这样吗?这是正常行为吗?
型:
public class JPAUser
{
@Id
@GeneratedValue(generator = "genuser", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "genuser", sequenceName = "user_id_seq", allocationSize=1)
public Integer id;
@Column(unique = true)
public String username;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "pid")
public JPAUserPassword password;
public JPAUser(String username, JPAUserPassword password)
{
this.username = username;
this.password = password;
}
...
}
public class JPAUserPassword
{
@Id
@GeneratedValue(generator = "genupwd", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "genupwd", sequenceName = "upwd_id_seq", allocationSize=1)
public Integer id;
@Column(nullable=false, updatable=false)
public String value;
@OneToOne(mappedBy = "password")
public JPAUser user;
public JPAUserPassword(String value)
{
this.password = value;
}
...
}
法典:
@Configuration
@EnableAutoConfiguration
@ComponentScan
@EntityScan("model.package.name")
@EnableJpaRepositories("repository.package.name")
public class JPATestConfiguration
{
@Autowired
Environment env;
@Bean
public DataSource dataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
}
@Repository
public interface JPAUserRepository extends CrudRepository<JPAUser, Integer>
{
}
@Repository
public interface JPAUserPasswordRepository extends CrudRepository<JPAUserPassword, Integer>
{
}
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource("classpath:/application-test.properties")
@SpringBootTest(classes={JPATestConfiguration.class})
public class JPAUserPasswordTest
{
@Autowired
private JPAUserPasswordRepository userPasswordRepository;
@Autowired
private JPAUserRepository userRepository;
private final String USERNAME = "username";
private final String PASSWORD = "password";
@Test
public void deleteAttachedEntity()
{
JPAUserPassword jpaUserPassword = new JPAUserPassword(PASSWORD);
JPAUser jpaUser = new JPAUser(USERNAME, jpaUserPassword);
userRepository.save(jpaUser);
int id = jpaUserPassword.getId();
// any of the two should throw the exception
userPasswordRepository.delete(jpaUserPassword);
userPasswordRepository.deleteById(id);
}
}
application-test.properties:
spring.datasource.url=jdbc:postgresql://localhost/MYDB?useSSL=false
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
依赖:
- 春季引导 2.1.2.发布
- Postgresql 42.2.5
- 休眠核心 5.3.7.最终版
// any of the two should throw the exception
userPasswordRepository.delete(jpaUserPassword);
userPasswordRepository.deleteById(id);
Above will delete record from child entity JPA`enter code here`UserPassword, so constraint violation error won't come.
If constraint violation is required on JPAUser, then remove CascadeType.ALL or make it CascadeType.PERSIST