MyBatis框架详解 MyBatis简介 MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的工作。MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO(Plain Old Java Objects)为数据库中的记录。
与其他ORM框架相比,MyBatis更加灵活,允许开发者直接编写SQL语句,这在处理复杂查询时特别有用。
MyBatis的主要特性
简单易学:MyBatis的基本概念简单明了,上手快
灵活的SQL操作:支持自定义SQL语句,而不是自动生成
支持动态SQL:可以根据不同条件构建不同的SQL
支持存储过程:可以调用数据库中的存储过程
支持高级映射:包括一对一、一对多、多对一等复杂映射关系
缓存机制:提供一级缓存和二级缓存,提高查询效率
MyBatis的基本工作流程
通过SqlSessionFactoryBuilder从XML配置文件或Configuration类创建SqlSessionFactory
通过SqlSessionFactory获取SqlSession实例
使用SqlSession执行SQL操作
关闭SqlSession
MyBatis的基本使用 添加依赖 Maven项目中添加依赖:
1 2 3 4 5 6 7 8 9 10 11 12 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.7</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.26</version > </dependency >
配置MyBatis 创建mybatis-config.xml
文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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 > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/testdb?useSSL=false& serverTimezone=UTC" /> <property name ="username" value ="root" /> <property name ="password" value ="password" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/example/mapper/UserMapper.xml" /> </mappers > </configuration >
创建实体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package com.example.entity;public class User { private Long id; private String username; private String email; private Integer age; public User () {} public User (Long id, String username, String email, Integer age) { this .id = id; this .username = username; this .email = email; this .age = age; } public Long getId () { return id; } public void setId (Long id) { this .id = id; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getEmail () { return email; } public void setEmail (String email) { this .email = email; } public Integer getAge () { return age; } public void setAge (Integer age) { this .age = age; } @Override public String toString () { return "User{" + "id=" + id + ", username='" + username + '\'' + ", email='" + email + '\'' + ", age=" + age + '}' ; } }
创建Mapper接口 1 2 3 4 5 6 7 8 9 10 11 12 package com.example.mapper;import com.example.entity.User;import java.util.List;public interface UserMapper { User getUserById (Long id) ; List<User> getAllUsers () ; void insertUser (User user) ; void updateUser (User user) ; void deleteUser (Long id) ; }
创建Mapper XML文件 创建UserMapper.xml
文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <?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.example.mapper.UserMapper" > <resultMap id ="UserResultMap" type ="com.example.entity.User" > <id property ="id" column ="id" /> <result property ="username" column ="username" /> <result property ="email" column ="email" /> <result property ="age" column ="age" /> </resultMap > <select id ="getUserById" parameterType ="long" resultMap ="UserResultMap" > SELECT id, username, email, age FROM users WHERE id = #{id} </select > <select id ="getAllUsers" resultMap ="UserResultMap" > SELECT id, username, email, age FROM users </select > <insert id ="insertUser" parameterType ="com.example.entity.User" useGeneratedKeys ="true" keyProperty ="id" > INSERT INTO users (username, email, age) VALUES (#{username}, #{email}, #{age}) </insert > <update id ="updateUser" parameterType ="com.example.entity.User" > UPDATE users SET username = #{username}, email = #{email}, age = #{age} WHERE id = #{id} </update > <delete id ="deleteUser" parameterType ="long" > DELETE FROM users WHERE id = #{id} </delete > </mapper >
使用MyBatis执行操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package com.example;import com.example.entity.User;import com.example.mapper.UserMapper;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.List;public class MyBatisExample { public static void main (String[] args) { try { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); User newUser = new User (null , "张三" , "zhangsan@example.com" , 28 ); userMapper.insertUser(newUser); session.commit(); System.out.println("插入用户ID: " + newUser.getId()); User user = userMapper.getUserById(newUser.getId()); System.out.println("查询到用户: " + user); user.setAge(30 ); userMapper.updateUser(user); session.commit(); List<User> users = userMapper.getAllUsers(); System.out.println("所有用户:" ); for (User u : users) { System.out.println(u); } userMapper.deleteUser(user.getId()); session.commit(); } } catch (IOException e) { e.printStackTrace(); } } }
MyBatis动态SQL MyBatis的一个强大特性是支持动态SQL,可以根据不同条件生成不同的SQL语句。
if语句 1 2 3 4 5 6 <select id ="findActiveUsersByName" resultType ="User" > SELECT * FROM users WHERE status = 'ACTIVE' <if test ="name != null" > AND name LIKE #{name} </if > </select >
choose (when, otherwise) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <select id ="findUsersByCondition" resultType ="User" > SELECT * FROM users WHERE 1=1 <choose > <when test ="name != null" > AND name LIKE #{name} </when > <when test ="email != null" > AND email = #{email} </when > <otherwise > AND created_date > CURRENT_DATE - 7 </otherwise > </choose > </select >
where语句 1 2 3 4 5 6 7 8 9 10 11 <select id ="findUsers" resultType ="User" > SELECT * FROM users <where > <if test ="name != null" > AND name LIKE #{name} </if > <if test ="email != null" > AND email = #{email} </if > </where > </select >
set语句 1 2 3 4 5 6 7 8 9 <update id ="updateUserSelective" > UPDATE users <set > <if test ="username != null" > username = #{username},</if > <if test ="email != null" > email = #{email},</if > <if test ="age != null" > age = #{age},</if > </set > WHERE id = #{id} </update >
foreach语句 1 2 3 4 5 6 7 8 <select id ="getUsersInList" resultType ="User" > SELECT * FROM users WHERE id IN <foreach item ="item" index ="index" collection ="list" open ="(" separator ="," close =")" > #{item} </foreach > </select >
一对一关系映射 假设我们有用户和账户表,一个用户对应一个账户:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <resultMap id ="userWithAccountMap" type ="com.example.entity.User" > <id property ="id" column ="user_id" /> <result property ="username" column ="username" /> <result property ="email" column ="email" /> <association property ="account" javaType ="com.example.entity.Account" > <id property ="id" column ="account_id" /> <result property ="accountNumber" column ="account_number" /> <result property ="balance" column ="balance" /> </association > </resultMap > <select id ="getUserWithAccount" parameterType ="long" resultMap ="userWithAccountMap" > SELECT u.id as user_id, u.username, u.email, a.id as account_id, a.account_number, a.balance FROM users u LEFT JOIN accounts a ON u.id = a.user_id WHERE u.id = #{id} </select >
一对多关系映射 假设一个用户可以有多个订单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <resultMap id ="userWithOrdersMap" type ="com.example.entity.User" > <id property ="id" column ="user_id" /> <result property ="username" column ="username" /> <result property ="email" column ="email" /> <collection property ="orders" ofType ="com.example.entity.Order" > <id property ="id" column ="order_id" /> <result property ="orderNumber" column ="order_number" /> <result property ="amount" column ="amount" /> </collection > </resultMap > <select id ="getUserWithOrders" parameterType ="long" resultMap ="userWithOrdersMap" > SELECT u.id as user_id, u.username, u.email, o.id as order_id, o.order_number, o.amount FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.id = #{id} </select >
MyBatis注解配置 除了XML配置,MyBatis还支持使用Java注解来配置Mapper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.example.mapper;import com.example.entity.User;import org.apache.ibatis.annotations.*;import java.util.List;public interface UserMapper { @Select("SELECT * FROM users WHERE id = #{id}") User getUserById (Long id) ; @Select("SELECT * FROM users") List<User> getAllUsers () ; @Insert("INSERT INTO users(username, email, age) VALUES(#{username}, #{email}, #{age})") @Options(useGeneratedKeys = true, keyProperty = "id") void insertUser (User user) ; @Update("UPDATE users SET username = #{username}, email = #{email}, age = #{age} WHERE id = #{id}") void updateUser (User user) ; @Delete("DELETE FROM users WHERE id = #{id}") void deleteUser (Long id) ; }
MyBatis缓存机制 MyBatis提供了两级缓存机制:
一级缓存(会话级缓存) 一级缓存是SqlSession级别的缓存,默认开启,同一个SqlSession中执行相同的查询语句时会返回缓存的结果。
1 2 3 4 5 6 7 8 User user1 = userMapper.getUserById(1L ); User user2 = userMapper.getUserById(1L ); session.commit(); session.rollback(); session.close();
二级缓存(应用级缓存) 二级缓存是Mapper级别的缓存,可以被多个SqlSession共享。需要在配置文件中开启:
1 2 3 4 5 6 7 8 9 10 11 <settings > <setting name ="cacheEnabled" value ="true" /> </settings > <cache eviction ="LRU" flushInterval ="60000" size ="512" readOnly ="true" />
与Spring集成 MyBatis可以很容易地与Spring框架集成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <bean id ="dataSource" class ="org.apache.commons.dbcp2.BasicDataSource" destroy-method ="close" > <property name ="driverClassName" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/testdb" /> <property name ="username" value ="root" /> <property name ="password" value ="password" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath:com/example/mapper/*.xml" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="basePackage" value ="com.example.mapper" /> </bean >
总结 MyBatis是一款功能强大且灵活的持久层框架,它的特点是提供了对SQL的完全控制,允许开发者编写原生SQL语句,同时还提供了强大的动态SQL功能和复杂的对象关系映射。对于需要对数据库操作有更精细控制的项目,MyBatis是一个很好的选择。
与Hibernate相比,MyBatis更加轻量级,学习曲线更平缓,而且在处理复杂查询和大量数据时往往表现更佳。与JDBC相比,MyBatis极大地简化了代码,同时提供了更强大的特性如缓存和动态SQL。