MyBatis 是什么?
MyBatis 是一款优秀的持久层框架(持久层就是负责与数据库相关的各种操作的一层架构),能够简化各种数据库操作,你只需要告诉 MyBatis“执行什么 SQL,输入什么参数,输出什么类型”,框架就会帮你完成数据库的增删改查操作。理论部分就到这里,因为我不是很喜欢那种学院派的风格,一上来先讲一堆的理论,让人头脑发晕。我认为在见过一些实践示例后,再来多讲一些理论学习效果会更好。那么,
如何使用 MyBatis?
本文是默认你是已经对 Java 项目的开发流程有了一定的了解了,知道如何添加依赖,知道基础的 SQL 语句,也知道三层架构的项目数据是如何流通的等其它内容。同时本文所讲都是使用 Spring Boot 框架的 Java 项目,并使用 Maven 进行管理。并且这里只会讲一些初略的配置流程,如有不理解的请见谅。
1.在项目的 pom 文件中添加依赖,仅作示范,依赖版本根据需要自行选择
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
2.在项目的配置文件中配置好数据库的连接,如在application.properties
#DataBase
spring.datasource.url=jdbc:mysql://localhost:3306/myblog?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
3.编写 mappr 相关文件
1)在项目主模块下创建 mapper 文件包并在包下编写 mapper 接口文件
package com.tsz.myblog.mapper;
@Mapper
public interface BlogMapper {
}
2)在 resource 模块下创建 mapper 包,并在包下创建并编写与 mapper 接口文件名相同的 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.tsz.myblog.mapper.BlogMapper">
<!--在此编写具体代码-->
</mapper>
到这里 MyBatis 的基础使用配置就完成了,下面就可以进入实践了
MyBatis 的几种使用方式
1 进行基础的 CRUD (通过 XML 方式,这里以实体类 User 为例)
@Data//使用lombok依赖提供的注解,自动生成getter/setter方法
public class User {
private Integer id;
private String name;
private Integer age;
// getter/setter方法可使用Lombok依赖自动生成
}
在 Mapper 接口处
@Mapper//记得打上注解,表明这是mapper文件方便Spring Boot管理
public interface UserMapper {
User selectById(Integer id);//根据id查询用户
List<User> selectAll();//查询所有用户,注意:如果有多个结果,可以使用对应数据类型的List集合来接收
int insert(User user);//新增用户
int update(User user);//修改用户信息
int delete(Integer id);//根据id删除用户
}//后面的也是这样的,在mapper接口文件这定义方法名和参数以及返回类型,再Service层调用就行
在对应的 XML 映射文件中,注:XML 中注解格式是,此处方便起见使用“//”来进行注释,此外在指定返回类型时,如果想直接使用类名,而不写完整的全限定类名的话,应在项目配置文件中加上
mybatis.type-aliases-package=com.example.pojo.entity
这样就可以使用 User 而不是 com.example.pojo.entity.User
<mapper namespace="com.example.mapper.UserMapper">
//根据id查询用户
//id="selectById" 中的 selectById对应的是mapper接口中的方法
//执行SELECT * FROM user WHERE id = #{id} 这个SQL语句
//#{id} 中的 id 是提供给查询语句的参数
//resultType="User" 中的 User 是查询所返回的数据类型,下同
<select id="selectById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
//查询所有用户
<select id="selectAll" resultType="User">
SELECT * FROM user
</select>
//新增用户
//useGeneratedKeys="true" 表示使用数据库自动生成的主键值
//keyProperty="id" 表示指定将获取到的 自动生成的主键值 赋值给传入参数对象的id属性。
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user(name, age) VALUES(#{name}, #{age})
</insert>
//修改用户信息
<update id="update">
UPDATE user SET name=#{name}, age=#{age} WHERE id=#{id}
</update>
//根据id删除用户
<delete id="delete">
DELETE FROM user WHERE id=#{id}
</delete>
</mapper>
2 注解方式
在面对一些简单 SQL 语句时,如果个个全都在 XML 文件中编写,会变的很麻烦且不易于管理,好在 MyBatis 提供了使用注解编写 SQL 语句的方式
public interface UserMapper {
//这样的话,参数id会自动传递给#{id}
//然后结果又会自动返回给调用者
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Integer id);
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
int insert(User user);
@Update("UPDATE user SET name=#{name} WHERE id=#{id}")
int update(User user);
@Delete("DELETE FROM user WHERE id=#{id}")
int delete(Integer id);
}
3 结果映射(解决字段名与表中属性名不一致的问题)
例如假设数据库表中的字段名为 user_name,而 Java 属性为 userName
这时有两种方法:1.使用 resultMap 2.开启驼峰自动映射
resultMap
<resultMap id="userMap" type="User">
<id column="id" property="id"/>
<result column="user_name" property="userName"/>//指定"user_name"对应"userName"属性
<result column="age" property="age"/>//注意,即使一致也要在resultMap中写出
</resultMap>
<select id="selectById" resultMap="userMap">
SELECT id, user_name, age FROM user WHERE id = #{id}
</select>
开启驼峰自动映射,在配置文件中设置
mybatis.configuration.map-underscore-to-camel-case=true
若不了解驼峰命名法建议去学习一下,这个是经常用到的
此外,要提一下的是若是数据库表中的字段名为 AAA,而 Java 属性为 BBB 的话,就只能使用 resultMap 方法来解决不一致问题了
4 动态 SQL
使用动态 SQL 的场景主要有以下几方面:
1. 多条件组合查询
当查询条件不确定时,例如用户可能输入姓名、年龄中的一个或多个,动态SQL能根据具体情况拼接WHERE子句,能自动处理多余的 AND 或 OR。
<select id="findUsers" resultType="User">
SELECT * FROM user
//根据用户输入的参数查找具体用户
<where>
//如果用户指定了名字,便会拼接AND name LIKE concat('%', #{name}, '%')这一条语句
//并将name参数传递给#{name}中的name,下同
<if test="name != null and name != ''">
AND name LIKE concat('%', #{name}, '%')
</if>
<if test="minAge != null">
AND age >= #{minAge}
</if>
</where>
</select>
//如果什么都没指定,这个SQL语句便是
SELECT * FROM user
//如果只指定了名字,则
SELECT * FROM user WHERE name LIKE concat('%',#{name},'%')
//如果既指定名字又指定了年龄,则
SELECT * FROM user WHERE name LIKE concat('%',#{name},'%') AND age >= #{minage}
2. 动态更新
在更新用户信息时,往往只修改用户提交的字段,而不是把整行数据覆盖。
动态SQL可以自动生成 UPDATE user SET name=?, age=? …,且仅包含需要更新的列,避免将用户未提交的字段误置为NULL
<update id="updateUser">
UPDATE user//更新用户信息
<set>
<if test="name != null">name = #{name},</if>//如果用户想改名称
<if test="age != null">age = #{age},</if>//想改年龄
<if test="email != null">email = #{email},</if>//想改邮箱
</set>
WHERE id = #{id}
</update>
3. 批量操作
动态 SQL 可以根据具体集合中的数据进行批量插入或查询等操作,
批量插入: 比如 List users 集合中是本次要新增的用户名单
<insert id="batchInsert">
INSERT INTO user(name, age, email) VALUES
<foreach collection="users" item="user" separator=",">
(#{user.name}, #{user.age}, #{user.email})
</foreach>
</insert>
<foreach :这个就不必说了吧
collection=“users” :指定要遍历的集合参数名称,即你传递给mapper的集合
注意:如果方法参数是 List 类型且没有使用@Param(“users”)进行注解的话,MyBatis 默认名称为 list,其它类型也一样
item=“user” :当前所遍历的元素别名,即通过 user.name 等来获取对应属性
separator=“,” :指定每一次迭代之间添加的分隔符为"," 这样,生成的多个(…,…,…)会被逗号连接,即
INSERT INTO . . . VALUES (...,...,...),(...,...,...),(...,...,...)
批量查询:比如要查询List ids 是本次要查询的所有用户的用户 ID
<select id="selectByIds" resultType="User">
SELECT * FROM user WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>SELECT * FROM user WHERE id IN (?, ?, ?)
</select>
open=“(”:指定本循环体(即整个 foreach 语句)生成的内容前面所添加的字符串为"("
close=“)”:指定本循环体生成的内容后面所添加的字符串为")"
若 ids=[1,2,3],则生成如下 SQL
SELECT * FROM user WHERE id IN (1, 2, 3)
4.复杂分支判断
这种用法就像是 Java 中的 switch,用于多选一的场景,如根据条件查询用户
<select id="findUsersByCondition" resultType="User">
SELECT * FROM user
<where>
<choose>
<when test="name != null and name != ''">
AND name = #{name}
</when>
<when test="age != null">
AND age = #{age}
</when>
<otherwise>
AND status = 1
</otherwise>
</choose>
</where>
</select>
含义:优先按 name 查;若name为 null 但有 age 则按 age 查;都为 null 则只查状态为 1 的用户。
5.辅助处理:在 SQL 语句内部创建一个新的变量
使用示例:
<select id="findUsersByName" resultType="User">
<bind name="pattern" value="'%' + name + '%'"/>
SELECT * FROM user WHERE name LIKE #{pattern}
</select>
name=“pattern”:新变量的名称,示例为 pattern
value=“‘%’ + name + ‘%’”:变量所代表的表达式
最终结果:SELECT * FROM user WHERE name LIKE %name%
其它
在大致学会了 MyBatis 的基础使用后,不妨来了解下其它持久层框架,毕竟不同的框架有其各自的特点,在一个项目中通常会使用不止一个持久层框架,妥善利用不同框架的优点来处理不同的模块才是正确的选择。
MyBatis 与同样作为持久层框架的有何不同?
先下一个大致的结论:
MyBatis:是一个“SQL 映射”框架,是半自动的。它要求你手动编写 SQL 语句,然后将执行结果映射到 Java 对象上
Hibernate / JPA:是一个“对象关系映射(ORM)”框架,是全自动的。它让你通过操作 Java 对象来间接操作数据库,SQL 语句由框架在背后自动生成。
接下来就主要讲讲两者在适用场景、性能优化、数据库移植三方面的区别:
在适用场景方面:
MyBatis 适合用于那些需要编写复杂 SQL 的场景,比如互联网项目、报表系统、高并发等,需求变化快,需要对 SQL 有绝对控制权的地方
Hibernate / JPA:则适合那些业务稳定的企业级应用,需要开发效率优先,比如OA、ERP、CRM 类项目
在性能优化方面:
MyBatis 用一个词来形容就是直接精准,毕竟 SQL 语句是自己编写的,可以针对每一条 SQL 的索引适用,执行计划等方面进行优化
Hibernate / JPA 则是间接且复杂的,你需要理解框架生成的 SQL 和内部的缓存、抓取策略,调优难度比较高
在数据库移植方面:
由于 MyBatis 是自己编写的 SQL,强依赖特定数据库的方言,更换数据库时修改成本高
而Hibernate / JPA 则可以通过配置 Dialect(数据库方言),这样框架就会自动适配不同数据库的 SQL,切换成本低
MyBatis 与Hibernate / JPA 的区别就简单讲到这,能有个大致的了解在心里有个印象就行了,如果读者感兴趣可以去自行搜索相关更详细的讲解。
以上就是本片文章的所有内容,因为我本人水平有限,因此可能会有许多错误,欢迎各位进行批评指正,共勉!
最后,如果您觉得本文对你有帮助,不妨点赞关注支持一下,谢谢!!!

437

被折叠的 条评论
为什么被折叠?



