MyBatis技术详解与实战

引言

MyBatis 是一款优秀的 Java 持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的工作,使开发者能更专注于对业务逻辑的实现。本文将详细介绍MyBatis的核心概念,并通过示例代码进行深入讲解。

一、配置文件 

MyBatis 配置文件(通常命名为 mybatis-config.xml)是 MyBatis 框架的核心配置文件,它定义了整个应用中如何连接数据库、事务管理器设置、映射器注册以及其他全局属性。下面将详细讲解其各个元素和结构,并提供示例代码。


配置文件基本结构




    
    
        
    

    
    
        
            
            
            
                
            
        
        
    

    
    
        
    

    
    
        
    

    
    
        
    

各部分详解:

  • :包含一系列影响 MyBatis 行为的全局设置,例如开启二级缓存、延迟加载策略、默认的执行器类型等。 

     
     
    

  • :定义一个或多个环境配置,每个环境可以有不同的事务管理和数据源配置。其中 default 属性指定了默认使用的环境。 

    
         
         
            
            
            
            
        
    

  • :用于定义类型别名,简化类全限定名在 XML 映射文件中的使用。 

    
    
    

  • :注册 Mapper 接口或 XML 映射文件的位置。 

    
    
    
    

  • :用于引入外部属性文件并可在此处覆盖属性值 

    

以上就是 MyBatis 配置文件的基本内容和用法示例。通过这些配置,开发者能够灵活地组织和定制 MyBatis 的运行环境和行为特性。 

二、映射文件

MyBatis 映射文件是 MyBatis 框架中用于定义 SQL 语句和结果映射关系的 XML 文件。每个映射文件通常对应一个 DAO(数据访问对象)接口或一个数据库表的操作逻辑。以下是一个详细的 MyBatis 映射文件结构及示例代码讲解:

映射文件基本结构



 

    
    
        INSERT INTO user(id, username, password)
        VALUES (#{id}, #{username}, #{password})
    

    
        UPDATE user SET username = #{username}, password = #{password}
        WHERE id = #{id}
    
    
    
        DELETE FROM user WHERE id = #{id}
    

    
    

    
    

    
    

    
    
        
        
        
        
        
            
            
        
    

    
    


 各部分详解:

  • 根标签:定义了映射器的命名空间,它与 Java 中的 Mapper 接口全限定名相匹配。
  • , , :分别用于定义插入、更新和删除操作的 SQL 语句,其中 id 属性是唯一标识符,方便在 Java 代码中调用。
  • SELECT * FROM user WHERE id = #{id} INSERT INTO user(username, password) VALUES (#{username}, #{password})

    在 XML 映射文件中:

    • 标签的 namespace 属性与 Java 接口中定义的完全限定名相匹配。
    • SELECT * FROM user username = #{username} AND age = #{age}

      在这个例子中,如果传入的参数 username 或者 age 不为 null,那么对应的 SQL 条件就会被添加到查询语句中。这样,就可以根据实际传入的参数动态生成过滤条件。

      示例2:choose, when, otherwise

      
      

      这里展示了如何基于不同的条件选择执行不同的 SQL 片段。当 type 参数等于 'active' 或 'inactive' 时,分别筛选出状态对应的数据;若 type 参数不满足上述两种情况,则默认筛选出状态为 'active' 或 'inactive' 的所有数据。

      示例3:foreach

      
      

      在本例中,foreach 标签用于遍历一个集合参数 list,并将其元素值依次插入到 SQL 中的 IN 子句中,从而实现在一次查询中根据多个 ID 进行批量查找。

      示例4:set

      
          UPDATE user
          
              username = #{username},
              password = #{password},
              
              email = #{email}
          
          WHERE id = #{id}
      
      

      该示例展示了 set 标签用于更新操作,它会根据传入的实体对象属性是否为空,动态拼接需要更新的字段及值,避免了无效的 SQL 更新。

      通过这些动态SQL标签,MyBatis 能够帮助我们编写出更加灵活、可复用的 SQL 语句,以适应多变的业务需求。

      七、事务管理

      在MyBatis中,事务管理主要是通过SqlSession来实现的。SqlSession对象提供了对数据库事务的基本控制,包括开启事务、提交事务和回滚事务等操作。

      MyBatis事务管理原理与示例

      1. 原理讲解:

      • 自动提交模式(默认):当打开一个新的SqlSession时,默认情况下,MyBatis会以自动提交模式运行。这意味着每次执行完SQL语句后,MyBatis都会立即提交事务,确保数据的持久化。
      • 手动提交模式:如果需要在一系列数据库操作之间进行事务控制,可以关闭SqlSession的自动提交,并在所有操作完成之后手动调用commit()方法提交事务,或者在发生错误时调用rollback()方法回滚事务。
      try (SqlSession session = sqlSessionFactory.openSession()) {
          // 手动开启事务(关闭自动提交)
          session.getConnection().setAutoCommit(false);
      
          UserMapper mapper = session.getMapper(UserMapper.class);
          mapper.insertUser(new User("user1", "password1"));
          mapper.updateUser(1, "newUsername");
      
          // 在所有操作成功后提交事务
          session.commit();
      } catch (Exception e) {
          // 如果出现任何异常,回滚事务
          session.rollback();
      }
      

      • Spring整合下事务管理:在实际开发中,通常使用Spring框架结合MyBatis来处理事务管理,通过AOP切面编程将事务逻辑从业务代码中解耦出来。在这种情况下,开发者不需要直接操作SqlSession的事务,而是配置声明式事务管理,在Service层方法上添加@Transactional注解,由Spring容器统一管理事务生命周期。
      @Service
      public class UserService {
      
          @Autowired
          private UserMapper userMapper;
      
          @Transactional
          public void updateUserAndInsertAnother(User updateUser, User insertUser) {
              userMapper.update(updateUser);
              try {
                  // 业务逻辑...
              } catch (Exception e) {
                  throw new RuntimeException("An error occurred", e); // 异常会被Spring捕获并触发回滚
              }
              userMapper.insert(insertUser);
          }
      }
      

      2. 示例代码:
      下面是一个不使用Spring的情况下,纯MyBatis手动管理事务的例子:

      import org.apache.ibatis.session.SqlSession;
      import org.apache.ibatis.session.SqlSessionFactory;
      import org.apache.ibatis.session.SqlSessionFactoryBuilder;
      
      import java.io.InputStream;
      
      public class MyBatisTransactionExample {
      
          public static void main(String[] args) throws Exception {
              String resource = "mybatis-config.xml";
              InputStream inputStream = Resources.getResourceAsStream(resource);
              SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      
              try (SqlSession session = sqlSessionFactory.openSession()) {
                  // 开启手动事务
                  session.getConnection().setAutoCommit(false);
      
                  UserMapper mapper = session.getMapper(UserMapper.class);
      
                  // 执行插入操作
                  User newUser = new User("user1", "password");
                  mapper.insert(newUser);
      
                  // 模拟异常,抛出后会导致事务回滚
                  if (true) {
                      throw new RuntimeException("模拟业务异常,导致事务回滚");
                  }
      
                  // 若没有异常,则提交事务
                  session.commit();
              } catch (Exception e) {
                  // 出现异常时,回滚事务
                  session.rollback();
                  e.printStackTrace();
              }
          }
      }
      

      在这个例子中,我们首先关闭了自动提交,然后执行了一次插入操作。若出现异常,则通过 session.rollback() 回滚事务;否则,在一切正常的情况下,调用 session.commit() 提交事务,从而完成整个事务流程。

      八、插件

      MyBatis 提供了一种插件(Plugin)机制,允许开发者在不修改 MyBatis 内部代码的情况下,对 SQL 执行过程中的某些环节进行拦截和扩展。通过实现 Interceptor 接口并注册到全局配置文件中,可以实现诸如日志记录、性能统计、权限控制等功能。

      原理讲解:

      1. 拦截器接口:MyBatis 的插件基于 Java 的动态代理技术实现,核心是 org.apache.ibatis.plugin.Interceptor 接口。这个接口有一个方法 intercept(),它会在执行 SQL 之前和之后被调用。
      2. 签名匹配:插件需要指定要拦截的方法签名,这可以通过 @Signature 注解来完成,包括类型(如 Executor, ParameterHandler, ResultSetHandler 或 StatementHandler)、方法名以及参数类型列表。
      3. 处理逻辑:在 intercept() 方法中,我们可以获取到当前执行上下文的信息,并根据业务需求插入自定义的处理逻辑。

      示例代码:

      下面是一个简单的 MyBatis 插件示例,该插件用于在每次执行 SQL 查询前打印 SQL 语句:

      import org.apache.ibatis.plugin.Interceptor;
      import org.apache.ibatis.plugin.Invocation;
      import org.apache.ibatis.plugin.Plugin;
      import org.apache.ibatis.reflection.MetaObject;
      import org.apache.ibatis.session.Configuration;
      
      import java.util.Properties;
      
      public class SimpleLoggingPlugin implements Interceptor {
      
          @Override
          public Object intercept(Invocation invocation) throws Throwable {
              // 在执行SQL前打印SQL语句
              MetaObject metaObject = SystemMetaObject.forObject(invocation.getTarget());
              Configuration configuration = (Configuration) metaObject.getValue("delegate.configuration");
              String sql = (String) metaObject.getValue("delegate.boundSql.sql");
              System.out.println("[SimpleLoggingPlugin] Executing SQL: " + sql);
      
              // 调用原始方法执行SQL
              return invocation.proceed();
          }
      
          @Override
          public Object plugin(Object target) {
              return Plugin.wrap(target, this);
          }
      
          @Override
          public void setProperties(Properties properties) {
              // 可以在这里设置插件的属性,如果有的话
          }
      
          @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
          public void onExecutorUpdate() {
              // 这里也可以添加针对特定方法的前置或后置处理
          }
      }
      

      要在 MyBatis 中启用这个插件,你需要在 MyBatis 配置文件(mybatis-config.xml)中添加如下配置:

      
          
          
              
                  
              
          
      
      

      以上示例仅演示了如何创建一个最基础的插件,在实际应用中,插件可能包含更复杂的逻辑,例如解析 SQL 参数、计算查询时间、验证用户权限等。

      总结

      MyBatis 以其轻量级、灵活和高度可定制的特性,在Java持久层框架中占据重要地位。通过掌握其基本用法和高级特性,开发者能够高效、简洁地完成数据访问层的设计与开发

你可能感兴趣的:(mybatis,java,开发语言)