0

私は純粋な JDBC とテストで遊んでいます。CRUD操作を実行できる単純なDAOを作成しました。

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() が最初に実行され、2 番目に testCRUD が実行された場合、SQLIntegrityConstraintViolationException がスローされたために testCRUD が失敗します 'VEHICLE' で定義された 'SQL131026082556940' で識別されるキー制約または一意のインデックス。
いくつかの調査の後、autoCommitがそのような動作を引き起こす可能性があるという情報を見つけたので、defaultAutoCommit プロパティを false に設定しました。
しかし、vehicleDao.insert(vehicle); を呼び出しているにもかかわらず、testCRUD は機能しません。vehicleDao.findByVehicleNo(vehicleNo); を使用すると、このオブジェクトが見つかりません。
その理由は単純だと思います。私の DAO はコミットを実行しませんでした。そこで、insert、update、delete メソッド「conn.commit()」を追加します。
しかし、今、あるテストからの変更は別のテストで再び表示されます:(テストはそれ自身のトランザクションをロールバックすると思いますが、DAOメソッドでコミットされたものではありません。
この問題に取り組むためのヒントはありますか?

4

2 に答える 2

1

このクラスには @Transactional のアノテーションが付けられており、私の知る限り、すべてのテスト メソッドのトランザクションが最後にロールバックされることを意味します。

はい、しかし、それは単一および/またはスプリング管理トランザクションを使用するコードにのみ当てはまりますあなたのコードはそうではありません。自分で接続を取得し、その接続でコミットを行っています。したがって、データは既にコミットされているため、コミットされたデータをロールバックすることはできません。その次に、トランザクションはスプリングに見えない (またはスプリングの制御下にある) ため、スプリングはそれについて何もできません。

Spring にトランザクションに影響を与えたり推進したりしたい場合は、コードを書き直して を使用するJdbcTemplateか、を使用しTransactionAwareDataSourceProxyます。詳細については、Spring リファレンス ガイドを参照してください。

リンク:

  1. JdbcTemplate javadoc | 参照
  2. TransactionAwareDataSourceProxy javadoc | 参照
  3. リファレンス ガイドのJDBC セクション
于 2013-10-27T09:38:20.680 に答える
0

@Transactional であり、私の知る限り、すべてのテスト メソッドのトランザクションが最後にロールバックされることを意味します。

これは正しくありません。アノテーションが構成されている例外が発生していない場合、トランザクションがコミットされます。

@TransactionalrollbackForおそらく構成する必要がある属性があります。

于 2013-10-26T20:10:11.863 に答える