简体   繁体   中英

How to read uncommitted data using jdbc?

I want to test how JDBC transactions work. Particularly, I want to see a read of uncommitted data. I've written one integration test in spring boot environment using a locally installed PostgreSQL database.

I'm trying to insert a row into a table, read it from one transaction, then update from another transaction without committing it, and read it again hoping it would change.

Table for the test (DDL):

create table users
(
    id          integer default nextval('user_id_sequence'::regclass) not null
        constraint users_pkey
            primary key,
    first_name  varchar(255)                                          not null,
    second_name varchar(255)                                          not null,
    email       varchar(255)
);

alter table users
    owner to postgres;

The test:

    public void testHealthCheck() throws SQLException {
        Connection zeroConnection = dataSource.getConnection();
        Integer insertedUserId = insertUserSilently(zeroConnection, new User()
                .setFirstName("John")
                .setSecondName("Doe")
                .setEmail("johndoe@gmail.com"));
        zeroConnection.close();

        Connection firstConnection = dataSource.getConnection();
        firstConnection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        firstConnection.setAutoCommit(false);

        Connection secondConnection = dataSource.getConnection();
        secondConnection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        secondConnection.setAutoCommit(false);

        List<User> users = getAllUsersSilently(firstConnection);
        log.info("Got users: {}", silentToJsonString(users));

        PersistenceUtils.updateUserEmailSilently(secondConnection, insertedUserId, "johndoe@yahoo.com");

        users = getAllUsersSilently(firstConnection);
        log.info("Got users: {}", silentToJsonString(users));

        secondConnection.rollback();
        secondConnection.close();

        users = getAllUsersSilently(firstConnection);
        log.info("Got users: {}", silentToJsonString(users));

        firstConnection.close();
    }

Utility class:


    private static final String INSERT_USER_SQL = "insert into users(first_name, second_name, email) values (?, ?, ?)";
    private static final String UPDATE_USER_SQL = "update users set email = ? where id = ?;";
    private static final String SELECT_ALL_USERS_SQL = "select * from users";

    public static List<User> extractUsersSilently(ResultSet resultSet) {
        List<User> resultList = newArrayList();
        try {
            while (resultSet.next()) {
                Integer id = resultSet.getInt(1);
                String firstName = resultSet.getString(2);
                String secondName = resultSet.getString(3);
                String email = resultSet.getString(4);
                resultList.add(new User(id, firstName, secondName, email));
            }
        } catch (SQLException e) {
            log.error("Error while extracting result set", e);
            return emptyList();
        }
        return resultList;
    }

    public static Integer insertUserSilently(Connection connection, User user) {
        try {
            PreparedStatement insertStatement = connection.prepareStatement(INSERT_USER_SQL, Statement.RETURN_GENERATED_KEYS);
            insertStatement.setString(1, user.getFirstName());
            insertStatement.setString(2, user.getSecondName());
            insertStatement.setString(3, user.getEmail());
            insertStatement.execute();
            ResultSet resultSet = insertStatement.getGeneratedKeys();
            resultSet.next();
            return resultSet.getInt(1);
        } catch (Exception exception) {
            log.error(format("Exception while inserting user %s", user), exception);
            return -1;
        }
    }

    public static List<User> getAllUsersSilently(Connection connection) {
        try {
            PreparedStatement selectStatement = connection.prepareStatement(SELECT_ALL_USERS_SQL);
            selectStatement.execute();
            return extractUsersSilently(selectStatement.getResultSet());
        } catch (Exception exception) {
            log.error("Exception while getting all users", exception);
            return Collections.emptyList();
        }
    }

    public static void updateUserEmailSilently(Connection connection, Integer userId, String userEmail) {
        try {
            PreparedStatement updateStatement = connection.prepareStatement(UPDATE_USER_SQL);
            updateStatement.setString(1, userEmail);
            updateStatement.setInt(2, userId);
            updateStatement.execute();
        } catch (Exception exception) {
            log.error(format("Exception while updating user %d", userId), exception);
        }
    }
}

Actual results are (you have to clear table manually before the test):

Got users:

[{"id":55,"firstName":"John","secondName":"Doe","email":"johndoe@gmail.com"}]

Got users:

[{"id":55,"firstName":"John","secondName":"Doe","email":"johndoe@gmail.com"}]

Got users:

[{"id":55,"firstName":"John","secondName":"Doe","email":"johndoe@gmail.com"}]

Although second read should've seen uncommitted change to email.

Cannot read uncommitted data in Postgres

See section 13.2. Transaction Isolation of the PostgreSQL documentation:

In PostgreSQL, you can request any of the four standard transaction isolation levels, but internally only three distinct isolation levels are implemented, ie PostgreSQL's Read Uncommitted mode behaves like Read Committed . This is because it is the only sensible way to map the standard isolation levels to PostgreSQL's multiversion concurrency control architecture.

This means that if you want to test TRANSACTION_READ_UNCOMMITTED , you need a DBMS other than PostgreSQL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM