MyBatis 框架全面指南
1. 概述
MyBatis 是一个优秀的持久层框架,它简化了 Java 应用程序与关系型数据库之间的交互。与传统的 JDBC 相比,MyBatis 通过 XML 或注解的方式将 SQL 语句与 Java 对象进行映射,避免了大量样板代码,同时保持了 SQL 的灵活性和可控制性。
核心优势:
- SQL 与代码分离,便于维护
- 减少数据转换工作量
- 保留 SQL 的完整控制权
- 支持动态 SQL
- 内置缓存机制
- 轻量级,学习曲线平缓
2. 安装与配置
2.1 安装方式
传统方式:
- 将 mybatis-x.x.x.jar 文件置于类路径(classpath)中
Maven 依赖:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
Gradle 依赖:
implementation 'org.mybatis:mybatis:x.x.x'
2.2 版本选择
根据 GitHub Releases 信息,MyBatis 3.5.19 是最新稳定版本(截至知识库更新时间)。需要注意:
- 3.5.18 是最后一个支持 Java 8 的版本
- 之后的版本将逐步升级到 Java 11 和 Java 17
- 新项目应根据 JDK 版本选择合适的 MyBatis 版本
版本选择建议:
- 评估功能需求、社区支持、性能表现、学习曲线和维护状态
- 优先选择 LTS (长期支持) 版本
- 避免使用已停止维护的版本
- 新项目可考虑较新的稳定版本
3. 核心架构与组件
3.1 核心组件
- SqlSessionFactoryBuilder:用于创建 SqlSessionFactory,方法作用域
- SqlSessionFactory:创建 SqlSession 的工厂类,应用作用域
- SqlSession:执行 SQL 命令的主要接口,请求/方法作用域
- Mapper 接口:定义数据库操作方法,方法作用域
- Mapper XML:包含 SQL 语句的配置文件
3.2 工作流程
- 通过 SqlSessionFactoryBuilder 创建 SqlSessionFactory
- SqlSessionFactory 创建 SqlSession
- SqlSession 获取 Mapper 接口实例
- 调用 Mapper 方法执行数据库操作
- 提交事务并关闭 SqlSession
4. 配置详解
4.1 主配置文件 (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"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
4.2 从 XML 构建 SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
4.3 无 XML 配置方式
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
5. 基本使用
5.1 获取 SqlSession
try (SqlSession session = sqlSessionFactory.openSession()) {
// 执行数据库操作
}
5.2 执行查询
方式一:直接使用 SqlSession
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
方式二:通过 Mapper 接口(推荐)
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
5.3 执行插入/更新/删除
User user = new User();
user.setName("张三");
user.setEmail("zhangsan@example.com");
int rows = mapper.insertUser(user);
session.commit(); // 提交事务
6. 映射配置
6.1 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="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
SELECT * FROM Blog WHERE id = #{id}
</select>
<insert id="insertUser" parameterType="User">
INSERT INTO users(name, email) VALUES(#{name}, #{email})
</insert>
</mapper>
6.2 注解方式
package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
@Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertUser(User user);
}
注解与 XML 选择建议:
- 简单语句:使用注解更简洁
- 复杂语句:XML 提供更好的可读性和维护性
- 团队可根据情况统一规范
7. 动态 SQL
7.1 常用动态 SQL 元素
if 元素:
<select parameterType="map" resultType="User">
SELECT * FROM users
WHERE 1=1
<if test="name != null">
AND name = #{name}
</if>
<if test="email != null">
AND email = #{email}
</if>
</select>
choose/when/otherwise 元素:
<select parameterType="map" resultType="User">
SELECT * FROM users
WHERE status = 'ACTIVE'
<choose>
<when test="name != null">
AND name like #{name}
</when>
<when test="email != null">
AND email = #{email}
</when>
<otherwise>
AND 1=1
</otherwise>
</choose>
</select>
foreach 元素:
<select parameterType="list" resultType="User">
SELECT * FROM users
WHERE id IN
<foreach item="id" collection="list" open="(" separator="," close=")">
#{id}
</foreach>
</select>
7.2 其他动态 SQL 元素
- trim:自定义前缀、后缀和去除字符
- where:智能处理 WHERE 子句
- set:智能处理 UPDATE 语句中的 SET 子句
- bind:创建变量绑定
8. 关联查询
8.1 一对一关联
<resultMap type="User" id="userWithAddress">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<association property="address" javaType="Address">
<id property="id" column="address_id"/>
<result property="street" column="street"/>
<result property="city" column="city"/>
</association>
</resultMap>
<select id="selectUserWithAddress" resultMap="userWithAddress">
SELECT
u.id as user_id, u.name as user_name,
a.id as address_id, a.street, a.city
FROM users u
LEFT JOIN addresses a ON u.address_id = a.id
WHERE u.id = #{id}
</select>
8.2 一对多关联
<resultMap type="User" id="userWithOrders">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<collection property="orders" ofType="Order">
<id property="id" column="order_id"/>
<result property="orderDate" column="order_date"/>
<result property="amount" column="amount"/>
</collection>
</resultMap>
<select id="selectUserWithOrders" resultMap="userWithOrders">
SELECT
u.id as user_id, u.name as user_name,
o.id as order_id, o.order_date, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = #{id}
</select>
9. 缓存机制
9.1 一级缓存
- 作用范围:SqlSession 级别(默认开启,不可关闭) — 同一个session
- 生命周期:随 SqlSession 创建而创建,随 SqlSession 关闭而销毁
- 触发清空的情况:
- 执行 INSERT/UPDATE/DELETE 操作
- 调用 sqlSession.clearCache()
- 执行事务回滚
- 配置不同的 Statement ID
@Test
public void findBookById(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Book book=sqlSession.selectOne( "getBookById",1);
System.out.println(book);
Book book1=sqlSession.selectOne( "getBookById",1);
System.out.println(book1);
sqlSession.close();
}
// 示例:相同查询在同一个SqlSession中只执行一次
User user1 = sqlSession.selectOne("getUserById", 1); // 执行SQL
User user2 = sqlSession.selectOne("getUserById", 1); // 从缓存获取
2025-10-20 10:45:26,508 [main] DEBUG com.itheima.mapper.BookMapper – Cache Hit Ratio [com.itheima.mapper.BookMapper]: 0.0
2025-10-20 10:45:26,767 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – ==> Preparing: select * from tb_book where id = ?
2025-10-20 10:45:26,820 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – ==> Parameters: 1(Integer)
2025-10-20 10:45:26,873 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – <== Total: 1
Book{id=1, name='null', price=99.9, author='小刚'}
2025-10-20 10:45:26,880 [main] DEBUG com.itheima.mapper.BookMapper – Cache Hit Ratio [com.itheima.mapper.BookMapper]: 0.0
Book{id=1, name='null', price=99.9, author='小刚'}
//更新了就不会触发缓存
@Test
public void findBookById1(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Book book=sqlSession.selectOne( "getBookById",1);
System.out.println(book);
Book book2=new Book();
book2.setId(3);
book2.setAuthor("Jeek");
book2.setPrice(0.2);
sqlSession.update("updateBook",book2);
sqlSession.commit();
Book book3=sqlSession.selectOne( "getBookById",3);
System.out.println(book3);
sqlSession.close();
}
2025-10-20 10:46:43,588 [main] DEBUG com.itheima.mapper.BookMapper – Cache Hit Ratio [com.itheima.mapper.BookMapper]: 0.0
2025-10-20 10:46:43,834 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – ==> Preparing: select * from tb_book where id = ?
2025-10-20 10:46:43,891 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – ==> Parameters: 1(Integer)
2025-10-20 10:46:43,947 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – <== Total: 1
Book{id=1, name='null', price=99.9, author='小刚'}
2025-10-20 10:46:43,955 [main] DEBUG com.itheima.mapper.BookMapper.updateBook – ==> Preparing: update tb_book set author=?, price=? where id = ?
2025-10-20 10:46:43,960 [main] DEBUG com.itheima.mapper.BookMapper.updateBook – ==> Parameters: Jeek(String), 0.2(Double), 3(Integer)
2025-10-20 10:46:43,961 [main] DEBUG com.itheima.mapper.BookMapper.updateBook – <== Updates: 1
2025-10-20 10:46:43,963 [main] DEBUG com.itheima.mapper.BookMapper – Cache Hit Ratio [com.itheima.mapper.BookMapper]: 0.0
2025-10-20 10:46:43,963 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – ==> Preparing: select * from tb_book where id = ?
2025-10-20 10:46:43,963 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – ==> Parameters: 3(Integer)
2025-10-20 10:46:43,964 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – <== Total: 1
Book{id=3, name='null', price=0.2, author='Jeek'}
9.2 二级缓存
— 不同session
@Test
public void findBookById2(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Book book=sqlSession.selectOne( "getBookById",1);
System.out.println(book);
sqlSession.close();
SqlSession sqlSession1= MyBatisUtils.getSqlSession();
Book book1=sqlSession1.selectOne( "getBookById",1);
System.out.println(book1);
sqlSession1.close();
}
启用配置:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
Mapper 级别配置:
<cache
eviction="LRU" <!– 淘汰策略(默认LRU) –>
flushInterval="60000" <!– 刷新间隔(毫秒) –>
size="512" <!– 缓存对象数量 –>
readOnly="true"/> <!– 只读模式(性能更优) –>
<?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.itheima.mapper.BookMapper">
<cache/>
<!– 开启缓存–>
<select id="getBookById" parameterType="Integer" resultType="Book">
select *
from tb_book
where id = #{id}
</select>
<!– <insert id="" parameterType="">–>
<!– </insert>–>
<update id="updateBook" parameterType="Book">
update tb_book
set author=#{author},
price=#{price}
where id = #{id}
</update>
<!– <delete id="" parameterType="">–>
<!– </delete>–>
</mapper>
2025-10-20 10:42:57,049 [main] DEBUG com.itheima.mapper.BookMapper – Cache Hit Ratio [com.itheima.mapper.BookMapper]: 0.0
2025-10-20 10:42:57,300 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – ==> Preparing: select * from tb_book where id = ?
2025-10-20 10:42:57,353 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – ==> Parameters: 1(Integer)
2025-10-20 10:42:57,409 [main] DEBUG com.itheima.mapper.BookMapper.getBookById – <== Total: 1
Book{id=1, name='null', price=99.9, author='小刚'}
2025-10-20 10:42:57,438 [main] DEBUG com.itheima.mapper.BookMapper – Cache Hit Ratio [com.itheima.mapper.BookMapper]: 0.5
Book{id=1, name='null', price=99.9, author='小刚'}
第二次查询命中二级缓存
缓存策略对比:
| 策略 | 描述 | 适用场景 |
| LRU | 最近最少使用 | 常规使用 |
| FIFO | 先进先出 | 固定顺序访问 |
| SOFT | 软引用 | 内存敏感场景 |
| WEAK | 弱引用 | 内存极度敏感 |
10. 与 Spring 集成
10.1 依赖配置
Spring Boot 推荐方式:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
传统 Spring 项目:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
10.2 配置方案
方案一:Spring Boot 自动配置(最简单)
# application.yml
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.example.model
configuration:
map-underscore-to-camel-case: true # 自动驼峰转换
方案二:Java Config 全配置(精细化控制)
@Configuration
public class MyBatisConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setTypeAliasesPackage("com.example.model");
// 自定义配置
org.apache.ibatis.session.Configuration config = new Configuration();
config.setMapUnderscoreToCamelCase(true);
config.setDefaultFetchSize(100);
factory.setConfiguration(config);
// 插件配置
factory.setPlugins(
new MyBatisInterceptor(),
new PaginationInterceptor()
);
return factory.getObject();
}
@Bean
public MapperScannerConfigurer mapperScanner() {
MapperScannerConfigurer scanner = new MapperScannerConfigurer();
scanner.setBasePackage("com.example.mapper");
scanner.setAnnotationClass(Repository.class);
return scanner;
}
}
方案三:XML 传统配置(兼容旧项目)
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper"/>
</bean>
10.3 事务管理
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// 可定义事务模板
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager manager) {
return new TransactionTemplate(manager);
}
}
10.4 使用规范
Mapper 接口示例:
@Repository
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User selectById(@Param("id") int id);
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("INSERT INTO users(name) VALUES(#{name})")
int insert(User user);
}
Service 层示例:
@Service
@Transactional(readOnly = true)
public class UserService {
private final UserMapper userMapper;
@Autowired
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Transactional
public User createUser(String name) {
User user = new User();
user.setName(name);
userMapper.insert(user);
return userMapper.selectById(user.getId());
}
}
10.5 高级功能
动态数据源配置:
@Bean
@Primary
public DataSource dynamicDataSource() {
DynamicDataSource ds = new DynamicDataSource();
ds.setDefaultTargetDataSource(primaryDataSource());
ds.setTargetDataSources(Map.of(
"master", primaryDataSource(),
"slave", secondaryDataSource()
));
return ds;
}
11. 最佳实践
11.1 代码规范
- 使用 Mapper 接口:比直接使用 SqlSession 更类型安全,更易维护
- 命名空间规范:使用 Java 包命名规范,如 com.example.mapper.UserMapper
- SQL 语句命名:使用动词+名词形式,如 selectUserById
- 参数命名:使用 @Param 注解明确参数名称
11.2 性能优化
- 合理使用缓存:
- 读多写少的场景使用二级缓存
- 注意缓存一致性问题
- 批量操作:
- 使用 ExecutorType.BATCH 提高批量操作性能
- 避免一次性处理过多数据
- SQL 优化:
- 避免 SELECT *,只查询需要的字段
- 合理使用索引
- 分页查询使用合理的分页方式
11.3 常见问题解决方案
- N+1 查询问题:
- 使用 JOIN 一次性查询
- 使用 @Select 注解的 fetchType 属性
- 使用 LazyLoadingEnabled 配置
- 驼峰命名转换:
- 启用 mapUnderscoreToCamelCase 配置
- 确保数据库字段使用下划线命名法
- 事务管理:
- 明确事务边界
- 避免在事务方法中调用非事务方法
- 合理设置事务超时时间
12. 版本更新要点
MyBatis 3.5.18-3.5.19 主要更新
- 3.5.19:修复了 3.5.17 中引入的回归问题
- 3.5.18:
- 修复 #3334 问题
- 忽略空的 xnode
- 共享表达式验证器
- 优化 mapper 构建器
- 构建系统更新:支持 Java 17 构建
重要提示:3.5.18 是最后一个支持 Java 8 的版本,后续版本将逐步升级到 Java 11 和 Java 17。
13. 总结
MyBatis 作为一款轻量级持久层框架,提供了 SQL 与代码分离、自动映射、动态 SQL 和缓存机制等核心功能,同时保持了对 SQL 的完全控制权。它既不像传统 JDBC 那样繁琐,也不像全自动 ORM 框架那样失去对 SQL 的控制,是一种平衡性极佳的解决方案。
使用建议:
- 新项目优先考虑 MyBatis 与 Spring Boot 的整合方案
- 根据项目复杂度选择 XML 或注解方式
- 重视命名规范和代码结构
- 合理使用缓存提高性能
- 遵循作用域和生命周期的最佳实践
通过合理使用 MyBatis,可以显著提高开发效率,同时保证应用程序的性能和可维护性。
resources/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>
<properties resource="db.properties"/>
<settings>
<!– 开启二级缓存–>
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases>
<package name="com.itheima.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/StudentMapper.xml"/>
<mapper resource="mapper/CustomerMapper.xml"/>
<mapper resource="mapper/PersonMapper.xml"/>
<mapper resource="mapper/IdCardMapper.xml"/>
<mapper resource="mapper/UsersMapper.xml"/>
<mapper resource="mapper/OrdersMapper.xml"/>
<mapper resource="mapper/ProductMapper.xml"/>
<mapper resource="mapper/BookMapper.xml"/>
</mappers>
</configuration>
resources/mapper/BookMapper.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.itheima.mapper.BookMapper">
<cache/>
<!– 开启缓存–>
<select id="getBookById" parameterType="Integer" resultType="Book">
select *
from tb_book
where id = #{id}
</select>
<!– <insert id="" parameterType="">–>
<!– </insert>–>
<update id="updateBook" parameterType="Book">
update tb_book
set author=#{author},
price=#{price}
where id = #{id}
</update>
<!– <delete id="" parameterType="">–>
<!– </delete>–>
</mapper>
resources/mapper/CustomerMapper.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.itheima.mapper.CustomerMapper">
<select id="findCustomerById" parameterType="com.itheima.pojo.Customer" resultType="com.itheima.pojo.Customer">
select * from t_customer where 1=1
<if test="username!=null and username !="">
and username like concat('%',#{username},'%')
</if>
<if test="jobs!=null and jobs!="">
and jobs=#{jobs}
</if>
</select>
<select id="findCustomerByNameOrJobs" parameterType="com.itheima.pojo.Customer"
resultType="com.itheima.pojo.Customer">
select * from t_customer where 1=1
<choose>
<when test="username!=null and username != "">
and username like concat('%',#{username},'%')
</when>
<when test="jobs!=null and jobs != "">
and jobs like concat('%',#{username},'%')
</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
</select>
<select id="findCustomerByNameOrJobs2" parameterType="com.itheima.pojo.Customer"
resultType="com.itheima.pojo.Customer">
select * from t_customer
<trim prefix="where" prefixOverrides="and">
<if test="username!=null and username != "">
and username like concat('%',#{username},'%')
</if>
<if test="jobs!=null and jobs != "">
and jobs=#{jobs}
</if>
</trim>
</select>
<select id="findCustomerByNameAndJobs" parameterType="com.itheima.pojo.Customer"
resultType="com.itheima.pojo.Customer">
select * from t_customer
<where>
<if test="username!=null and username !="">
and username like concat('%',#{username},'%')
</if>
<if test="jobs!=null and jobs!="">
and jobs=#{jobs}
</if>
</where>
</select>
<select id="findCustomerByArray" resultType="com.itheima.pojo.Customer">
SELECT * FROM t_customer
<where>
<if test="array != null and array.length > 0">
id IN
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</if>
</where>
</select>
<!– <select id="findCustomerByArray" resultType="com.itheima.pojo.Customer">–>
<!– SELECT * FROM t_customer–>
<!– <where>–>
<!– <if test="array != null and array.length > 0">–>
<!– id IN–>
<!– <foreach item="id" collection="array" open="(" separator="," close=")">–>
<!– #{id}–>
<!– </foreach>–>
<!– </if>–>
<!– </where>–>
<!– </select>–>
<select id="findByList" parameterType="java.util.List" resultType="com.itheima.pojo.Customer">
select * from t_customer where id in
<foreach collection="list" item="id" index="index" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="findByMap" parameterType="java.util.Map" resultType="com.itheima.pojo.Customer">
select * from t_customer where id in
<foreach collection="list" item="roleMap" index="index" open="(" separator="," close=")">
#{roleMap}
</foreach>
</select>
<!– <insert id="" parameterType="">–>
<!– </insert>–>
<update id="updateCustomerBySet" parameterType="com.itheima.pojo.Customer">
update t_customer
<set>
<if test="username!=null and username !="">
username=#{username},
</if>
<if test="jobs!=null and jobs !="">
jobs=#{jobs},
</if>
<if test="phone!=null and phone !="">
phone=#{phone},
</if>
</set>
where id=#{id}
</update>
<!– <delete id="" parameterType="">–>
<!– </delete>–>
</mapper>
resources/mapper/OrdersMapper.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.itheima.mapper.OrdersMapper">
<select id="getOrdersByUserId" parameterType="Integer" resultMap="ordersWithProductResult">
select *
from tb_orders
where id = #{id}
</select>
<resultMap id="ordersWithProductResult" type="Orders">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<collection property="productList" ofType="Product"
select="com.itheima.mapper.ProductMapper.getProductById"
column="id"/>
</resultMap>
<!– <insert id="" parameterType="">–>
<!– </insert>–>
<!– <update id="" parameterType="">–>
<!– </update>–>
<!– <delete id="" parameterType="">–>
<!– </delete>–>
</mapper>
resources/mapper/UsersMapper.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.itheima.mapper.UsersMapper">
<!– 用户订单查询 –>
<select id="getUserWithOrders" parameterType="Integer" resultMap="userOrderResultMap">
SELECT
u.id,
u.username,
u.address,
o.id AS order_id,
o.number
FROM tb_user u
LEFT JOIN tb_orders o ON u.id = o.user_id
WHERE u.id = #{id}
</select>
<!– 用户与订单映射关系 –>
<resultMap id="userOrderResultMap" type="com.itheima.pojo.Users">
<!– 主键映射(必须放在最前面) –>
<id property="id" column="id"/>
<!– 普通字段映射 –>
<result property="name" column="name"/>
<result property="address" column="address"/>
<!– 订单集合映射(关键修复:正确闭合标签) –>
<collection
property="orders"
javaType="java.util.ArrayList"
ofType="com.itheima.pojo.Orders">
<!– 订单主键 –>
<id property="id" column="order_id"/>
<!– 订单其他字段 –>
<result property="number" column="number"/>
</collection>
</resultMap>
<!– 身份证与人员映射(修复顺序问题) –>
<resultMap id="IdCardWithPersonResult" type="com.itheima.pojo.IdCard">
<!– 主键必须放在最前面 –>
<id property="id" column="id"/>
<!– 普通字段 –>
<result property="code" column="code"/>
<!– 关联对象 –>
<association
property="person"
javaType="com.itheima.pojo.Person">
<id property="id" column="person_id"/>
<result property="name" column="person_name"/>
<result property="age" column="person_age"/>
</association>
</resultMap>
</mapper>
resources/db.properties
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
mysql.username=root
mysql.password=123456
resources/log4j.properties
log4j.rootLogger=DEBUG, Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p %c – %m%n
log4j.logger.java.sql.Result=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
src/test/java/MybatisTest.java
import com.itheima.pojo.*;
import com.itheima.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MybatisTest {
@Test
public void testFindCustomerById(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Customer customer=new Customer();
List<Customer> list =sqlSession.selectList("findCustomerById",customer);
for(Customer c:list){
System.out.println(c);
}
sqlSession.close();
}
@Test
public void testfindCustomerByNameOrJobs(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Customer customer=new Customer();
List<Customer> list =sqlSession.selectList("findCustomerByNameOrJobs2",customer);
for(Customer c:list){
System.out.println(c);
}
sqlSession.close();
}
@Test
public void testfindCustomerByArray(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
int[] ids=new int[]{1,2};
List<Customer> list =sqlSession.selectList("findCustomerByArray",ids);
for(Customer c:list){
System.out.println(c);
}
sqlSession.close();
}
@Test
public void testfindCustomerByList(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
List<Integer> ids=new ArrayList<>();
ids.add(2);
ids.add(3);
List<Customer> list =sqlSession.selectList("findByList",ids);
for(Customer c:list){
System.out.println(c);
}
sqlSession.close();
}
@Test
public void testfindCustomerByMap(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
List<Integer> ids=new ArrayList<>();
ids.add(2);
ids.add(3);
Map<String,Object> map=new HashMap<String,Object>();
map.put("id",ids);
map.put("jobs","teacher");
List<Customer> list =sqlSession.selectList("findByMap",map);
for(Customer c:list){
System.out.println(c);
}
sqlSession.close();
}
@Test
public void updateCustomerById(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Customer customer=new Customer();
customer.setId(1);
customer.setUsername("marry");
int count=sqlSession.update("updateCustomerBySet",customer);
if(count>0){
System.out.println("Success");
}else {
System.out.println("Fail");
}
sqlSession.commit();
sqlSession.close();
}
@Test
public void findPersonById(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Person person=sqlSession.selectOne( "getPersonById2",1);
System.out.println(person);
sqlSession.close();
}
@Test
public void findUsersById(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Users users=sqlSession.selectOne( "getUserWithOrders",1);
System.out.println(users);
sqlSession.close();
}
@Test
public void getProductById(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Orders orders=sqlSession.selectOne( "getOrdersByUserId",1);
System.out.println(orders);
sqlSession.close();
}
@Test
public void findBookById(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Book book=sqlSession.selectOne( "getBookById",1);
System.out.println(book);
Book book1=sqlSession.selectOne( "getBookById",1);
System.out.println(book1);
sqlSession.close();
}
@Test
public void findBookById1(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Book book=sqlSession.selectOne( "getBookById",1);
System.out.println(book);
Book book2=new Book();
book2.setId(3);
book2.setAuthor("Jeek");
book2.setPrice(0.2);
sqlSession.update("updateBook",book2);
sqlSession.commit();
Book book3=sqlSession.selectOne( "getBookById",3);
System.out.println(book3);
sqlSession.close();
}
@Test
public void findBookById2(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
Book book=sqlSession.selectOne( "getBookById",1);
System.out.println(book);
sqlSession.close();
SqlSession sqlSession1= MyBatisUtils.getSqlSession();
Book book1=sqlSession1.selectOne( "getBookById",1);
System.out.println(book1);
sqlSession1.close();
}
@Test
public void findBookById3(){
SqlSession sqlSession= MyBatisUtils.getSqlSession();
SqlSession sqlSession1= MyBatisUtils.getSqlSession();
SqlSession sqlSession2= MyBatisUtils.getSqlSession();
Book book=sqlSession.selectOne( "getBookById",1);
System.out.println(book);
Book book3=sqlSession1.selectOne( "getBookById",1);
System.out.println(book3);
sqlSession.close();
Book book2=new Book();
book2.setId(3);
book2.setAuthor("Jeek");
book2.setPrice(0.2);
sqlSession.update("updateBook",book2);
sqlSession.commit();
Book book1=sqlSession2.selectOne( "getBookById",1);
System.out.println(book1);
sqlSession1.close();
}
}