MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.2.1version>
dependency>
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://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/test"/>
<property name="username" value="root"/>
<property name="password" value="120125hzy."/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="UserMapper.xml"/>
mappers>
configuration>
既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
创建 UserMapper.java
public interface UserMapper {
// @Param 是 MyBatis 中用于给方法参数起别名的注解。这个注解主要用于在 XML 映射文件中引用参数时,提供一个明确的名称。
User selectUser(@Param("id") int id);
}
创建 UserMapper.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hzy.mybatis.UserMapper">
<select id="selectUser" resultType="com.hzy.mybatis.User">
select * from user where id=${id}
select>
mapper>
UserMapper.java 与 UserMapper.xml 是一一对应的
获取 SqlSession 执行sql
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUser(1);
System.out.println(user);
}
}
与 上篇文章 讲的 JDBC 的操作流程:
1. 创建数据库连接池 DataSource
2. 通过 DataSource 获取数据库连接 Connection
3. 编写要执行带 ? 占位符的 SQL 语句
4. 通过 Connection 及 SQL 创建操作命令对象 Statement
5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
6. 使⽤ Statement 执行 SQL 语句
7. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
8. 处理结果集
9. 释放资源
相比,Mybatis 简单了许多,但还是要手动配置一些核心组件如如 SqlSessionFactory
、DataSource
、TransactionManager
等。
所以我们一般基于 SpringBoot 使用 Mybatis 来简化开发。
Spring Boot 是一个现代的、约定大于配置的框架,通过 Spring Boot 的自动配置和约定来简化整体架构,大大减少了手动配置的需求,提高了开发效率。
在 Spring Boot 中,只需在配置文件中指定数据库连接等少量信息,Spring Boot 将会根据约定自动配置 MyBatis 相关组件,包括创建 SqlSessionFactory
、DataSource
、TransactionManager
等。
选择数据库修改依赖
配置文件
Spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 120125hzy.
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
type-aliases-package: com.hzy.demo.pojos # 指定MyBatis实体类的包路径,使得在XML文件中可以直接使用类名而不是全限定名。
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志
map-underscore-to-camel-case: true # 将数据库字段的下划线命名方式映射为Java驼峰命名方式
pojos.User
@Data
public class User {
private int id;
private String name;
private Double balance;
private String homeAddr;
}
mapper.UserMapper
@Mapper
public interface UserMapper {
User selectUser(@Param("id") int id);
}
UserMapper.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hzy.demo.mapper.UserMapper">
<select id="selectUser" resultType="User">
select * from user2 where id=${id}
select>
mapper>
测试代码
@Test
void test01(){
User user = userMapper.selectUser(1);
System.out.println(user);
}
当前的目录结构
需要注意的是 UserMapper 和 UserMapper.xml 文件的路径要相同,不同会报错
或者在配置文件中指定 Mapper.xml 文件的目录
mybatis:
mapper-locations: classpath:/mybatis/mappers/*.xml
MyBatis 使用 元素来定义查询语句。查询可以返回单个实体对象、集合对象或基本类型的值。
<select id="selectUser" parameterType="int" resultType="User">
select * from user2 where id=${id}
select>
selectUser
是查询语句的唯一标识符,parameterType
指定了传递给查询的参数类型,resultType
指定了查询结果的返回类型。
对于简单 sql 语句可以直接使用@Select()
注解实现
@Select("select * from user2 where id=${id}")
User selectUser(@Param("id") int id);
测试
@Test
void test01(){
User user = userMapper.selectUser(1);
System.out.println(user);
}
MyBatis 使用
元素来定义插入语句。
<insert id="addUser" parameterType="User">
insert into user2(name,balance,home_addr) values(#{name},#{balance},#{homeAddr})
insert>
insertUser
是插入语句的唯一标识符,parameterType
指定了传递给插入语句的参数类型,name,balance,homeAddr是 User 的属性
同样也可以使用@Insert()
注解实现:
@Insert("insert into user2(name,balance,home_addr) values(#{name},#{balance},#{homeAddr})")
int addUser(User user);
测试
@Test
void test03(){
User user = new User();
user.setName("李四");
user.setBalance(1200.0);
user.setHomeAddr("cq");
int i = userMapper.addUser(user);
assert i == 1;
}
MyBatis 使用
元素来定义删除语句。
<delete id="removeUserById" parameterType="int">
delete from user2 where id = #{id}
delete>
MyBatis 使用
元素来定义删除语句。
同样也可以使用@Insert()
注解实现:
@Delete("delete from user2 where id = #{id}")
int removeUserById(@Param("id") int id);
测试
@Test
void test04(){
int i = userMapper.removeUserById(4);
assert i == 1;
}
MyBatis 使用
元素来定义更新语句。
<update id="updateUserById" parameterType="User">
update user2 set name=#{name},balance=#{balance},home_addr=#{homeAddr} where id = #{id}
update>
同样使用@Update()
注解也行
@Update("update user2 set name=#{name},balance=#{balance},home_addr=#{homeAddr} where id = #{id}")
int updateUserById(User user);
测试
@Test
void test05(){
User user = new User();
user.setId(4);
user.setName("哈哈哈");
user.setBalance(1000.0);
user.setHomeAddr("sh");
int i = userMapper.updateUserById(user);
assert i == 1;
}
因为前面已经删除id为4的数据所以这里断言未通过
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
判断一个参数是否有值的,如果没值,那么就会隐藏 if 中的 sql
<select id="selectUsers" resultType="User">
select * from user2
<if test="id != null">
where id=#{id}
if>
select>
测试
@Test
void test06(){
List<User> users = userMapper.selectUsers(null);
for(User user: users){
System.out.println(user);
}
}
通常情况下 if 标签会和 where 标签一起用,不然有可能出现 select * from user2 where 这样的语句。
<select id="selectUsers" resultType="User">
select * from user2
<where>
<if test="name != null and name != '' ">
and name like concat('%',#{name},'%')
if>
<if test="homeAddr != null and homeAddr != '' ">
and home_addr = #{homeAddr}
if>
where>
select>
测试
@Test
void test06(){
User user = new User();
List<User> users = userMapper.selectUsers(user);
for(User u: users){
System.out.println(u);
}
System.out.println("不带参查询");
user.setName("s");
user.setHomeAddr("sh");
users = userMapper.selectUsers(user);
for(User u: users){
System.out.println(u);
}
System.out.println("带参查询");
}
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="selectUsers" resultType="User">
select * from user2 where
<choose>
<when test="name != null and name != '' ">
name like concat('%',#{name},'%')
when>
<when test="homeAddr != null and homeAddr != '' ">
home_addr = #{homeAddr}
when>
<otherwise>
id = 1
otherwise>
choose>
select>
测试
@Test
void test06(){
User user = new User();
List<User> users = userMapper.selectUsers(user);
for(User u: users){
System.out.println(u);
}
System.out.println("不带参查询");
user.setName("s");
user.setHomeAddr("sh");
users = userMapper.selectUsers(user);
for(User u: users){
System.out.println(u);
}
System.out.println("带参查询");
}
虽然传入两个参数只生效了一个参数
元素用于迭代集合或数组,动态生成 SQL 片段。这在处理 IN 子句中的多个参数时非常有用。
// 批量删除
int removeUserByIds(@Param("ids") List<Integer> ids);
<delete id="removeUserByIds">
delete
from user2
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
foreach>
delete>
foreach 标签中主要属性介绍:
collection:绑定方法参数中的集合,如List, Set, Map或数组对象
item:遍历时的每一个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
测试
@Test
void test07(){
int i = userMapper.removeUserByIds(Arrays.asList(3,5,6));
assert i == 3;
}
标签:
标签用于处理字符串拼接时可能出现的空格问题。它包含了四个属性:prefix
、suffix
、prefixOverrides
、suffixOverrides
,用于在SQL语句的拼接时添加前缀、后缀,或者移除多余的前缀、后缀。
修改前面的修改语句
<update id="updateUserById" parameterType="User">
update user2
<trim prefix="SET" suffixOverrides=",">
<if test="name != null" >
name = #{name},
if>
<if test=" balance != null">
balance = #{balance},
if>
<if test="home_addr != null">
home_addr = #{homeAddr},
if>
trim>
where id = #{id}
update>
在上述例子中,
标签用于处理SET
关键字后可能出现的多余逗号。
标签:
标签用于处理UPDATE语句中SET关键字后可能出现的多余逗号,并且可以灵活地处理更新字段。
<update id="updateUserById" parameterType="User">
update user2
<set>
<if test="name != null" >
name = #{name},
if>
<if test=" balance != null">
balance = #{balance},
if>
<if test="home_addr != null">
home_addr = #{homeAddr},
if>
set>
where id = #{id}
update>
这个和语句和上面
标签实现的功能一样,区别在于使用
标签,手动指定了SET关键字和可能的多余逗号的处理方式。
而
标签,它自动处理了SET关键字后可能出现的多余逗号,确保生成的SQL语句是合法的。
两者相比
标签更直观,而
标签更加灵活,允许你手动指定前缀和后缀。
标签:
标签用于将WHERE关键字加到SQL语句中,并且能够智能处理条件语句的连接。如果条件语句中的第一个条件是AND或OR,
标签会自动将其去除。
前面提到过。