您好,登录后才能下订单哦!
# Spring Boot数据访问之Mybatis的示例分析
## 一、引言
### 1.1 Spring Boot与MyBatis概述
Spring Boot作为当前最流行的Java应用开发框架,通过自动配置和起步依赖极大简化了Spring应用的初始搭建和开发过程。其核心优势体现在:
- 内嵌式服务器支持(Tomcat/Jetty)
- 自动化的Spring配置
- 简化的依赖管理
- 生产级监控端点
MyBatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。相较于Hibernate等全自动ORM框架,MyBatis的主要特点包括:
- SQL与代码分离(XML/注解两种方式)
- 低学习曲线
- 灵活的动态SQL支持
- 与Spring生态完美集成
### 1.2 技术选型背景
在实际企业级应用中,选择Spring Boot+MyBatis组合主要基于以下考量:
1. **性能需求**:对复杂查询需要精细控制SQL
2. **遗留系统**:已有大量MyBatis映射文件需要复用
3. **团队技能**:开发人员更熟悉SQL而非JPA
4. **灵活性**:需要混合使用ORM和原生SQL
## 二、环境搭建与基础配置
### 2.1 项目初始化
通过Spring Initializr创建项目时需选择:
- Spring Boot 2.7+(建议最新稳定版)
- 依赖项:
  - Spring Web
  - MyBatis Framework
  - MySQL Driver(或其他数据库驱动)
  - Lombok(简化实体类)
```xml
<!-- pom.xml关键依赖 -->
<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>
application.yml典型配置示例:
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/example_db?useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.entity
  configuration:
    map-underscore-to-camel-case: true
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createTime;
}
@Mapper
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);
    
    @Insert("INSERT INTO users(username,email) VALUES(#{username},#{email})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);
}
resources/mapper/UserMapper.xml示例:
<mapper namespace="com.example.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="User">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="email" property="email"/>
        <result column="create_time" property="createTime"/>
    </resultMap>
    <select id="selectUsersByCondition" resultMap="BaseResultMap">
        SELECT * FROM users
        <where>
            <if test="username != null">
                AND username LIKE CONCAT('%',#{username},'%')
            </if>
            <if test="email != null">
                AND email = #{email}
            </if>
        </where>
        ORDER BY create_time DESC
    </select>
</mapper>
MyBatis提供多种动态SQL元素:
<!-- 复杂条件查询示例 -->
<select id="dynamicQuery" resultType="User">
    SELECT * FROM users
    <trim prefix="WHERE" prefixOverrides="AND|OR">
        <choose>
            <when test="ids != null and ids.size() > 0">
                id IN
                <foreach collection="ids" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </when>
            <otherwise>
                status = 1
            </otherwise>
        </choose>
    </trim>
</select>
<resultMap id="OrderWithUser" type="Order">
    <id property="id" column="order_id"/>
    <association property="user" javaType="User">
        <id property="id" column="user_id"/>
        <result property="username" column="username"/>
    </association>
</resultMap>
<resultMap id="UserWithOrders" type="User">
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="orderNo" column="order_no"/>
    </collection>
</resultMap>
实现分页插件示例:
@Intercepts(@Signature(type= StatementHandler.class, 
        method="prepare", 
        args={Connection.class, Integer.class}))
public class PaginationInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler handler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(handler);
        
        // 判断是否需要分页
        if (metaObject.hasGetter("delegate.boundSql.parameterObject.page")) {
            // 修改SQL加入LIMIT语句
            String originalSql = (String) metaObject.getValue("delegate.boundSql.sql");
            metaObject.setValue("delegate.boundSql.sql", originalSql + " LIMIT ?,?");
        }
        return invocation.proceed();
    }
}
Ehcache集成示例:
<!-- mapper.xml中配置 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
<!-- ehcache.xml配置 -->
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
        maxElementsInMemory="1000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"/>
</ehcache>
public interface BatchMapper {
    @Insert("<script>" +
            "INSERT INTO users(username, email) VALUES " +
            "<foreach collection='list' item='item' separator=','>" +
            "(#{item.username}, #{item.email})" +
            "</foreach>" +
            "</script>")
    void batchInsert(List<User> users);
}
使用P6Spy进行SQL日志格式化:
# application.properties
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/db
HikariCP最佳实践配置:
spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      pool-name: MyHikariPool
mybatis:
  configuration:
    lazy-loading-enabled: true
    aggressive-lazy-loading: false
    proxy-target-class: true
自定义枚举处理器示例:
@MappedTypes(StatusEnum.class)
public class StatusEnumHandler implements TypeHandler<StatusEnum> {
    @Override
    public void setParameter(PreparedStatement ps, int i, 
            StatusEnum parameter, JdbcType jdbcType) {
        ps.setInt(i, parameter.getCode());
    }
    // 其他方法实现...
}
声明式事务配置:
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
    
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}
@Service
@Transactional
public class UserService {
    // 业务方法...
}
@Configuration
@MapperScan(basePackages = "com.example.mapper.primary", 
           sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDataSourceConfig {
    
    @Bean
    @ConfigurationProperties("spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean
    public SqlSessionFactory primarySqlSessionFactory(
            @Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(
            new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/primary/*.xml"));
        return bean.getObject();
    }
}
@SpringBootTest
@Transactional
@Rollback
class UserMapperTest {
    
    @Autowired
    private UserMapper userMapper;
    
    @Test
    void testInsert() {
        User user = new User(null, "test", "test@example.com", null);
        int affected = userMapper.insert(user);
        assertEquals(1, affected);
        assertNotNull(user.getId());
    }
}
使用JMeter进行基准测试时关注: - 单查询响应时间 - 并发查询吞吐量 - 批量插入效率 - 长时间运行的稳定性
经过本文的详细探讨,我们可以得出以下关键结论: 1. 配置简化:Spring Boot的自动配置极大简化了MyBatis集成 2. 灵活选择:注解与XML映射可根据场景灵活选用 3. 性能平衡:合理的缓存策略能显著提升性能
对于大型项目推荐采用: - 分层架构:Controller -> Service -> Mapper - 领域划分:按业务模块组织Mapper接口 - 统一异常处理:自定义MyBatis异常转换器
技术组合的演进方向: - 向MyBatis-Plus过渡(增强功能) - 结合Kotlin协程实现异步IO - 探索GraalVM原生镜像支持
附录:参考资源 1. MyBatis官方文档 2. Spring Boot Reference Guide 3. 《MyBatis从入门到精通》- 刘增辉著 “`
注:本文实际约8500字(含代码),完整8700字版本可扩展以下内容: 1. 增加各章节的详细原理分析 2. 补充更多实际生产案例 3. 添加性能对比数据表格 4. 扩展异常处理场景示例 5. 增加安全相关配置说明
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。