MyBatis 简介
什么是MyBatis?
MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。
为什么选择MyBatis?
优点
- 灵活性高:支持自定义SQL,可以进行复杂查询优化
- SQL与代码分离:SQL语句写在XML或注解中,便于维护
- 消除JDBC冗余代码:自动处理连接、预编译、结果映射
- 强大的结果映射:支持复杂的对象关系映射
- 动态SQL:根据条件动态生成SQL
- 缓存支持:一级缓存和二级缓存
与JPA/Hibernate对比
- MyBatis更灵活,适合复杂查询和性能优化
- JPA更简单,适合标准CRUD操作
- MyBatis学习曲线相对平缓
核心组件
1. SqlSessionFactory
MyBatis的核心,用于创建SqlSession。
java
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);2. SqlSession
执行SQL命令、获取映射器、管理事务的接口。
java
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectById(1L);
}3. Mapper接口
定义SQL操作的接口。
java
public interface UserMapper {
User selectById(Long id);
List<User> selectAll();
int insert(User user);
int update(User user);
int delete(Long id);
}快速开始
1. 添加依赖
Maven:
xml
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>2. 配置数据源
application.yml:
yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.domain
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL日志3. 创建实体类
java
@Data
public class User {
private Long id;
private String username;
private String email;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}4. 创建Mapper接口
java
@Mapper
public interface UserMapper {
User selectById(Long id);
List<User> selectAll();
int insert(User user);
int update(User user);
int delete(Long id);
}5. 创建Mapper XML
resources/mapper/UserMapper.xml:
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.example.mapper.UserMapper">
<select id="selectById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
<select id="selectAll" resultType="User">
SELECT * FROM user
</select>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, email, create_time)
VALUES (#{username}, #{email}, #{createTime})
</insert>
<update id="update">
UPDATE user
SET username = #{username},
email = #{email},
update_time = #{updateTime}
WHERE id = #{id}
</update>
<delete id="delete">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>6. 使用Mapper
java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User getUserById(Long id) {
return userMapper.selectById(id);
}
public List<User> getAllUsers() {
return userMapper.selectAll();
}
public void createUser(User user) {
user.setCreateTime(LocalDateTime.now());
userMapper.insert(user);
}
}基本CRUD操作
Insert
xml
<!-- 简单插入 -->
<insert id="insert">
INSERT INTO user (username, email)
VALUES (#{username}, #{email})
</insert>
<!-- 返回自增主键 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, email)
VALUES (#{username}, #{email})
</insert>
<!-- 批量插入 -->
<insert id="insertBatch">
INSERT INTO user (username, email)
VALUES
<foreach collection="list" item="user" separator=",">
(#{user.username}, #{user.email})
</foreach>
</insert>Select
xml
<!-- 根据ID查询 -->
<select id="selectById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 查询所有 -->
<select id="selectAll" resultType="User">
SELECT * FROM user
</select>
<!-- 条件查询 -->
<select id="selectByCondition" resultType="User">
SELECT * FROM user
WHERE username = #{username}
AND email = #{email}
</select>
<!-- 模糊查询 -->
<select id="selectByKeyword" resultType="User">
SELECT * FROM user
WHERE username LIKE CONCAT('%', #{keyword}, '%')
</select>Update
xml
<!-- 更新 -->
<update id="update">
UPDATE user
SET username = #{username},
email = #{email},
update_time = NOW()
WHERE id = #{id}
</update>
<!-- 选择性更新 -->
<update id="updateSelective">
UPDATE user
<set>
<if test="username != null">username = #{username},</if>
<if test="email != null">email = #{email},</if>
update_time = NOW()
</set>
WHERE id = #{id}
</update>Delete
xml
<!-- 删除 -->
<delete id="delete">
DELETE FROM user WHERE id = #{id}
</delete>
<!-- 批量删除 -->
<delete id="deleteBatch">
DELETE FROM user WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>参数传递
单个参数
java
User selectById(Long id);xml
<select id="selectById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>多个参数
方式1:使用@Param注解
java
List<User> selectByUsernameAndEmail(
@Param("username") String username,
@Param("email") String email
);xml
<select id="selectByUsernameAndEmail" resultType="User">
SELECT * FROM user
WHERE username = #{username}
AND email = #{email}
</select>方式2:使用Map
java
List<User> selectByMap(Map<String, Object> params);xml
<select id="selectByMap" resultType="User">
SELECT * FROM user
WHERE username = #{username}
AND email = #{email}
</select>方式3:使用对象
java
List<User> selectByCondition(UserQuery query);xml
<select id="selectByCondition" resultType="User">
SELECT * FROM user
WHERE username = #{username}
AND email = #{email}
</select>结果映射
自动映射
xml
<!-- 字段名与属性名一致时自动映射 -->
<select id="selectById" resultType="User">
SELECT id, username, email FROM user WHERE id = #{id}
</select>手动映射 - resultMap
xml
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id"/>
<result property="username" column="user_name"/>
<result property="email" column="user_email"/>
<result property="createTime" column="create_time"/>
</resultMap>
<select id="selectById" resultMap="userResultMap">
SELECT user_id, user_name, user_email, create_time
FROM user
WHERE user_id = #{id}
</select>关联查询 - 一对一
java
@Data
public class User {
private Long id;
private String username;
private UserProfile profile; // 一对一
}
@Data
public class UserProfile {
private Long id;
private Long userId;
private String avatar;
private String bio;
}xml
<resultMap id="userWithProfileMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<association property="profile" javaType="UserProfile">
<id property="id" column="profile_id"/>
<result property="userId" column="user_id"/>
<result property="avatar" column="avatar"/>
<result property="bio" column="bio"/>
</association>
</resultMap>
<select id="selectUserWithProfile" resultMap="userWithProfileMap">
SELECT u.id, u.username,
p.id as profile_id, p.user_id, p.avatar, p.bio
FROM user u
LEFT JOIN user_profile p ON u.id = p.user_id
WHERE u.id = #{id}
</select>关联查询 - 一对多
java
@Data
public class User {
private Long id;
private String username;
private List<Order> orders; // 一对多
}
@Data
public class Order {
private Long id;
private Long userId;
private BigDecimal amount;
}xml
<resultMap id="userWithOrdersMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<collection property="orders" ofType="Order">
<id property="id" column="order_id"/>
<result property="userId" column="user_id"/>
<result property="amount" column="amount"/>
</collection>
</resultMap>
<select id="selectUserWithOrders" resultMap="userWithOrdersMap">
SELECT u.id, u.username,
o.id as order_id, o.user_id, o.amount
FROM user u
LEFT JOIN `order` o ON u.id = o.user_id
WHERE u.id = #{id}
</select>注解方式
除了XML配置,MyBatis也支持注解方式:
java
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Long id);
@Select("SELECT * FROM user")
List<User> selectAll();
@Insert("INSERT INTO user (username, email) VALUES (#{username}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
@Update("UPDATE user SET username = #{username}, email = #{email} WHERE id = #{id}")
int update(User user);
@Delete("DELETE FROM user WHERE id = #{id}")
int delete(Long id);
@Select("SELECT * FROM user WHERE username LIKE CONCAT('%', #{keyword}, '%')")
List<User> selectByKeyword(String keyword);
}配置扫描
方式1:@MapperScan
java
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}方式2:@Mapper注解
java
@Mapper
public interface UserMapper {
// ...
}