SqlSessionManagerTest.java
/*
* Copyright 2009-2026 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.session;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.Reader;
import java.sql.Connection;
import java.util.List;
import org.apache.ibatis.BaseDataTest;
import org.apache.ibatis.domain.blog.Author;
import org.apache.ibatis.domain.blog.PostLite;
import org.apache.ibatis.domain.blog.mappers.AuthorMapper;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.io.Resources;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class SqlSessionManagerTest extends BaseDataTest {
private static SqlSessionManager manager;
@BeforeAll
static void setup() throws Exception {
createBlogDataSource();
final String resource = "org/apache/ibatis/builder/MapperConfig.xml";
final Reader reader = Resources.getResourceAsReader(resource);
manager = SqlSessionManager.newInstance(reader);
}
@Test
void shouldThrowExceptionIfMappedStatementDoesNotExistAndSqlSessionIsOpen() {
try {
manager.startManagedSession();
manager.selectList("ThisStatementDoesNotExist");
fail("Expected exception to be thrown due to statement that does not exist.");
} catch (PersistenceException e) {
assertTrue(e.getMessage().contains("does not contain value for ThisStatementDoesNotExist"));
} finally {
manager.close();
}
}
@Test
void shouldCommitInsertedAuthor() {
try {
manager.startManagedSession();
AuthorMapper mapper = manager.getMapper(AuthorMapper.class);
Author expected = new Author(500, "cbegin", "******", "cbegin@somewhere.com", "Something...", null);
mapper.insertAuthor(expected);
manager.commit();
Author actual = mapper.selectAuthor(500);
assertNotNull(actual);
} finally {
manager.close();
}
}
@Test
void shouldRollbackInsertedAuthor() {
try {
manager.startManagedSession();
AuthorMapper mapper = manager.getMapper(AuthorMapper.class);
Author expected = new Author(501, "lmeadors", "******", "lmeadors@somewhere.com", "Something...", null);
mapper.insertAuthor(expected);
manager.rollback();
Author actual = mapper.selectAuthor(501);
assertNull(actual);
} finally {
manager.close();
}
}
@Test
void shouldImplicitlyRollbackInsertedAuthor() {
manager.startManagedSession();
AuthorMapper mapper = manager.getMapper(AuthorMapper.class);
Author expected = new Author(502, "emacarron", "******", "emacarron@somewhere.com", "Something...", null);
mapper.insertAuthor(expected);
manager.close();
Author actual = mapper.selectAuthor(502);
assertNull(actual);
}
@Test
void shouldFindAllPostLites() throws Exception {
List<PostLite> posts = manager.selectList("org.apache.ibatis.domain.blog.mappers.PostMapper.selectPostLite");
assertEquals(2, posts.size()); // old gcode issue #392, new #1848
}
@Test
void shouldFindAllMutablePostLites() throws Exception {
List<PostLite> posts = manager.selectList("org.apache.ibatis.domain.blog.mappers.PostMapper.selectMutablePostLite");
assertEquals(2, posts.size()); // old gcode issue #392, new #1848
}
@Test
void shouldCloseSessionWhenManagedSessionIsStarted() {
manager.startManagedSession();
assertTrue(manager.isManagedSessionStarted());
manager.close();
assertFalse(manager.isManagedSessionStarted());
}
@Test
void shouldThrowExceptionWhenClosingWithoutManagedSession() {
SqlSessionException exception = assertThrows(SqlSessionException.class, () -> manager.close());
assertNotNull(exception);
assertTrue(exception.getMessage().contains("Cannot close"));
assertTrue(exception.getMessage().contains("No managed session is started"));
}
@Test
void shouldClearThreadLocalEvenWhenSessionCloseThrowsException() throws Exception {
createBlogDataSource();
final String resource = "org/apache/ibatis/builder/MapperConfig.xml";
final Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory baseFactory = new SqlSessionFactoryBuilder().build(reader);
Configuration configuration = baseFactory.getConfiguration();
SqlSession baseSession = baseFactory.openSession();
SqlSession failingSession = new SqlSession() {
@Override
public <T> T selectOne(String statement) {
return baseSession.selectOne(statement);
}
@Override
public <T> T selectOne(String statement, Object parameter) {
return baseSession.selectOne(statement, parameter);
}
@Override
public <K, V> java.util.Map<K, V> selectMap(String statement, String mapKey) {
return baseSession.selectMap(statement, mapKey);
}
@Override
public <K, V> java.util.Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return baseSession.selectMap(statement, parameter, mapKey);
}
@Override
public <K, V> java.util.Map<K, V> selectMap(String statement, Object parameter, String mapKey,
RowBounds rowBounds) {
return baseSession.selectMap(statement, parameter, mapKey, rowBounds);
}
@Override
public <T> org.apache.ibatis.cursor.Cursor<T> selectCursor(String statement) {
return baseSession.selectCursor(statement);
}
@Override
public <T> org.apache.ibatis.cursor.Cursor<T> selectCursor(String statement, Object parameter) {
return baseSession.selectCursor(statement, parameter);
}
@Override
public <T> org.apache.ibatis.cursor.Cursor<T> selectCursor(String statement, Object parameter,
RowBounds rowBounds) {
return baseSession.selectCursor(statement, parameter, rowBounds);
}
@Override
public <E> java.util.List<E> selectList(String statement) {
return baseSession.selectList(statement);
}
@Override
public <E> java.util.List<E> selectList(String statement, Object parameter) {
return baseSession.selectList(statement, parameter);
}
@Override
public <E> java.util.List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return baseSession.selectList(statement, parameter, rowBounds);
}
@Override
public void select(String statement, ResultHandler handler) {
baseSession.select(statement, handler);
}
@Override
public void select(String statement, Object parameter, ResultHandler handler) {
baseSession.select(statement, parameter, handler);
}
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
baseSession.select(statement, parameter, rowBounds, handler);
}
@Override
public int insert(String statement) {
return baseSession.insert(statement);
}
@Override
public int insert(String statement, Object parameter) {
return baseSession.insert(statement, parameter);
}
@Override
public int update(String statement) {
return baseSession.update(statement);
}
@Override
public int update(String statement, Object parameter) {
return baseSession.update(statement, parameter);
}
@Override
public int delete(String statement) {
return baseSession.delete(statement);
}
@Override
public int delete(String statement, Object parameter) {
return baseSession.delete(statement, parameter);
}
@Override
public void commit() {
baseSession.commit();
}
@Override
public void commit(boolean force) {
baseSession.commit(force);
}
@Override
public void rollback() {
baseSession.rollback();
}
@Override
public void rollback(boolean force) {
baseSession.rollback(force);
}
@Override
public java.util.List<org.apache.ibatis.executor.BatchResult> flushStatements() {
return baseSession.flushStatements();
}
@Override
public void close() {
baseSession.close();
throw new RuntimeException("Simulated close failure");
}
@Override
public void clearCache() {
baseSession.clearCache();
}
@Override
public Configuration getConfiguration() {
return baseSession.getConfiguration();
}
@Override
public <T> T getMapper(Class<T> type) {
return baseSession.getMapper(type);
}
@Override
public Connection getConnection() {
return baseSession.getConnection();
}
};
SqlSessionFactory factoryWithFailingSession = new SqlSessionFactory() {
@Override
public SqlSession openSession() {
return failingSession;
}
@Override
public SqlSession openSession(boolean autoCommit) {
return failingSession;
}
@Override
public SqlSession openSession(TransactionIsolationLevel level) {
return failingSession;
}
@Override
public SqlSession openSession(ExecutorType execType) {
return failingSession;
}
@Override
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return failingSession;
}
@Override
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return failingSession;
}
@Override
public SqlSession openSession(ExecutorType execType, Connection connection) {
return failingSession;
}
@Override
public SqlSession openSession(Connection connection) {
return failingSession;
}
@Override
public Configuration getConfiguration() {
return configuration;
}
};
SqlSessionManager newManager = SqlSessionManager.newInstance(factoryWithFailingSession);
newManager.startManagedSession();
assertTrue(newManager.isManagedSessionStarted());
RuntimeException exception = assertThrows(RuntimeException.class, () -> newManager.close());
assertNotNull(exception);
assertTrue(exception.getMessage().contains("Simulated close failure"));
assertFalse(newManager.isManagedSessionStarted());
}
}