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.
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.