前言
本文通过一个简单的Demo(功能并不成熟)来快速上手MyBatis,实现增、删、改、查。
更多详细的使用细节可点击如下链接:
版本:
Maven:3.8.1
JDK:17
SpringBoot:3.3.2
API测试工具:Postman
项目实例构建
新建一个名为springboot_demo
的项目,并勾选添加如下依赖:
Developer Tools
Web
SQL
MyBatis Framework
MySQL Driver
项目目录如下:
User
类:
1 2 3 4 5 6 7 8 9 10 11 @Data @NoArgsConstructor @AllArgsConstructor public class User { private Integer id; private String name; private Integer age; private Short gender; private LocalDateTime createTime; private LocalDateTime updateTime; }
Result
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Data @NoArgsConstructor @AllArgsConstructor public class Result { private Integer code; private String msg; private Object data; public static Result success (Object data) { return new Result(1 , "success" , data); } public static Result success () { return new Result(1 , "success" , null ); } public static Result error (String msg) { return new Result(0 , msg, null ); } }
application.properties
配置数据库连接信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 spring.application.name =springboot_demo spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver spring.datasource.url =jdbc:mysql://localhost:3306/springboot_demo spring.datasource.username =root spring.datasource.password =root mybatis.configuration.log-impl =org.apache.ibatis.logging.stdout.StdOutImpl mybatis.configuration.map-underscore-to-camel-case =true
数据库表中的字段为下划线_
命名的方式,而定义的Bean中的属性名采用驼峰命名方式,mybatis.configuration.map-underscore-to-camel-case=true
可以在mapper中自动完成两种命名方式的映射。
创建一个名为springboot_demo
的数据库,在其中新建一个user
表:
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 SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0 ;DROP TABLE IF EXISTS `user `;CREATE TABLE `user ` ( `id` int (11 ) NOT NULL AUTO_INCREMENT, `name` varchar (255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , `age` int (11 ) NOT NULL , `gender` tinyint(4 ) NOT NULL , `create_time` datetime NOT NULL , `update_time` datetime NOT NULL , PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic ; INSERT INTO `user ` VALUES (1 , '张三' , 19 , 1 , '2024-08-02 17:41:33' , '2024-08-02 18:14:29' );INSERT INTO `user ` VALUES (2 , '李四' , 20 , 0 , '2024-08-02 14:55:25' , '2024-08-02 14:55:27' );INSERT INTO `user ` VALUES (3 , '王五' , 19 , 1 , '2024-08-02 16:49:59' , '2024-08-02 16:50:02' );INSERT INTO `user ` VALUES (4 , '赵六' , 30 , 0 , '2024-08-02 16:50:20' , '2024-08-02 16:50:22' );SET FOREIGN_KEY_CHECKS = 1 ;
功能实现
说明:
本节内容分别通过注解
和xml配置文件
的方式实现对数据库中user
表数据的增、删、改、查。(两种实现方式可以根据实际情况选择使用(通常来说:简单的sql实现使用注解
方式实现,复杂的sql实现使用xml配置文件
方式实现。)注意:同一种方法不可以同时使用两种实现方式,否则会报错!)
值得说明的是XML映射文件须遵循以下规范:
XML映射文件的名称需与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同的包下(同包同名 )
XML映射文件<Mapper>
标签的namespace属性需与Mapper接口全限定名一致
XML映射文件中sql语句的id需与Mapper接口中的方法名一致,并保持返回类型一致
配置XML映射文件首先需要在一开始配置约束,该约束是固定格式,可参考官网:https://mybatis.net.cn/getting-started.html#:~:text=探究已映射的 SQL 语句
1 2 3 4 5 6 7 8 <?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 ="_1004.mapper.UserMapper" > </mapper >
增
需求:根据前端传送的name
、age
、gender
字段新增user数据。
Controller层
UserController
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Slf4j @RestController public class UserController { @Autowired private UserService userService; @PostMapping("/addUser") public Result addUser (@RequestBody User user) { log.info("新增员工,user:{}" , user); userService.addUser(user); return Result.success(); } }
Service层
UserService
接口:
1 2 3 public interface UserService { void addUser (User user) ; }
UserServiceImpl
实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public void addUser (User user) { user.setCreateTime(LocalDateTime.now()); user.setUpdateTime(LocalDateTime.now()); userMapper.addUser(user); } }
Mapper层
注解实现
UserMapper
类:
1 2 3 4 5 6 7 @Mapper public interface UserMapper { @Options(keyProperty = "id", useGeneratedKeys = true) @Insert("insert into user(name, age, gender, create_time, update_time) " + "values (#{name}, #{age}, #{gender}, #{createTime}, #{updateTime})") void addUser (User user) ; }
说明:注解@Options
可以设置获取添加对象返回的主键
useGeneratedKeys = true
:表示要拿到主键值
keyProperty = "id"
:表示拿到的主键最终会封装到id
属性中
拿到的主键值可以直接在Controller中调用user.getId()
方法获取。
XML实现
UserMapper
类:
1 2 3 4 5 6 @Mapper public interface UserMapper { @Insert("insert into user(name, age, gender, create_time, update_time) " + "values (#{name}, #{age}, #{gender}, #{createTime}, #{updateTime})") void addUser (User user) ; }
UserMapper.xml
:
1 2 3 4 5 6 7 8 <mapper namespace ="_1004.mapper.UserMapper" > <insert id ="addUser" keyProperty ="id" useGeneratedKeys ="true" > insert into user(name, age, gender, create_time, update_time) values (#{name}, #{age}, #{gender}, #{createTime}, #{updateTime}) </insert > </mapper >
同样可以利用keyProperty
和useGeneratedKeys
获取返回的主键值。
本示例中id
为自增,因此不需要添加id信息。
假设id
非自增,需要我们手动添加bean
对象的所有属性,那么可以利用parameterType
属性指定要插入的数据类型,舍去要插入的字段:
1 2 3 <insert id ="addUser" parameterType ="_1004.pojo.User" > insert into user values (#{id}, #{name}, #{age}, #{gender}, #{createTime}, #{updateTime}) </insert >
POST请求:
删
需求:根据前端传送的ids
值(可以是多个id)批量删除对应的user数据。
Controller层
UserController
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Slf4j @RestController public class UserController { @Autowired private UserService userService; @DeleteMapping("/deleteByIds/{ids}") public Result deleteById (@PathVariable List<Integer> ids) { log.info("根据id删除用户:{}" , ids); userService.deleteById(ids); return Result.success(); } }
Service层
UserService
接口:
1 2 3 public interface UserService { void deleteById (List<Integer> ids) ; }
UserServiceImpl
实现类:
1 2 3 4 5 6 7 8 9 10 11 @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public void deleteById (List<Integer> ids) { userMapper.deleteById(ids); } }
Mapper层
注解实现
UserMapper
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Mapper public interface UserMapper { @DeleteProvider(type = SqlProvider.class, method = "deleteByIds") void deleteById (@Param("ids") List<Integer> ids) ; class SqlProvider implements ProviderMethodResolver { public static String deleteByIds (@Param("ids") List<Integer> ids) { String idsString = ids.stream() .map(String::valueOf) .collect(Collectors.joining("," )); return new SQL() {{ DELETE_FROM("user" ); WHERE("id IN (" + idsString + ")" ); }}.toString(); } } }
说明:该动态SQL要求传入的列表不能为空,否则会报错!(通常动态SQL推荐使用XML配置文件的方式实现)
XML实现
UserMapper.xml
:
1 2 3 4 5 6 7 8 9 10 <mapper namespace ="_1004.mapper.UserMapper" > <delete id ="deleteById" > delete from user where id in <foreach collection ="ids" item ="id" separator ="," open ="(" close =")" > #{id} </foreach > </delete > </mapper >
<foreach>
标签说明:
collection
属性:要遍历的集合
item
属性:遍历的元素
separator
属性:指定每一次遍历元素的分隔符
open
属性:遍历开始前拼接的SQL片段
close
属性:遍历结束后拼接的SQL片段
该动态SQL同样要求传入的列表不能为空,否则会报错!
DELETE请求:
改
需求:根据前端传来的id
、name
、age
、gender
字段(字段可选择)更新修改对应id
的uesr数据。
Controller层
UserController
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Slf4j @RestController public class UserController { @Autowired private UserService userService; @PutMapping("/updateUser") public Result updateUser (@RequestBody User user) { log.info("更新员工信息:{}" , user); userService.updateUser(user); return Result.success(); } }
Service层
UserService
接口:
1 2 3 public interface UserService { void updateUser (User user) ; }
UserServiceImpl
实现类:
1 2 3 4 5 6 7 8 9 10 11 12 @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public void updateUser (User user) { user.setUpdateTime(LocalDateTime.now()); userMapper.updateUser(user); } }
Mapper层
注解实现
UserMapper
类:
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 @Mapper public interface UserMapper { @UpdateProvider(type = SqlProvider.class, method = "updateUser") void updateUser (@Param("user") User user) ; class SqlProvider { public static String updateUser (@Param("user") User user) { StringBuilder sql = new StringBuilder(); sql.append("UPDATE user SET " ); if (user.getName() != null ) { sql.append("name = #{user.name}, " ); } if (user.getAge() != null ) { sql.append("age = #{user.age}, " ); } if (user.getGender() != null ) { sql.append("gender = #{user.gender}, " ); } if (user.getUpdateTime() != null ) { sql.append("update_time = #{user.updateTime}, " ); } sql.setLength(sql.length() - 2 ); sql.append(" WHERE id = #{user.id}" ); return sql.toString(); } } }
该方法不建议使用注解的方式
XML实现
UserMapper.xml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <mapper namespace ="_1004.mapper.UserMapper" > <update id ="updateUser" > update user <set > <if test ="name != null and name != ''" > name = #{name}, </if > <if test ="age != null" > age = #{age}, </if > <if test ="gender != null" > gender = #{gender}, </if > <if test ="updateTime != null" > update_time = #{updateTime} </if > </set > where id = #{id} </update > </mapper >
<if>
标签说明:根据test
属性进行条件判断,如果为true,则拼接包裹的SQL语句
<set>
标签说明:以上述代码为例,如果update_time
不更新,那么SQL语句:gender = #{gender},
就会多一个.
,致使SQL语句出现错误,为此可以利用<set>
标签进行包裹,可以自动地将正确的<if>
项进行添加。
(<where>
标签作用同理)
PUT请求:
查
需求:根据前端传送的id
字段更新对应的user数据。
Controller层
UserController
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Slf4j @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/getById/{id}") public Result getById (@PathVariable Integer id) { log.info("根据ID查询员工信息,id:{}" , id); User user = userService.getById(id); return Result.success(user); } }
Service层
UserService
接口:
1 2 3 public interface UserService { User getById (Integer id) ; }
UserServiceImpl
实现类:
1 2 3 4 5 6 7 8 9 10 11 @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User getById (Integer id) { return userMapper.getById(id); } }
Mapper层
注解实现
UserMapper
类:
1 2 3 4 5 @Mapper public interface UserMapper { @Select("select * from user where id = #{id}") User getById (Integer id) ; }
XML实现
UserMapper.xml
:
1 2 3 4 5 6 <mapper namespace ="_1004.mapper.UserMapper" > <select id ="getById" resultType ="_1004.pojo.User" > select * from user where id = #{id} </select > </mapper >
GET请求:
后记
在XML中为了抽取相同的SQL语句片段,实现良好的复用性可以使用<sql>
标签:
1 2 3 4 5 <sql id = "sqlFragmentName" > </sql > <include refid ="sqlFragmentName" />