【问题标题】:Testing Pure JDBC DAO method with AbstractTransactionalJUnit4SpringContextTests: changes in DB not reverted after test method使用 AbstractTransactionalJUnit4SpringContextTests 测试纯 JDBC DAO 方法:测试方法后未恢复 DB 中的更改
【发布时间】:2013-11-05 19:59:08
【问题描述】:

我在玩纯 JDBC 和测试。我编写了简单的 DAO,它允许执行 CRUD 操作:

package pl.aszecowka;


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


public class JdbcVehicleDao implements VehicleDao {
    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public void insert(Vehicle vehicle) {
        String sql = "insert into vehicle(vehicle_no,color, wheel, seat) values(?,?,?,?)";
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, vehicle.getVehicleNo());
            ps.setString(2, vehicle.getColor());
            ps.setInt(3, vehicle.getWheel());
            ps.setInt(4, vehicle.getSeat());
            ps.executeUpdate();
            ps.close();
            conn.commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                }
            }
        }
    }

    @Override
    public void update(Vehicle vehicle) {
        String sql = "update vehicle set color=?, wheel=?, seat=? where vehicle_no = ?";
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, vehicle.getColor());
            ps.setString(4, vehicle.getVehicleNo());
            ps.setInt(2, vehicle.getWheel());
            ps.setInt(3, vehicle.getSeat());
            ps.executeUpdate();
            ps.close();
            conn.commit();
        } catch (SQLException ex) {
            throw new RuntimeException(ex);
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException ex) {
                }
            }
        }
    }

    @Override
    public void delete(Vehicle vehicle) {
        String sql = "delete from vehicle where vehicle_no = ? ";
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, vehicle.getVehicleNo());
            int i = ps.executeUpdate();
            System.out.println(i);
            ps.close();
            conn.commit();
        } catch (SQLException ex) {
            throw new RuntimeException(ex);
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException ex) {
                }
            }
        }
    }

    @Override
    public Vehicle findByVehicleNo(String vehicleNo) {
        String sql = "select * from vehicle where vehicle_no = ?";
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, vehicleNo);
            Vehicle vehicle = null;
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                vehicle = new Vehicle(rs.getString("vehicle_no"), rs.getString("color"), rs.getInt("wheel"), rs.getInt("seat"));
            }
            rs.close();
            ps.close();
            return vehicle;
        } catch (SQLException ex) {
            throw new RuntimeException(ex);
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException ex) {
                }
            }
        }

    }
}

这是我的弹簧配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver"/>
            <property name="url" value="jdbc:derby://localhost:1527/vehicle;create=true"/>
            <property name="username" value="app"/>
            <property name="password" value="app"/>
            <property name="initialSize" value="2"/>
            <property name="maxActive" value="5"/>
           <property name="defaultAutoCommit" value="false" />
        </bean>

        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>

        <bean id="vehicleDao" class="pl.aszecowka.JdbcVehicleDao">
            <property name="dataSource" ref="dataSource"/>
        </bean>

我的测试:

@ContextConfiguration("/beans.xml")
public class JdbcVehicleDaoTest extends AbstractTransactionalJUnit4SpringContextTests {

    @Resource
    private VehicleDao vehicleDao;


    @Test
    public void testCRUD()
    {
        String vehicleNo = "ABCDEF";
        String color = "blue";
        int wheel = 4;
        int seat = 4;
        Vehicle vehicle = new Vehicle(vehicleNo, color, wheel, seat);
        vehicleDao.insert(vehicle);
        Vehicle fromDB = vehicleDao.findByVehicleNo(vehicleNo);
        Assert.assertNotNull(fromDB);
        Assert.assertEquals(vehicleNo, fromDB.getVehicleNo());
        Assert.assertEquals(color, fromDB.getColor());
        Assert.assertEquals(wheel, fromDB.getWheel());
        Assert.assertEquals(seat, fromDB.getSeat());

        color = "blue";
        seat = 5;
        wheel = 12;

        fromDB.setColor(color);
        fromDB.setSeat(seat);
        fromDB.setWheel(wheel);
        vehicleDao.update(fromDB);
        fromDB = vehicleDao.findByVehicleNo(fromDB.getVehicleNo());
        Assert.assertNotNull(fromDB);
        Assert.assertEquals(vehicleNo, fromDB.getVehicleNo());
        Assert.assertEquals(color, fromDB.getColor());
        Assert.assertEquals(wheel, fromDB.getWheel());
        Assert.assertEquals(seat, fromDB.getSeat());

        vehicleDao.delete(fromDB);
        fromDB = vehicleDao.findByVehicleNo(fromDB.getVehicleNo());
        Assert.assertNull(fromDB);
    }

    @Test
    public void testCheckIfTestRollbackWorks()
    {
        Vehicle vehicle = new Vehicle("ABCDEF", "blue", 4, 4);
        vehicleDao.insert(vehicle);
    }
}

在我的测试类中,我想避免任何自定义“清理”方法,这些方法会恢复测试期间所做的所有更改,因此我扩展了 AbstractTransactionalJUnit4SpringContextTests。这个类用 @Transactional 注释,据我所知,这意味着所有测试方法的事务将在最后回滚。
一开始回滚不起作用,例如,如果 testCheckIfTestRollbackWorks() 作为第一个运行,第二个是 testCRUD,则 testCRUD 由于抛出 SQLIntegrityConstraintViolationException 而失败:语句被中止,因为它会导致重复唯一或主键约束或唯一索引中的键值由“车辆”上定义的“SQL131026082556940”标识。
经过一番研究,我发现 autoCommit 可能导致此类行为的信息,然后我将 defaultAutoCommit 属性设置为 false。
但是,testCRUD 不起作用,因为尽管我打电话给 vehicleDao.insert(车辆); 使用时找不到这个对象:vehicleDao.findByVehicleNo(vehicleNo);
我认为原因很简单:我的 DAO 没有执行任何提交。所以我添加了插入、更新和删除方法“conn.commit()”。
但是现在,一个测试的更改在另一个测试中再次可见:(我假设测试回滚它自己的事务,但不是这个在 DAO 方法中提交的事务。
任何提示如何解决这个问题?

【问题讨论】:

    标签: java spring testing jdbc transactions


    【解决方案1】:

    这个类是用@Transactional注解的,据我所知 意味着所有测试方法的事务将在 结束。

    是的但是这仅适用于使用单个和/或弹簧管理事务的代码。您的代码没有,您自己获得了连接并对该连接进行了提交。所以数据已经提交,提交的数据不能回滚。除此之外,事务对 Spring 不可见(或在 Springs 控制下),因此 Spring 对此无能为力。

    如果您希望 Spring 影响/驱动您的事务,请重写您的代码以使用 JdbcTemplate 或使用 TransactionAwareDataSourceProxy。更多信息可以在Spring Reference Guide找到。

    链接:

    1. Jdbc模板javadoc | reference
    2. TransactionAwareDataSourceProxy javadoc | reference
    3. 参考指南的JDBC Section

    【讨论】:

      【解决方案2】:

      @Transactional,据我所知,这意味着交易 所有测试方法最后都会回滚。

      这不是真的,如果没有发生配置注释的异常,它将提交事务。

      @Transactional 有一个 rollbackFor 属性,您应该配置它。

      【讨论】:

        猜你喜欢
        • 2019-07-19
        • 1970-01-01
        • 1970-01-01
        • 2015-04-07
        • 1970-01-01
        • 1970-01-01
        • 2018-11-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多