1.4 SqlSession 1.4 SqlSession:MyBatis 的灵魂接口 SqlSession 是 MyBatis 中最重要的接口之一,它代表了与数据库的一次会话。你可以把它想象成 JDBC 中的 对象,但 SqlSession 提供了更高级、更便捷的操作数据库的方式。SqlSession 提供了执行 SQL 命令、获取映射器实例、管理事务等功能。 1.4.1 SqlSession 的作用 SqlSession 在 MyBatis 中扮演着核心角色,主要负责以下职责: 执行 SQL 语句: SqlSession 提供了多种执行 SQL 语句的方法,例如 , , , , 等。
SqlSession 是 MyBatis 中最重要的接口之一,它代表了与数据库的一次会话。你可以把它想象成 JDBC 中的 Connection 对象,但 SqlSession 提供了更高级、更便捷的操作数据库的方式。SqlSession 提供了执行 SQL 命令、获取映射器实例、管理事务等功能。
SqlSession 在 MyBatis 中扮演着核心角色,主要负责以下职责:
执行 SQL 语句: SqlSession 提供了多种执行 SQL 语句的方法,例如 selectOne, selectList, insert, update, delete 等。
获取 Mapper 接口: 通过 SqlSession,你可以获取与 XML 映射文件关联的 Mapper 接口实例,从而以面向对象的方式操作数据库。
事务管理: SqlSession 提供了事务控制的方法,例如 commit, rollback, close 等。
缓存管理: SqlSession 内部维护了一级缓存,用于提高查询效率。
SqlSession 的生命周期应该尽可能短。最佳实践是在一个请求或一个业务逻辑单元中使用一个 SqlSession 实例。用完后应该立即关闭 SqlSession,释放资源。
SqlSession 通常通过 SqlSessionFactory 获取。SqlSessionFactory 是 MyBatis 的核心组件,负责创建 SqlSession 实例。
// 从 SqlSessionFactory 获取 SqlSession SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSessionFactory.openSession() 方法有多个重载版本,可以指定是否自动提交事务、事务隔离级别等。
openSession(): 创建一个非自动提交事务的 SqlSession。
openSession(boolean autoCommit): 创建一个 SqlSession,可以指定是否自动提交事务。
openSession(TransactionIsolationLevel level): 创建一个具有指定事务隔离级别的 SqlSession。
openSession(ExecutorType execType): 创建一个具有指定执行器类型的 SqlSession。
openSession(ExecutorType execType, boolean autoCommit): 创建一个具有指定执行器类型和自动提交设置的 SqlSession。
openSession(Connection connection): 使用现有的 JDBC 连接创建 SqlSession。
openSession(ExecutorType execType, Connection connection): 使用现有的 JDBC 连接和指定的执行器类型创建 SqlSession。
SqlSession 提供了丰富的 API,用于执行各种数据库操作。以下是一些常用的方法:
selectOne(String statement, Object parameter): 执行一个查询,返回单个结果对象。
selectList(String statement, Object parameter): 执行一个查询,返回结果对象列表。
selectMap(String statement, Object parameter, String mapKey): 执行一个查询,返回一个以 mapKey 属性值为键,结果对象为值的 Map。
insert(String statement, Object parameter): 执行一个插入操作,返回受影响的行数。
update(String statement, Object parameter): 执行一个更新操作,返回受影响的行数。
delete(String statement, Object parameter): 执行一个删除操作,返回受影响的行数。
commit(): 提交事务。
rollback(): 回滚事务。
close(): 关闭 SqlSession,释放资源。
getMapper(Class<T> type): 获取 Mapper 接口的实例。
以下是一个使用 SqlSession 的简单示例,假设我们有一个 User 实体类和一个 UserMapper 接口。
定义实体类 User:
public class User { private Integer id; private String username; private String email; // Getters and setters public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
定义 Mapper 接口 UserMapper:
public interface UserMapper { User selectUserById(Integer id); List<User> selectAllUsers(); int insertUser(User user); int updateUser(User user); int deleteUser(Integer id); }
编写 XML 映射文件 UserMapper.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.mapper.UserMapper"> <select id="selectUserById" parameterType="java.lang.Integer" resultType="com.example.entity.User"> SELECT id, username, email FROM users WHERE id = #{id} </select> <select id="selectAllUsers" resultType="com.example.entity.User"> SELECT id, username, email FROM users </select> <insert id="insertUser" parameterType="com.example.entity.User"> INSERT INTO users (username, email) VALUES (#{username}, #{email}) </insert> <update id="updateUser" parameterType="com.example.entity.User"> UPDATE users SET username = #{username}, email = #{email} WHERE id = #{id} </update> <delete id="deleteUser" parameterType="java.lang.Integer"> DELETE FROM users WHERE id = #{id} </delete> </mapper>
使用 SqlSession 操作数据库:
import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; public class MyBatisExample { public static void main(String[] args) throws IOException { String resource = "mybatis-config.xml"; // 替换为你的 MyBatis 配置文件 InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession sqlSession = sqlSessionFactory.openSession()) { // 获取 Mapper 接口实例 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 查询用户 User user = userMapper.selectUserById(1); System.out.println("User: " + user.getUsername() + ", " + user.getEmail()); // 插入用户 User newUser = new User(); newUser.setUsername("testUser"); newUser.setEmail("test@example.com"); int insertedRows = userMapper.insertUser(newUser); System.out.println("Inserted rows: " + insertedRows); // 提交事务 sqlSession.commit(); // 查询所有用户 List<User> allUsers = userMapper.selectAllUsers(); allUsers.forEach(u -> System.out.println("User: " + u.getUsername() + ", " + u.getEmail())); } catch (Exception e) { // 处理异常,回滚事务 sqlSession.rollback(); e.printStackTrace(); } } }
代码解释:
首先,我们从 mybatis-config.xml 文件中加载 MyBatis 配置,创建 SqlSessionFactory。
然后,我们使用 sqlSessionFactory.openSession() 创建一个 SqlSession 实例。
通过 sqlSession.getMapper(UserMapper.class) 获取 UserMapper 接口的实例。
使用 userMapper 执行数据库操作,例如查询、插入等。
如果操作成功,调用 sqlSession.commit() 提交事务。
如果发生异常,调用 sqlSession.rollback() 回滚事务。
最后,务必调用 sqlSession.close() 关闭 SqlSession,释放资源。 这里使用了try-with-resources语句,SqlSession实现了AutoCloseable接口,所以可以自动关闭资源。
SqlSession 提供了编程式事务管理的方式。默认情况下,SqlSession 创建的连接不会自动提交事务。你需要手动调用 commit() 方法提交事务,或者调用 rollback() 方法回滚事务。
示例:
try (SqlSession sqlSession = sqlSessionFactory.openSession()) { try { // 执行数据库操作 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.insertUser(new User()); userMapper.updateUser(new User()); // 提交事务 sqlSession.commit(); } catch (Exception e) { // 回滚事务 sqlSession.rollback(); throw e; } }
SqlSession 内部维护了一级缓存,也称为本地缓存。一级缓存的生命周期与 SqlSession 相同。当你在同一个 SqlSession 中执行相同的查询时,MyBatis 会首先从一级缓存中查找结果,如果找到则直接返回,避免重复查询数据库。
一级缓存的特点:
作用域:SqlSession 级别。
存储方式:HashMap。
失效条件:
SqlSession 关闭。
执行了任何 update、insert、delete 操作,都会清空缓存。
手动调用 sqlSession.clearCache() 清空缓存。
示例:
try (SqlSession sqlSession = sqlSessionFactory.openSession()) { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 第一次查询,会查询数据库 User user1 = userMapper.selectUserById(1); System.out.println("First query: " + user1.getUsername()); // 第二次查询,会从一级缓存中获取 User user2 = userMapper.selectUserById(1); System.out.println("Second query: " + user2.getUsername()); // 修改用户信息,会清空一级缓存 User updateUser = new User(); updateUser.setId(1); updateUser.setUsername("newUsername"); userMapper.updateUser(updateUser); sqlSession.commit(); // 第三次查询,会重新查询数据库 User user3 = userMapper.selectUserById(1); System.out.println("Third query: " + user3.getUsername()); }
ExecutorType 用于控制 SqlSession 执行 SQL 语句的方式。MyBatis 提供了三种 ExecutorType:
SIMPLE: 默认的执行器类型,为每个 SQL 语句创建一个新的 Statement 对象。
REUSE: 重用 Statement 对象,可以提高性能,尤其是在执行大量相同 SQL 语句时。
BATCH: 批量执行 SQL 语句,可以显著提高插入、更新、删除操作的性能。
示例:
// 使用 BATCH 执行器 try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 批量插入用户 for (int i = 0; i < 1000; i++) { User user = new User(); user.setUsername("user" + i); user.setEmail("user" + i + "@example.com"); userMapper.insertUser(user); } // 提交事务 sqlSession.commit(); }
注意: 使用 BATCH 执行器时,需要手动调用 commit() 方法提交事务,否则数据不会被写入数据库。
SqlSession 本身不是线程安全的。因此,不要在多个线程之间共享同一个 SqlSession 实例。最佳实践是在每个线程中创建一个新的 SqlSession 实例,并在线程结束时关闭它。
SqlSession 是 MyBatis 中最重要的接口,它代表了与数据库的一次会话。通过 SqlSession,你可以执行 SQL 语句、获取 Mapper 接口实例、管理事务等。理解 SqlSession 的作用、生命周期、常用方法以及注意事项,对于编写高效、可靠的 MyBatis 应用程序至关重要。