Spring DBUnit 插入数据的时候如何处理自增ID

Posted ekoeko

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring DBUnit 插入数据的时候如何处理自增ID相关的知识,希望对你有一定的参考价值。

Spring DBUnit 插入数据的时候如何处理自增ID

今天在补单元测试的时候遇到一个问题,在给插入数据的方法写单元测试的时候,第一遍运行的时候是没问题,第二遍运行就报错了,如下:

junit.framework.ComparisonFailure: value (table=FACULTY_ROOM, row=2, col=id) 
Expected :3
Actual   :4
 <Click to see difference>
   at org.dbunit.assertion.JUnitFailureFactory.createFailure(JUnitFailureFactory.java:39)
    at org.dbunit.assertion.DefaultFailureHandler.createFailure(DefaultFailureHandler.java:97)
    at org.dbunit.assertion.DefaultFailureHandler.handle(DefaultFailureHandler.java:223)
    at org.dbunit.assertion.DbUnitAssert.compareData(DbUnitAssert.java:524)
    at org.dbunit.assertion.DbUnitAssert.assertEquals(DbUnitAssert.java:409)
    at org.dbunit.assertion.DbUnitAssert.assertEquals(DbUnitAssert.java:312)
    at org.dbunit.assertion.DbUnitAssert.assertEquals(DbUnitAssert.java:274)
    at org.dbunit.assertion.DbUnitAssert.assertEqualsIgnoreCols(DbUnitAssert.java:122)
    at org.dbunit.Assertion.assertEqualsIgnoreCols(Assertion.java:74)
    at com.github.springtestdbunit.assertion.NonStrictDatabaseAssertion.assertEquals(NonStrictDatabaseAssertion.java:56)
    at com.github.springtestdbunit.assertion.NonStrictDatabaseAssertion.assertEquals(NonStrictDatabaseAssertion.java:48)
    at com.github.springtestdbunit.DbUnitRunner.verifyExpected(DbUnitRunner.java:154)
    at com.github.springtestdbunit.DbUnitRunner.verifyExpected(DbUnitRunner.java:120)
    at com.github.springtestdbunit.DbUnitRunner.afterTestMethod(DbUnitRunner.java:86)
    at com.github.springtestdbunit.DbUnitTestExecutionListener.afterTestMethod(DbUnitTestExecutionListener.java:190)
    at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:319)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:94)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)`

第一遍运行成功是因为第一次插入数据到测试数据库时,从原始数据ID=2增长到ID=3,和预期一致,后面执行完毕,数据虽然回滚删除了,但是自增ID的游标没变,下次插入数据ID就是从4开始的,所以与预期的ID=3不一致,我的代码和数据文件如下:

@Test
@ExpectedDatabase(value = "facultyService.createFaculty.expectedData.xml", assertionMode = DatabaseAssertionMode.NON_STRICT)
public void testCreateFaculty() {
    Faculty faculty = new Faculty();
    faculty.setCode("rjgc");
    faculty.setName("软件工程");
    faculty.setAbbreviation("rjgc");
    facultyService.createFaculty(faculty);
}


<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<FACULTY id="1" code="jsj" name="计算机系" abbreviation="jsj"/>
<FACULTY id="2" code="cstmgc" name="测试更新土木工程系" abbreviation="cstmgc"/>
</dataset>

解决方法:在插入操作之前把ID自增的游标定位到当前初始数据的最大ID处,下一次插入数据的ID就是最大ID+1,代码如下:

package test.edu.util;

import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public final class DbTestUtil {

    private static final String MAX_ID = "test.reset.sql.maxId";

    private static final String RESET = "test.reset.sql.template";

    private DbTestUtil() {
    }

    public static void resetAutoIncrementColumns(ApplicationContext applicationContext,
                                                 String... tableNames) throws SQLException {
        DataSource dataSource = applicationContext.getBean(DataSource.class);
        String resetSqlTemplate = getResetSqlTemplate(applicationContext, RESET);
        String getMaxIdTemplate = getResetSqlTemplate(applicationContext, MAX_ID);
        try (Connection dbConnection = dataSource.getConnection()) {
            //Create SQL statements that reset the auto increment columns and invoke
            //the created SQL statements.
            for (String resetSqlArgument : tableNames) {
                try (Statement statement = dbConnection.createStatement()) {
                    String maxId = String.format(getMaxIdTemplate, resetSqlArgument);
                    ResultSet resultSet = statement.executeQuery(maxId);
                    if (resultSet.next()) {
                        String id = resultSet.getString(1);
                        String resetSql = String.format(resetSqlTemplate, resetSqlArgument);
                        resetSql = resetSql.replace("maxId", id);
                        statement.execute(resetSql);
                    }
                }
            }
        }
    }

    private static String getResetSqlTemplate(ApplicationContext applicationContext, String option) {
        //Read the SQL template from the properties file
        Environment environment = applicationContext.getBean(Environment.class);
        return environment.getRequiredProperty(option);
    }
}


@DatabaseSetup("facultyService.data.xml")
public class FacultyServiceTest extends BaseServiceTest {
    @Autowired
    private FacultyService facultyService;
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @Before
    public void setUp() throws SQLException {
        DbTestUtil.resetAutoIncrementColumns(applicationContext, "faculty", "faculty_room");
    }
    
    @Test
    @ExpectedDatabase(value = "facultyService.createFaculty.expectedData.xml", assertionMode = DatabaseAssertionMode.NON_STRICT)
    public void testCreateFaculty() {
        Faculty faculty = new Faculty();
        faculty.setCode("rjgc");
        faculty.setName("软件工程");
        faculty.setAbbreviation("rjgc");
        facultyService.createFaculty(faculty);
    }
}

如果还有什么问题,可以在下面留言。

以上是关于Spring DBUnit 插入数据的时候如何处理自增ID的主要内容,如果未能解决你的问题,请参考以下文章

Spring AOP 配置通知方法的时候如何处理方法重载

如何处理spring事务与多数据源冲突问题?

Codeigniter:当我插入数据时出现重复键错误,我该如何处理这个错误?

使用 PetaPoco 插入时如何处理数据库中的 DEFAULT 值?

spring boot中各种数据不匹配如何处理jackson反序列化错误

如何处理插入 '\0' 的字符数组?