MyBatis 设备类编写指南

MyBatis 工具类编写指南

1. 基础工具类实现

1.1 核心工具类

package com.example.util;
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;
/**
* MyBatis 工具类 - 单例模式
*/
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
// 私有构造器,防止实例化
private MyBatisUtil() {}
// 静态代码块初始化 SqlSessionFactory
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException("初始化SqlSessionFactory失败", e);
}
}
/**
* 获取 SqlSessionFactory
*/
public static SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
/**
* 获取 SqlSession(默认不自动提交)
*/
public static SqlSession openSession() {
return sqlSessionFactory.openSession();
}
/**
* 获取 SqlSession(指定是否自动提交)
*/
public static SqlSession openSession(boolean autoCommit) {
return sqlSessionFactory.openSession(autoCommit);
}
/**
* 关闭 SqlSession
*/
public static void closeSession(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.close();
}
}
}

1.2 增强版工具类(支持多数据源)

package com.example.util;
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.HashMap;
import java.util.Map;
/**
* 增强版 MyBatis 工具类 - 支持多数据源
*/
public class EnhancedMyBatisUtil {
private static final Map<String, SqlSessionFactory> SQL_SESSION_FACTORY_MAP = new HashMap<>();
  static {
  // 初始化默认数据源
  initSqlSessionFactory("mybatis-config.xml", "default");
  }
  /**
  * 初始化指定配置文件的 SqlSessionFactory
  */
  public static void initSqlSessionFactory(String configFile, String dataSourceName) {
  try {
  InputStream inputStream = Resources.getResourceAsStream(configFile);
  SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  SQL_SESSION_FACTORY_MAP.put(dataSourceName, sqlSessionFactory);
  } catch (IOException e) {
  throw new RuntimeException("初始化SqlSessionFactory失败: " + dataSourceName, e);
  }
  }
  /**
  * 获取默认数据源的 SqlSessionFactory
  */
  public static SqlSessionFactory getSqlSessionFactory() {
  return getSqlSessionFactory("default");
  }
  /**
  * 获取指定数据源的 SqlSessionFactory
  */
  public static SqlSessionFactory getSqlSessionFactory(String dataSourceName) {
  SqlSessionFactory factory = SQL_SESSION_FACTORY_MAP.get(dataSourceName);
  if (factory == null) {
  throw new IllegalArgumentException("未找到数据源: " + dataSourceName);
  }
  return factory;
  }
  /**
  * 从默认数据源获取 SqlSession
  */
  public static SqlSession openSession() {
  return openSession("default");
  }
  /**
  * 从指定数据源获取 SqlSession
  */
  public static SqlSession openSession(String dataSourceName) {
  return getSqlSessionFactory(dataSourceName).openSession();
  }
  /**
  * 安全关闭 SqlSession
  */
  public static void closeSession(SqlSession sqlSession) {
  if (sqlSession != null) {
  try {
  sqlSession.close();
  } catch (Exception e) {
  // 记录日志,但不抛出异常
  System.err.println("关闭SqlSession时发生异常: " + e.getMessage());
  }
  }
  }
  /**
  * 提交并关闭 SqlSession
  */
  public static void commitAndClose(SqlSession sqlSession) {
  if (sqlSession != null) {
  try {
  sqlSession.commit();
  } finally {
  closeSession(sqlSession);
  }
  }
  }
  /**
  * 回滚并关闭 SqlSession
  */
  public static void rollbackAndClose(SqlSession sqlSession) {
  if (sqlSession != null) {
  try {
  sqlSession.rollback();
  } finally {
  closeSession(sqlSession);
  }
  }
  }
  }

2. 事务管理工具类

2.1 事务模板工具类

package com.example.util;
import org.apache.ibatis.session.SqlSession;
/**
* 事务模板工具类
*/
public class TransactionTemplate {
/**
* 在事务中执行操作(自动提交)
*/
public static <T> T execute(MyBatisCallback<T> callback) {
  SqlSession sqlSession = null;
  try {
  sqlSession = MyBatisUtil.openSession();
  T result = callback.doInSqlSession(sqlSession);
  sqlSession.commit();
  return result;
  } catch (Exception e) {
  if (sqlSession != null) {
  sqlSession.rollback();
  }
  throw new RuntimeException("事务执行失败", e);
  } finally {
  MyBatisUtil.closeSession(sqlSession);
  }
  }
  /**
  * 在事务中执行操作(无返回值)
  */
  public static void executeWithoutResult(MyBatisCallbackWithoutResult callback) {
  execute(sqlSession -> {
  callback.doInSqlSession(sqlSession);
  return null;
  });
  }
  /**
  * 带重试机制的事务执行
  */
  public static <T> T executeWithRetry(MyBatisCallback<T> callback, int maxRetries) {
    int retryCount = 0;
    while (retryCount <= maxRetries) {
    try {
    return execute(callback);
    } catch (Exception e) {
    retryCount++;
    if (retryCount > maxRetries) {
    throw e;
    }
    // 等待后重试
    try {
    Thread.sleep(1000 * retryCount);
    } catch (InterruptedException ie) {
    Thread.currentThread().interrupt();
    throw new RuntimeException("重试被中断", ie);
    }
    }
    }
    throw new RuntimeException("重试次数耗尽");
    }
    }
    /**
    * 回调接口(有返回值)
    */
    @FunctionalInterface
    interface MyBatisCallback<T> {
      T doInSqlSession(SqlSession sqlSession);
      }
      /**
      * 回调接口(无返回值)
      */
      @FunctionalInterface
      interface MyBatisCallbackWithoutResult {
      void doInSqlSession(SqlSession sqlSession);
      }

2.2 使用示例

// 使用事务模板
public class UserService {
public void createUserWithProfile(User user, UserProfile profile) {
TransactionTemplate.executeWithoutResult(sqlSession -> {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserProfileMapper profileMapper = sqlSession.getMapper(UserProfileMapper.class);
userMapper.insert(user);
profile.setUserId(user.getId());
profileMapper.insert(profile);
});
}
public User getUserByIdWithRetry(Long id) {
return TransactionTemplate.executeWithRetry(sqlSession -> {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
return userMapper.selectById(id);
}, 3); // 最多重试3次
}
}

3. Mapper 管理工具类

3.1 Mapper 工具类

package com.example.util;
import org.apache.ibatis.session.SqlSession;
import java.util.function.Function;
/**
* Mapper 工具类
*/
public class MapperUtil {
/**
* 执行 Mapper 操作(自动管理资源)
*/
public static <T, R> R executeMapper(Class<T> mapperClass, Function<T, R> function) {
  try (SqlSession sqlSession = MyBatisUtil.openSession()) {
  T mapper = sqlSession.getMapper(mapperClass);
  R result = function.apply(mapper);
  sqlSession.commit();
  return result;
  }
  }
  /**
  * 执行 Mapper 操作(无返回值)
  */
  public static <T> void executeMapper(Class<T> mapperClass, Consumer<T> consumer) {
    executeMapper(mapperClass, mapper -> {
    consumer.accept(mapper);
    return null;
    });
    }
    /**
    * 批量操作工具方法
    */
    public static <T> void batchInsert(Class<T> mapperClass, List<?> entities, Consumer<T> insertMethod) {
      try (SqlSession sqlSession = MyBatisUtil.openSession(ExecutorType.BATCH)) {
      T mapper = sqlSession.getMapper(mapperClass);
      for (Object entity : entities) {
      insertMethod.accept(mapper, entity);
      }
      sqlSession.commit();
      }
      }
      }
      @FunctionalInterface
      interface Consumer<T> {
        void accept(T t) throws Exception;
        }

3.2 使用示例

public class UserService {
public User findUserById(Long id) {
return MapperUtil.executeMapper(UserMapper.class, mapper ->
mapper.selectById(id)
);
}
public void batchCreateUsers(List<User> users) {
  MapperUtil.batchInsert(UserMapper.class, users, (mapper, user) ->
  mapper.insert(user)
  );
  }
  public void updateUserEmail(Long id, String email) {
  MapperUtil.executeMapper(UserMapper.class, mapper -> {
  mapper.updateEmail(id, email);
  });
  }
  }

4. 分页工具类

4.1 分页参数类

package com.example.util;
import java.util.Collections;
import java.util.List;
/**
* 分页参数类
*/
public class Page<T> {
  private int pageNum;        // 当前页码
  private int pageSize;       // 每页大小
  private long total;         // 总记录数
  private int pages;          // 总页数
  private List<T> records;    // 数据列表
    public Page() {
    this.records = Collections.emptyList();
    }
    public Page(int pageNum, int pageSize) {
    this();
    this.pageNum = pageNum;
    this.pageSize = pageSize;
    }
    // getter 和 setter
    public int getPageNum() { return pageNum; }
    public void setPageNum(int pageNum) { this.pageNum = pageNum; }
    public int getPageSize() { return pageSize; }
    public void setPageSize(int pageSize) { this.pageSize = pageSize; }
    public long getTotal() { return total; }
    public void setTotal(long total) {
    this.total = total;
    // 计算总页数
    if (pageSize > 0) {
    this.pages = (int) (total / pageSize);
    if (total % pageSize != 0) {
    this.pages++;
    }
    }
    }
    public int getPages() { return pages; }
    public void setPages(int pages) { this.pages = pages; }
    public List<T> getRecords() { return records; }
      public void setRecords(List<T> records) { this.records = records; }
        /**
        * 获取起始行(用于MySQL的LIMIT)
        */
        public int getStartRow() {
        return (pageNum - 1) * pageSize;
        }
        /**
        * 是否有上一页
        */
        public boolean hasPrevious() {
        return pageNum > 1;
        }
        /**
        * 是否有下一页
        */
        public boolean hasNext() {
        return pageNum < pages;
        }
        }

4.2 分页工具类

package com.example.util;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
import java.util.function.BiFunction;
/**
* 分页工具类
*/
public class PageUtil {
/**
* 执行分页查询
*/
public static <T, M> Page<T> paginate(Class<M> mapperClass,
  BiFunction<M, RowBounds, List<T>> queryFunction,
    int pageNum, int pageSize) {
    return paginate(mapperClass, queryFunction, pageNum, pageSize, null);
    }
    /**
    * 执行分页查询(带总数查询)
    */
    public static <T, M> Page<T> paginate(Class<M> mapperClass,
      BiFunction<M, RowBounds, List<T>> queryFunction,
        int pageNum, int pageSize,
        TotalCounter<M> totalCounter) {
          Page<T> page = new Page<>(pageNum, pageSize);
            try (SqlSession sqlSession = MyBatisUtil.openSession()) {
            M mapper = sqlSession.getMapper(mapperClass);
            // 查询总数
            if (totalCounter != null) {
            long total = totalCounter.count(mapper);
            page.setTotal(total);
            }
            // 如果没有数据,直接返回空分页
            if (page.getTotal() == 0) {
            return page;
            }
            // 执行分页查询
            RowBounds rowBounds = new RowBounds((pageNum - 1) * pageSize, pageSize);
            List<T> records = queryFunction.apply(mapper, rowBounds);
              page.setRecords(records);
              return page;
              }
              }
              /**
              * 简单的分页查询(使用MyBatis物理分页)
              */
              public static <T> List<T> simplePaginate(BiFunction<SqlSession, RowBounds, List<T>> queryFunction,
                int pageNum, int pageSize) {
                try (SqlSession sqlSession = MyBatisUtil.openSession()) {
                RowBounds rowBounds = new RowBounds((pageNum - 1) * pageSize, pageSize);
                return queryFunction.apply(sqlSession, rowBounds);
                }
                }
                }
                @FunctionalInterface
                interface TotalCounter<M> {
                  long count(M mapper);
                  }

4.3 使用示例

public class UserService {
public Page<User> getUsersByPage(int pageNum, int pageSize) {
  return PageUtil.paginate(
  UserMapper.class,
  (mapper, rowBounds) -> mapper.selectByPage(rowBounds),
  pageNum,
  pageSize,
  mapper -> mapper.selectCount()  // 总数查询
  );
  }
  public Page<User> searchUsers(String keyword, int pageNum, int pageSize) {
    return PageUtil.paginate(
    UserMapper.class,
    (mapper, rowBounds) -> mapper.search(keyword, rowBounds),
    pageNum,
    pageSize,
    mapper -> mapper.searchCount(keyword)
    );
    }
    }

5. 配置工具类

5.1 动态数据源工具类

package com.example.util;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 动态数据源工具类
*/
public class DynamicDataSourceUtil {
private static final ThreadLocal<String> DATA_SOURCE_CONTEXT = new ThreadLocal<>();
  private static final Map<String, SqlSessionFactory> FACTORY_MAP = new ConcurrentHashMap<>();
    /**
    * 设置当前线程的数据源
    */
    public static void setDataSource(String dataSourceName) {
    DATA_SOURCE_CONTEXT.set(dataSourceName);
    }
    /**
    * 获取当前线程的数据源
    */
    public static String getDataSource() {
    return DATA_SOURCE_CONTEXT.get();
    }
    /**
    * 清除数据源设置
    */
    public static void clearDataSource() {
    DATA_SOURCE_CONTEXT.remove();
    }
    /**
    * 注册数据源
    */
    public static void registerDataSource(String name, SqlSessionFactory factory) {
    FACTORY_MAP.put(name, factory);
    }
    /**
    * 获取当前数据源的 SqlSessionFactory
    */
    public static SqlSessionFactory getCurrentSqlSessionFactory() {
    String dataSourceName = getDataSource();
    if (dataSourceName == null) {
    dataSourceName = "default";
    }
    SqlSessionFactory factory = FACTORY_MAP.get(dataSourceName);
    if (factory == null) {
    throw new IllegalArgumentException("未找到数据源: " + dataSourceName);
    }
    return factory;
    }
    /**
    * 在指定数据源中执行操作
    */
    public static <T> T executeInDataSource(String dataSourceName, DataSourceCallback<T> callback) {
      String previousDataSource = getDataSource();
      try {
      setDataSource(dataSourceName);
      return callback.execute();
      } finally {
      if (previousDataSource != null) {
      setDataSource(previousDataSource);
      } else {
      clearDataSource();
      }
      }
      }
      }
      @FunctionalInterface
      interface DataSourceCallback<T> {
        T execute();
        }

5.2 使用示例

public class MultiDataSourceService {
public void syncUserData(Long userId) {
// 从主库读取
User user = DynamicDataSourceUtil.executeInDataSource("master", () -> {
try (SqlSession sqlSession = DynamicDataSourceUtil.getCurrentSqlSessionFactory().openSession()) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectById(userId);
}
});
// 写入从库
DynamicDataSourceUtil.executeInDataSource("slave", () -> {
try (SqlSession sqlSession = DynamicDataSourceUtil.getCurrentSqlSessionFactory().openSession()) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.insertOrUpdate(user);
sqlSession.commit();
}
return null;
});
}
}

6. 最佳实践总结

6.1 工具类设计原则

  1. 单一职责:每个工具类只负责一个特定功能
  2. 线程安全:确保在多线程环境下安全使用
  3. 资源管理:自动管理 SqlSession 等资源的生命周期
  4. 异常处理:提供统一的异常处理机制
  5. 灵活扩展:支持自定义回调函数

6.2 配置文件示例

<!-- mybatis-config.xml -->
  <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
      <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="true"/>
      </settings>
      <typeAliases>
        <package name="com.example.entity"/>
      </typeAliases>
      <plugins>
        <!-- 可以添加分页插件、性能监控插件等 -->
        </plugins>
      </configuration>
posted on 2025-11-09 12:43  blfbuaa  阅读(2)  评论(0)    收藏  举报