MyBatis调用数据库的完整流程是怎样的?

MyBatis作为一款优秀的持久层框架,它极大地简化了Java应用程序与数据库的交互过程,它将繁琐的JDBC操作封装起来,让开发者能够更专注于SQL本身,而非繁琐的连接管理和结果集处理,理解MyBatis如何调用数据库,是掌握其核心机制的关键,这个过程可以分解为几个清晰的步骤,从配置初始化到最终执行SQL并返回结果。

MyBatis调用数据库的完整流程是怎样的?

核心配置:搭建桥梁的基石

MyBatis的一切操作都始于一个核心配置文件,通常是mybatis-config.xml,这个文件是MyBatis的全局性配置,它告诉MyBatis如何连接数据库、如何管理事务以及去哪里找到SQL语句。

配置文件中最重要的部分是<environments>标签,它定义了数据库环境,包括:

  • 事务管理器:配置为JDBCMANAGEDJDBC表示由MyBatis自身管理事务的提交和回滚,适用于简单的本地应用;MANAGED则将事务管理交给容器(如Spring),这是在集成环境中的常见选择。
  • 数据源:配置数据库连接信息,MyBatis支持多种数据源配置,如UNPOOLED(不使用连接池,每次请求都打开新连接)、POOLED(使用连接池,性能更优,是开发中的首选)和JNDI(从应用服务器配置的JNDI数据源获取连接),在POOLED配置中,我们需要提供数据库驱动、URL、用户名和密码等基本信息。

配置文件通过<mappers>标签注册Mapper XML文件或Mapper接口,将SQL定义与Java代码关联起来,这是MyBatis能够找到并执行SQL的前提。

Mapper接口与XML:定义SQL的契约

现代MyBatis开发推荐使用Mapper接口的方式,这种方式将SQL调用与Java方法绑定,提供了类型安全的API。

  1. Mapper接口:这是一个普通的Java接口,其中定义的方法与要执行的SQL语句一一对应,一个UserMapper接口可能包含User findById(Integer id)方法,这个接口本身不包含任何实现代码,它仅仅是一个契约,定义了调用数据库的规范。

  2. Mapper XML文件:这是SQL语句真正存在的地方,每个Mapper接口通常对应一个同名的XML文件,该文件以<mapper>为根标签,其namespace属性必须指向对应的Mapper接口的全限定名(例如com.example.mapper.UserMapper)。

<mapper>标签内部,我们使用一系列标签来定义SQL语句:

  • <select>:用于定义查询语句。
  • <insert>:用于定义插入语句。
  • <update>:用于定义更新语句。
  • <delete>:用于定义删除语句。

每个标签都有一个id属性,这个id必须与Mapper接口中的方法名完全一致,MyBatis正是通过“接口全限定名 + 方法名”来唯一定位一条SQL语句的。parameterType指定传入参数的类型,resultTyperesultMap则指定返回结果的映射规则。

MyBatis调用数据库的完整流程是怎样的?

下表小编总结了这些常用标签的用途:

用途 关键属性
<select> 执行数据库查询操作 id, parameterType, resultType/resultMap
<insert> 执行数据库插入操作 id, parameterType, useGeneratedKeys, keyProperty
<update> 执行数据库更新操作 id, parameterType
<delete> 执行数据库删除操作 id, parameterType

SqlSessionFactory与SqlSession:执行SQL的引擎

配置和定义完成后,MyBatis需要一个执行引擎来真正地调用数据库,这个引擎由两个核心组件构成:SqlSessionFactorySqlSession

  1. SqlSessionFactory:这是一个重量级对象,是创建SqlSession的工厂,它的作用是读取并解析mybatis-config.xml配置文件,将所有配置信息加载到内存中,一个应用通常只需要一个SqlSessionFactory实例,它应该在应用启动时被创建,并伴随整个应用的生命周期,创建它通常使用SqlSessionFactoryBuilder

  2. SqlSession:这是一个轻量级、非线程安全的对象,可以将其理解为一次与数据库的会话,它包含了执行SQL命令所需的所有方法,例如selectOne, selectList, insert, update, delete等,它还负责管理事务和获取Mapper接口的代理实例。

SqlSession的生命周期应该是短期的,通常在一个方法或一个请求的范围内,每次需要与数据库交互时,都从SqlSessionFactory中获取一个新的SqlSession实例,使用完毕后必须立即关闭,以释放数据库连接资源。

完整调用流程:从方法到数据库

将以上所有部分串联起来,MyBatis调用数据库的完整流程如下:

  1. 初始化:应用启动时,通过SqlSessionFactoryBuilder读取mybatis-config.xml,构建一个SqlSessionFactory实例。
  2. 创建会话:当业务代码需要操作数据库时,通过sqlSessionFactory.openSession()创建一个SqlSession对象。
  3. 获取Mapper代理:调用sqlSession.getMapper(UserMapper.class)方法,MyBatis会使用动态代理技术,为UserMapper接口创建一个代理对象,这个代理对象实现了UserMapper接口。
  4. 执行方法:业务代码调用代理对象的方法,例如userMapper.findById(1)
  5. 定位SQL:代理对象拦截到方法调用,它会根据当前Mapper接口的namespace和方法名findById,组合成com.example.mapper.UserMapper.findById这个唯一的ID,去已加载的Mapper XML中查找对应的<select>
  6. 参数处理与执行:找到SQL语句后,MyBatis会解析SQL中的占位符(如#{id}),将传入的参数1设置到PreparedStatement中,通过底层的JDBC执行这条SQL语句。
  7. 结果映射:数据库返回结果集后,MyBatis根据resultTyperesultMap的定义,将结果集中的每一行数据映射成一个Java对象(如User对象)。
  8. 返回结果:将映射好的Java对象返回给业务代码。
  9. 关闭会话:在finally块中调用sqlSession.close(),关闭会话,释放数据库连接。

通过这一系列精巧的设计,MyBatis将对JDBC的复杂操作封装在内部,开发者只需关注业务逻辑和SQL编写,实现了Java代码与SQL语句的解耦,极大地提升了开发效率和代码的可维护性。


相关问答FAQs

Q1: 在MyBatis的SQL中,和有什么区别?

MyBatis调用数据库的完整流程是怎样的?

A: 和在MyBatis中是两种截然不同的参数替换方式,核心区别在于安全性和处理时机。

  • (预编译处理):这是MyBatis推荐的、默认的方式,当MyBatis处理带有的SQL时,它会创建一个PreparedStatement对象,然后将中的参数作为占位符()安全地传入,这种方式可以有效防止SQL注入攻击,因为参数值在SQL执行前已经被数据库驱动进行了转义处理,它只会被当作纯粹的数值或字符串,而不会被解释为SQL语法的一部分。SELECT * FROM user WHERE id = #{id} 会被处理成 SELECT * FROM user WHERE id = ?

  • (字符串替换):这种方式直接将中的内容原封不动地拼接到SQL语句中,它发生在MyBatis创建PreparedStatement之前,虽然它在某些场景下很有用,例如动态传入表名、列名或者ORDER BY排序字段,但存在极大的SQL注入风险,如果传入的参数是恶意构造的SQL片段,它会被直接执行,从而破坏数据库。SELECT * FROM user ORDER BY ${columnName},如果columnName被传入id; DROP TABLE user;,将会导致灾难性后果。

为了安全,能使用的地方就绝对不要使用,只有在需要动态拼接SQL结构(如表名、列名)且能确保参数来源安全可控时,才应谨慎使用。

Q2: 为什么SqlSession是非线程安全的?在项目中应该如何管理它的生命周期?

A: SqlSession被设计为非线程安全的,主要是因为它内部持有了与数据库会话相关的状态信息,这些信息不应该被多个线程共享。

  1. 非线程安全的原因

    • 事务管理SqlSession管理着当前会话的事务状态(如自动提交开关、事务是否已提交或回滚),如果多个线程共享一个SqlSession,一个线程的提交或回滚操作会影响到其他线程正在执行的操作,导致数据不一致。
    • 一级缓存:每个SqlSession都拥有自己独立的一级缓存(Session级别的缓存),如果在多个线程间共享,一个线程对数据库的修改可能会被另一个线程的缓存所覆盖,导致读取到脏数据。
    • 数据库连接SqlSession内部封装了数据库连接对象(Connection),让多个线程并发使用同一个连接是非常危险的,会导致执行顺序混乱和结果错误。
  2. 生命周期管理
    正确的做法是,将SqlSession的作用域限制在方法级别或请求级别。

    • 在独立应用中:通常在try-with-resourcestry-finally代码块中创建和使用,确保在方法执行完毕后能被立即关闭。
      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.findById(1);
        // ... do something with user
        sqlSession.commit(); // 如果需要
      } // sqlSession会自动关闭
    • 在Web应用(如与Spring集成):开发者通常不需要手动管理SqlSession,MyBatis-Spring集成包会通过SqlSessionTemplateMapperScannerConfigurer,将SqlSession的生命周期与Spring的事务管理绑定,每个事务或请求都会获得一个独立的SqlSession实例,并在事务结束时自动关闭,从而保证了线程安全。

【版权声明】:本站所有内容均来自网络,若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!

(0)
热舞的头像热舞
上一篇 2025-10-04 18:00
下一篇 2024-07-10 14:19

相关推荐

  • 如何正确使用CDN250FG电暖器以确保最佳性能?

    cdn250fg电暖器使用方法:先确保电源符合要求,再将电暖器放置在平稳的地面上。打开开关前,检查是否有异物堵塞散热口。使用时保持室内适当的通风,避免长时间直吹身体,特别是头部和脚部。不用时记得关闭电源,并拔掉插头。定期清理灰尘,维护设备性能。

    2024-09-11
    0011
  • 服务器ecs配置

    服务器 ECS 配置涵盖实例规格(含 vCPU、内存等)、镜像、块存储、网络及环境参数等多方面设置。

    2025-04-30
    004
  • 如何将NSG3025与CDN163成功连接?

    要连接NSG3025和CDN163,您需要配置网络设置并确保两者在同一网络中。具体步骤可能因设备而异,建议查阅相关文档或联系技术支持获取详细指导。

    2024-09-28
    0011
  • 未经备案的域名是否能够接入CDN加速服务?

    未备案的域名理论上可以使用CDN加速服务,但实际操作中可能会遇到限制。根据相关法律法规,所有网站都需要进行ICP备案,未经备案的网站可能无法正常访问或使用国内的CDN服务。建议先完成备案流程后再考虑使用CDN加速。

    2024-09-12
    0012

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

QQ-14239236

在线咨询: QQ交谈

邮件:asy@cxas.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信