当前位置: 代码网 > it编程>编程语言>Java > MyBatis会话模块详解

MyBatis会话模块详解

2026年02月09日 Java 我要评论
一、mybatis整体架构与会话模块mybatis是一个优秀的持久层框架,它支持定制化sql、存储过程以及高级映射。mybatis避免了几乎所有的jdbc代码和手动设置参数以及获取结果集的工作。1.1

一、mybatis整体架构与会话模块

mybatis是一个优秀的持久层框架,它支持定制化sql、存储过程以及高级映射。mybatis避免了几乎所有的jdbc代码和手动设置参数以及获取结果集的工作。

1.1 mybatis整体架构

mybatis采用分层架构设计,从上到下分为:

  • 应用层 — 与用户应用程序直接交互
  • 接口层 — 提供sqlsession和mapper接口
  • 核心处理层 — 包括sql解析、执行、结果映射
  • 基础支撑层 — 包括反射、类型处理、日志、缓存、事务
  • 数据层 — 数据源管理、连接池、jdbc驱动

会话模块位于接口层,是mybatis与应用程序交互的主要入口。

1.2 会话模块的核心职责

会话模块在mybatis中承担以下核心职责:

✅ 数据库操作接口 — 提供insert、update、delete、select等方法
✅ sqlsession生命周期管理 — 创建、使用、关闭sqlsession
✅ 事务控制 — 管理事务的开启、提交、回滚
✅ mapper管理 — 获取mapper接口的代理对象
✅ 批量操作支持 — 提供批量执行sql的能力

二、sqlsession接口详解

sqlsession是mybatis的核心接口之一,它定义了所有数据库操作的方法。

2.1 sqlsession核心方法分类

// 查询单个对象
<t> t selectone(string statement);
<t> t selectone(string statement, object parameter);

// 查询列表
<e> list<e> selectlist(string statement);
<e> list<e> selectlist(string statement, object parameter);

// 查询map
<k, v> map<k, v> selectmap(string statement, string mapkey);

// 游标查询
<t> cursor<t> selectcursor(string statement);
// 插入
int insert(string statement);
int insert(string statement, object parameter);

// 更新
int update(string statement);
int update(string statement, object parameter);

// 删除
int delete(string statement);
int delete(string statement, object parameter);
// 提交事务
void commit();
void commit(boolean force);

// 回滚事务
void rollback();
void rollback(boolean force);
// 获取mapper代理对象
<t> t getmapper(class<t> type);
// 1. 获取sqlsessionfactory
sqlsessionfactory factory = new sqlsessionfactorybuilder()
    .build(resources.getresourceasstream("mybatis-config.xml"));

// 2. 打开sqlsession
try (sqlsession session = factory.opensession()) {
    // 3. 执行sql
    user user = session.selectone(
        "com.example.mapper.usermapper.selectbyid", 1);
    system.out.println(user);
}
try (sqlsession session = factory.opensession()) {
    // 获取mapper代理对象
    usermapper mapper = session.getmapper(usermapper.class);

    // 调用mapper方法
    user user = mapper.selectbyid(1);
    system.out.println(user);

    session.commit();
}

三、sqlsession的实现类

mybatis提供了两个主要的sqlsession实现类。

3.1 defaultsqlsession

defaultsqlsession是sqlsession的默认实现类,最常用的实现。

核心代码片段:

public class defaultsqlsession implements sqlsession {

    private final configuration configuration;
    private final executor executor;

    @override
    public <t> t selectone(string statement, object parameter) {
        list<t> list = this.selectlist(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new toomanyresultsexception(
                "expected one result but found: " + list.size());
        }
        return null;
    }

    @override
    public void commit(boolean force) {
        try {
            executor.commit(iscommitorrollbackrequired(force));
            dirty = false;
        } catch (exception e) {
            throw exceptionfactory.wrapexception(
                "error committing transaction.", e);
        }
    }
}

3.2 sqlsessionmanager

sqlsessionmanager同时实现了sqlsession和sqlsessionfactory接口,既可以作为sqlsession使用,也可以作为工厂使用。

public class sqlsessionmanager 
    implements sqlsessionfactory, sqlsession {

    private final sqlsessionfactory sqlsessionfactory;
    private final sqlsession sqlsessionproxy;
    private threadlocal<sqlsession> localsqlsession 
        = new threadlocal<>();

    // 开启本地session
    public void startmanagedsession() {
        this.localsqlsession.set(opensession());
    }

    // 关闭本地session
    public void closemanagedsession() {
        sqlsession sqlsession = localsqlsession.get();
        if (sqlsession != null) {
            try {
                sqlsession.close();
            } finally {
                localsqlsession.remove();
            }
        }
    }
}

四、sqlsessionfactory工厂

sqlsessionfactory是创建sqlsession的工厂接口。

4.1 sqlsessionfactory接口方法

public interface sqlsessionfactory {

    // 常用方法:打开session
    sqlsession opensession();

    // 指定executortype
    sqlsession opensession(executortype exectype);

    // 指定是否自动提交
    sqlsession opensession(boolean autocommit);

    // 指定事务隔离级别
    sqlsession opensession(transactionisolationlevel level);

    // 使用指定连接
    sqlsession opensession(connection connection);
}

4.2 defaultsqlsessionfactory核心流程

创建sqlsession的完整流程:

private sqlsession opensessionfromdatasource(
    executortype exectype,
    transactionisolationlevel level,
    boolean autocommit) {

    transaction tx = null;
    try {
        //获取环境配置
        environment environment = configuration.getenvironment();

        //创建事务工厂
        transactionfactory transactionfactory = 
            gettransactionfactoryfromenvironment(environment);

        //创建事务
        tx = transactionfactory.newtransaction(
            environment.getdatasource(), level, autocommit);

        //创建执行器
        executor executor = configuration.newexecutor(tx, exectype);

        //创建defaultsqlsession
        return new defaultsqlsession(configuration, executor, autocommit);
    } catch (exception e) {
        closetransaction(tx);
        throw exceptionfactory.wrapexception(
            "error opening session.", e);
    }
}

五、sqlsession生命周期管理

sqlsession的生命周期管理非常重要,不当使用会导致资源泄漏。

5.1 sqlsession的三个阶段

// 方式1:默认创建
sqlsession session = sqlsessionfactory.opensession();

// 方式2:自动提交
sqlsession session = sqlsessionfactory.opensession(true);

// 方式3:指定executor类型
sqlsession session = sqlsessionfactory.opensession(
    executortype.batch);

// 方式4:事务隔离级别
sqlsession session = sqlsessionfactory.opensession(
    transactionisolationlevel.read_committed);
try (sqlsession session = factory.opensession()) {
    // 执行查询
    user user = session.selectone(
        "com.example.mapper.usermapper.selectbyid", 1);

    // 执行更新
    user updateuser = new user();
    updateuser.setid(1);
    updateuser.setname("张三");
    session.update(
        "com.example.mapper.usermapper.update", updateuser);

    // 提交事务
    session.commit();
}
// 推荐方式:try-with-resources
try (sqlsession session = factory.opensession()) {
    // 使用session
} // 自动关闭

// 传统方式
sqlsession session = null;
try {
    session = factory.opensession();
    // 使用session
} finally {
    if (session != null) {
        session.close();
    }
}

重要原则:sqlsession的作用域应该是方法级别的!

// 错误:sqlsession作为成员变量
public class userservice {
    private sqlsession session; // ❌ 不要这样做!

    public user getuserbyid(int id) {
        return session.selectone(
            "com.example.mapper.usermapper.selectbyid", id);
    }
}
// 正确:sqlsession在方法中创建和关闭
public class userservice {
    private sqlsessionfactory factory;

    public user getuserbyid(int id) {
        try (sqlsession session = factory.opensession()) {
            return session.selectone(
                "com.example.mapper.usermapper.selectbyid", id);
        }
    }
}

5.2 线程安全问题

sqlsession不是线程安全的,每个线程都应该有自己的sqlsession实例!

public class userservice {
    // ❌ 多个线程共享同一个sqlsession
    private sqlsession session = factory.opensession();
}
public class userservice {
    private sqlsessionfactory factory;

    public user getuserbyid(int id) {
        // ✅ 每次调用都创建新的sqlsession
        try (sqlsession session = factory.opensession()) {
            return session.selectone("...", id);
        }
    }
}

5.3 threadlocal管理模式

在某些场景下,可以使用threadlocal管理sqlsession:

public class sqlsessionmanager {

    private static final threadlocal<sqlsession> local_session 
        = new threadlocal<>();
    private static sqlsessionfactory factory;

    // 获取当前线程的sqlsession
    public static sqlsession getsession() {
        sqlsession session = local_session.get();
        if (session == null) {
            session = factory.opensession();
            local_session.set(session);
        }
        return session;
    }

    // 关闭当前线程的sqlsession
    public static void closesession() {
        sqlsession session = local_session.get();
        if (session != null) {
            session.close();
            local_session.remove();
        }
    }
}

六、事务控制机制

sqlsession提供了完善的事务控制机制。

6.1 自动提交 vs 手动提交

// 不自动提交(默认)
sqlsession session = factory.opensession();
session.insert("...");
session.commit(); // 需要手动提交

//自动提交
sqlsession session = factory.opensession(true);
session.insert("..."); // 自动提交

6.2 手动事务控制实战

try (sqlsession session = factory.opensession()) {
    try {
        // 1.插入用户
        user user = new user();
        user.setname("张三");
        user.setemail("zhangsan@example.com");
        session.insert(
            "com.example.mapper.usermapper.insert", user);

        //2.插入订单
        order order = new order();
        order.setuserid(user.getid());
        order.setamount(100.0);
        session.insert(
            "com.example.mapper.ordermapper.insert", order);

        //3.提交事务
        session.commit();
    } catch (exception e) {
        //4.回滚事务
        session.rollback();
        throw e;
    }
}

6.3 事务隔离级别

mybatis支持设置事务隔离级别:

sqlsession session = factory.opensession(
    transactionisolationlevel.read_committed);

支持的隔离级别:

隔离级别说明适用场景
none无事务隔离不推荐
read_uncommitted读未提交极少使用
read_committed读已提交大多数数据库默认
repeatable_read可重复读mysql默认
serializable串行化最高隔离级别

6.4 批量操作的事务控制

try (sqlsession session = factory.opensession(
    executortype.batch, false)) {
    try {
        usermapper mapper = session.getmapper(usermapper.class);

        // 批量插入
        for (int i = 0; i < 1000; i++) {
            user user = new user();
            user.setname("user" + i);
            user.setemail("user" + i + "@example.com");
            mapper.insert(user);
        }

        // 统一提交
        session.commit();
    } catch (exception e) {
        session.rollback();
        throw e;
    }
}

七、sqlsession与mapper集成

sqlsession与mapper接口的集成是mybatis最常用的方式。

7.1 定义mapper接口

public interface usermapper {
    user selectbyid(@param("id") integer id);
    list<user> selectall();
    int insert(user user);
    int update(user user);
    int deletebyid(@param("id") integer id);
}

7.2 mapper 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">

    <resultmap id="baseresultmap" 
               type="com.example.entity.user">
        <id column="id" property="id" jdbctype="integer"/>
        <result column="name" property="name" 
                jdbctype="varchar"/>
        <result column="email" property="email" 
                jdbctype="varchar"/>
    </resultmap>

    <select id="selectbyid" resultmap="baseresultmap">
        select id, name, email, age
        from t_user
        where id = #{id}
    </select>

    <insert id="insert" parametertype="com.example.entity.user" 
            usegeneratedkeys="true" keyproperty="id">
        insert into t_user (name, email, age)
        values (#{name}, #{email}, #{age})
    </insert>

</mapper>

7.3 通过sqlsession获取mapper

try (sqlsession session = factory.opensession()) {
    // 获取mapper代理对象
    usermapper mapper = session.getmapper(usermapper.class);

    //调用mapper方法
    user user = mapper.selectbyid(1);

    //插入数据
    user newuser = new user();
    newuser.setname("李四");
    newuser.setemail("lisi@example.com");
    mapper.insert(newuser);

    //提交事务
    session.commit();
}

7.4 mapperproxy工作原理

mybatis通过jdk动态代理为mapper接口生成代理对象:

public class mapperproxy<t> implements invocationhandler {

    private final sqlsession sqlsession;
    private final class<t> mapperinterface;

    @override
    public object invoke(object proxy, method method, 
                        object[] args) throws throwable {
        // 如果是object类的方法,直接执行
        if (object.class.equals(method.getdeclaringclass())) {
            return method.invoke(this, args);
        }

        // 获取mapper方法
        final mappermethod mappermethod = 
            cachedmappermethod(method);

        // 执行mapper方法
        return mappermethod.execute(sqlsession, args);
    }
}

八、executor执行器详解

executor是sqlsession的核心组件,负责实际执行sql语句。

8.1 三种executor类型

// 默认的executor,每次执行都会创建新的statement
sqlsession session = factory.opensession(executortype.simple);

特点:简单直接,每次创建新statement

适用场景:一般查询、单条操作

// 重用statement,减少创建开销
sqlsession session = factory.opensession(executortype.reuse);

特点:重用statement,减少创建开销

适用场景:执行相同sql多次

// 批量执行sql,性能最高
sqlsession session = factory.opensession(executortype.batch);

特点:批量执行,性能最优

适用场景:批量插入、更新

8.2 executor对比表

executor类型性能statement复用适用场景
simple⭐⭐⭐一般查询
reuse⭐⭐⭐⭐相同sql多次执行
batch⭐⭐⭐⭐⭐批量操作

8.3 实战示例

//batch执行器批量插入示例
try (sqlsession session = factory.opensession(
    executortype.batch)) {

    usermapper mapper = session.getmapper(usermapper.class);

    for (int i = 0; i < 1000; i++) {
        user user = new user();
        user.setname("user" + i);
        mapper.insert(user);
    }

    // 批量提交
    session.commit();
}

九、最佳实践

9.1 sqlsession使用黄金法则

✅ 及时关闭 — 使用try-with-resources确保资源释放
✅ 方法作用域 — sqlsession应该在方法级别创建和关闭
✅ 线程独立 — 每个线程使用独立的sqlsession
✅ 事务控制 — 明确提交或回滚事务
✅ 异常处理 — 捕获异常并回滚事务

9.2 spring集成最佳实践

在spring中使用mybatis时,sqlsession由容器管理:

@service
public class userservice {

    @autowired
    private usermapper usermapper;

    @transactional
    public void createuser(user user) {
        // sqlsession由spring管理,无需手动关闭
        usermapper.insert(user);
    }
}

9.3 常见问题排查

// 错误示例
sqlsession session = factory.opensession();
user user = session.selectone("...");
//忘记关闭 → 资源泄漏

//正确示例
try (sqlsession session = factory.opensession()) {
    user user = session.selectone("...");
} // 自动关闭
// 错误示例
try (sqlsession session = factory.opensession()) {
    session.insert("...");
    // 忘记提交 → 数据未保存
}

//正确示例
try (sqlsession session = factory.opensession()) {
    session.insert("...");
    session.commit(); // 记得提交
}
//错误示例
private sqlsession session = factory.opensession();

//正确示例
public user getuserbyid(integer id) {
    try (sqlsession session = factory.opensession()) {
        return session.selectone("...", id);
    }
}

十、总结

通过本文的学习,我们深入了解了mybatis会话模块的核心内容:

sqlsession接口 — 定义了所有数据库操作方法
sqlsessionfactory — 负责创建和管理sqlsession实例
生命周期管理 — 方法级别创建,线程独立使用
事务控制 — 支持手动提交和自动提交两种模式
mapper集成 — 通过动态代理实现类型安全操作
executor类型 — simple、reuse、batch各有千秋

到此这篇关于mybatis会话模块详解的文章就介绍到这了,更多相关mybatis会话模块内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com