java - 语句被中止,因为它会导致唯一或主键约束中出现重复的键值

标签 java jpa jakarta-ee derby jboss-arquillian

运行测试时出错。我收到 SQLIntegrityConstraintViolationException

Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL160412141534310' defined on 'CHARACTERS'.

字符类代码

@Entity
@Table(name = "CHARACTERS")
@NamedQueries({
@NamedQuery(name = Character.FIND_ALL, query = "SELECT c FROM Character c")
})
public class Character implements Serializable {

public static final String FIND_ALL = "Character.findAll";

private static final long serialVersionUID = 1L;

@Id 
private int id;

@Column(length = 50)
private String name;

public Character() {
}

public Character(int id, String name) {
    this.id = id;
    this.name = name;
}

public Character(String name) {
    this.name = name;
}

/* Getter and setter below */

CharactersBean 类

@Stateful
@TransactionAttribute(TransactionAttributeType.NEVER)
public class CharactersBean implements Serializable {

@PersistenceContext(type = PersistenceContextType.EXTENDED)
EntityManager em;

public void save(Character e) {
    em.persist(e);
}

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void commitChanges() {

}

public List<Character> get() {
    return em.createNamedQuery(Character.FIND_ALL, Character.class).getResultList();
}

测试类 当执行should_update_characters_after_transaction_flush时,会抛出上述异常。

@RunWith(Arquillian.class)
public class ExtendedPersistenceContextTest {

@PersistenceContext
EntityManager em;

@EJB
CharactersBean bean;

@Deployment
public static WebArchive deploy() {
    return ShrinkWrap.create(WebArchive.class)
            .addPackage("org.javaee7.jpa.extended.pc")
            .addAsResource("META-INF/persistence.xml")
            .addAsResource("META-INF/create.sql")
            .addAsResource("META-INF/drop.sql")
            .addAsResource("META-INF/load.sql");
}

@Before
public void setup() {
    Character wil = new Character(8, "Wil Wheaton");
    bean.save(wil);

    for (Character c : bean.get()) {
        if ("Raj".equals(c.getName())) {
            c.setName("Rajesh Ramayan");
            bean.save(c);
        }
    }
}

@Test
@InSequence(1)
public void should_not_persist_changes_without_transaction_flush() {
    List<Character> characters = em.createNamedQuery(Character.FIND_ALL, Character.class).getResultList();
    Character raj = em.find(Character.class, 6);

    assertThat(characters, hasSize(7));
    assertThat(raj.getName(), is(equalTo("Raj")));
}

@Test
@InSequence(2)
public void should_update_characters_after_transaction_flush() {
    //when
    bean.commitChanges();

    //then
    List<Character> characters = em.createNamedQuery(Character.FIND_ALL, Character.class).getResultList();
    Character rajesh = em.find(Character.class, 6);
    Character wil = em.find(Character.class, 8);

    assertThat(characters, hasSize(8));
    assertThat(rajesh.getName(), is(equalTo("Rajesh Ramayan")));
    assertThat(wil.getName(), is(equalTo("Wil Wheaton")));
}

数据输入 Derby 数据库中。

INSERT INTO CHARACTERS("ID", "NAME") VALUES (1, 'Penny')
INSERT INTO CHARACTERS("ID", "NAME") VALUES (2, 'Sheldon')
INSERT INTO CHARACTERS("ID", "NAME") VALUES (3, 'Amy')
INSERT INTO CHARACTERS("ID", "NAME") VALUES (4, 'Leonard')
INSERT INTO CHARACTERS("ID", "NAME") VALUES (5, 'Bernadette')
INSERT INTO CHARACTERS("ID", "NAME") VALUES (6, 'Raj')
INSERT INTO CHARACTERS("ID", "NAME") VALUES (7, 'Howard')

最佳答案

这与 JUnit 测试框架的运行方式有关: 共有5个注释标记方法需要在某个事件上执行:

  • @BeforeClass:在执行任何测试之前,此方法将执行一次
  • @Before:此方法将在实际测试方法被调用之前执行,并且对于每个测试方法都有一个新的
  • @Test:这是一个实际的测试方法
  • @After:该方法将在每个测试方法执行完毕后执行,为下一个测试做清理工作
  • @AfterClass:此方法将在所有测试方法完成后执行,以关闭打开的数据库连接或其他...

在你的测试课上,你试图在每次重新测试之前坚持威尔·惠顿先生。 这是第一次工作,但第二次时,该条目已经被持久化。尝试使用完全相同的 ID 来持久化它会违反您的唯一约束。

这里简单的解决方案是将@Before替换为@BeforeClass注释,这样该条目只会被持久化一次,或者,添加一个带有@After注释的方法正在从数据库中删除该条目,以便您可以重新插入它。

此外,我建议在测试完成后清除数据库中测试插入的任何条目。您可以通过使用带注释的 @After@AfterClass

方法轻松做到这一点

最诚挚的问候

J·亚当

关于java - 语句被中止,因为它会导致唯一或主键约束中出现重复的键值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36578870/

相关文章:

jakarta-ee - Java EE 应用服务器上的 OSGi 支持

java - 部署 Java Web 应用程序是否比其他 PHP Web 应用程序更便宜?

java - 将 JPQL 自定义查询结果渲染到 JSF 页面中的问题

java - 为什么我在下面的程序中收到 UnsatisfiedLinkError?

java - Gradle 将命令行参数传递给 war

java - 当csv值不存在时,如何使if语句正常工作?

jpa - @MappedSuperclass 和子类中相同的 JPA 回调方法

java - CrudRepository 不从 API 返回数据库元素

java - 使用 while 循环记分的问题 (Java)

java.sql.SQLSyntaxErrorException : Table/View 'SEQUENCE' does not exist