MyBatis 查询数据库

x33g5p2x  于2022-06-08 转载在 其他  
字(13.4k)|赞(0)|评价(0)|浏览(485)

1. 什么是MyBatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
 
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
 
MyBatis 可以通过简单的 XML注解 来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

用一句简单的话来概述: MyBatis 是更简单完成程序和数据库交互的工具MyBatis 是更简单的操作和读取数据库工具

2. 配置 MyBatis 的开发环境

2.1 准备工作, 创建数据库和表

  1. create database if not exists MyBlogSystem;
  2. use MyBlogSystem;
  3. drop table if exists blog;
  4. -- 创建一个博客表
  5. create table blog (
  6. blogId int primary key auto_increment,
  7. title varchar(1024),
  8. content mediumtext,
  9. postTime datetime,
  10. userId int
  11. );
  12. drop table if exists user;
  13. -- 创建一个用户信息表
  14. create table user (
  15. userId int primary key auto_increment,
  16. username varchar(128) unique,
  17. password varchar(128)
  18. );

2.2 添加 MyBatis 依赖

  1. <dependency>
  2. <groupId>org.mybatis.spring.boot</groupId>
  3. <artifactId>mybatis-spring-boot-starter</artifactId>
  4. <version>2.2.2</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>mysql</groupId>
  8. <artifactId>mysql-connector-java</artifactId>
  9. <scope>runtime</scope>
  10. </dependency>

2.3 配置连接字符串和 MyBatis

2.3.1 配置数据库连接信息

  1. spring.datasource.url=jdbc:mysql://localhost:3306/MyBlogSystem?characterEncoding=utf8&useSSL=true
  2. spring.datasource.username=root
  3. spring.datasource.password=root
  4. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

2.3.2 配置 MyBatis 中的 XML 路径

配置 mybatis 的文件路径, 在 resources/mapper 创建所有表的xml文件

  1. mybatis.mapper-locations=classpath:mapper/**Mapper.xml

这里必须要一样

2.4 添加代码

2.4.1 添加实体类

添加用户的实体类

  1. @Getter
  2. @Setter
  3. @ToString
  4. public class User {
  5. public int userId;
  6. public String username;
  7. public String password;
  8. }

2.4.2 添加 mapper 接口

  1. @Mapper
  2. public interface UserMapper {
  3. List<User> getAll();
  4. }

2.4.3 添加 UserMapper.xml

固定的xml格式

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.example.demo.mapper.UserMapper">
  5. </mapper>

这里的 UserMapper.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.example.demo.mapper.UserMapper">
  5. <select id="getAll" resultType="com.example.demo.model.User">
  6. select * from user;
  7. </select>
  8. </mapper>

2.4.4 添加 Service

  1. @Service
  2. public class UserService {
  3. // 记得要注入
  4. @Resource
  5. private UserMapper userMapper;
  6. public List<User> getAll() {
  7. return userMapper.getAll();
  8. }
  9. }

2.4.5 添加 Controller

  1. // 这里的 @RestController 相当于 @Controller + @ResponseBody
  2. @RestController
  3. @RequestMapping("/user")
  4. public class UserController3 {
  5. @Autowired
  6. private UserService userService;
  7. @RequestMapping("/getall")
  8. public List<User> getAll() {
  9. return userService.getAll();
  10. }
  11. }

2.4.6 测试代码

2.5 注意事项

  1. 注意配置文件中的mapper配置和mapper文件夹的对应

  2. UserMapper.xml 这里需要一些路径对应, 以及id格式对应 , 这里的resultType是返回的类型.

  1. 按照业务规定流程写代码

3. MyBatis 的增删改查操作.

3.1 增加操作

步骤:

  • 添加 实体类(这里有了就不需要添加了)
  • 添加 controller
  • 添加 service
  • 添加 mapper 接口
  • 添加 xml

① 添加 controller 实现代码

  1. @RestController
  2. @RequestMapping("/user")
  3. public class UserController3 {
  4. @Autowired
  5. private UserService userService;
  6. @RequestMapping("/insert")
  7. public Integer insert(User user) {
  8. return userService.insert(user);
  9. }
  10. }

② 添加 service 实现代码

  1. @Service
  2. public class UserService {
  3. // 记得要注入
  4. @Resource
  5. private UserMapper userMapper;
  6. public Integer insert(User user) {
  7. return userMapper.insert();
  8. }
  9. }

③ 添加 mapper 接口

  1. @Mapper
  2. public interface UserMapper {
  3. Integer insert();
  4. }

④ 添加 xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.example.demo.mapper.UserMapper">
  5. <insert id="insert">
  6. insert into user values (null, #{username},#{password});
  7. </insert>
  8. </mapper>

⑤ 测试代码

3.2 查找操作

步骤:

  • 添加 实体类(这里有了就不需要添加了)
  • 添加 controller
  • 添加 service
  • 添加 mapper 接口
  • 添加 xml

① 添加 controller

  1. @RequestMapping("/getall")
  2. public List<User> getAll() {
  3. return userService.getAll();
  4. }

② 添加 service

  1. @RequestMapping("/getall")
  2. public List<User> getAll() {
  3. return userService.getAll();
  4. }

③ 添加 mapper 接口

  1. public List<User> getAll() {
  2. return userMapper.getAll();
  3. }

④ 添加 xml

  1. <select id="getAll" resultType="com.example.demo.model.User">
  2. select * from user;
  3. </select>

⑤ 测试代码

3.3 修改操作

步骤:

  • 添加 实体类(这里有了就不需要添加了)
  • 添加 controller
  • 添加 service
  • 添加 mapper 接口
  • 添加 xml

① 添加controller

  1. @RequestMapping("/update")
  2. public Integer update(Integer userId, String password) {
  3. return userService.update(userId,password);
  4. }

② 添加 service

  1. public Integer update(Integer userId, String password) {
  2. return userMapper.update(userId,password);
  3. }

③ 添加 mapper 接口

  1. Integer update(Integer userId, String password);

④ 添加 xml

  1. <update id="update">
  2. update user set password=#{password} where userId=#{userId}
  3. </update>

⑤ 测试代码

3.4 删除操作

步骤:

  • 添加 实体类(这里有了就不需要添加了)
  • 添加 controller
  • 添加 service
  • 添加 mapper 接口
  • 添加 xml

① 添加 controller

  1. @RequestMapping("/delete")
  2. public Integer delete(Integer userId) {
  3. return userService.delete(userId);
  4. }

② 3.4.2 添加 service

  1. public Integer delete(Integer userId) {
  2. return userMapper.delete(userId);
  3. }

③ 添加 mapper 接口

  1. Integer delete(Integer userId);

④ 添加 xml

  1. <delete id="delete">
  2. delete from user where userId=#{userId}
  3. </delete>

⑤ 测试代码

4. MyBatis 的进阶操作

4.1 返回自增id

这里用增加操作来进行演示

4.1.1 添加 controller 实现代码

  1. @RequestMapping("/insert2")
  2. public Integer insert2(User user) {
  3. if (user == null || user.getUsername() == null
  4. || user.getPassword() == null
  5. || user.getUsername().equals("")
  6. || user.getPassword().equals("")
  7. ) { // 非法参数
  8. return 0;
  9. }
  10. userService.insert2(user);
  11. return user.getUserId();
  12. }

4.1.2 添加 service 实现代码

  1. public void insert2(User user) {
  2. userMapper.insert2(user);
  3. }

4.1.3 添加 mapper 接口

  1. void insert2(User user);

4.1.4 添加 xml

注意: 如果要返回自增id, 就不能像普通增加那样写xml

正确写法:

  1. <insert id="insert2" useGeneratedKeys="true" keyProperty="userId" keyColumn="userId">
  2. insert into user values (null,#{username}, #{password});
  3. </insert>
  • useGeneratedKeys: 这个会取出数据库内部生成的主键, 默认值是false
  • keyColumn: 设置生成键值在表中的列名, 在某些数据库中, 当主键列不是表中第一列的时候, 是必须设置的.如果生成列不止一个, 可以用逗号分隔多个属性名称
  • keyProperty: 指定能够唯一标识对象的属性, 默认值: 未设置(unset), .如果生成列不止一个, 可以用逗号分隔多个属性名称

4.1.5 测试代码

4.2 一对一的表映射

4.2.1 xml中具体的实现

一对一的表映射要使用 <association> 标签, 具体实现

  1. <resultMap id="baseMap" type="com.example.demo.model.User">
  2. <!-- 主键映射 -->
  3. <id column="userId" property="userId"></id>
  4. <!-- 普通映射 -->
  5. <result column="username" property="username"></result>
  6. <result column="password" property="password"></result>
  7. </resultMap>
  8. <resultMap id="BaseMap" type="com.example.demo.model.Blog">
  9. <id column="blogId" property="blogId"></id>
  10. <result column="title" property="title"></result>
  11. <result column="content" property="content"></result>
  12. <result column="postTime" property="postTime"></result>
  13. <result column="userId" property="userId"></result>
  14. <association property="user"
  15. resultMap="com.example.demo.mapper.UserMapper.baseMap"
  16. columnPrefix="u_">
  17. </association>
  18. </resultMap>
  19. <select id="getAll" resultMap="BaseMap">
  20. select b.*,u.userId u_userId,u.username u_username,u.password u_password from blog b left join user u on u.userId=b.userId
  21. </select>

注意事项:

  • property 属性: 指定 Blog 表中对应的属性名, 与实体类一致, 这里是user
  • resultMap 属性: 指定关联的结果集映射, 将基于该映射配置来组织用户数据
  • columnPrefix 属性: 绑定一对一对象时, 多表前缀, 作用防止多张表出现相同字段查询的问题

4.2.2 Blog 实体类

  1. @Data
  2. public class Blog {
  3. public int blogId;
  4. public String title;
  5. public String content;
  6. public Timestamp postTime;
  7. public int userId;
  8. public User user;
  9. }

4.2.3 添加 controll

  1. @RequestMapping("/getall")
  2. public List<Blog> getAll() {
  3. return userService.getAll();
  4. }

4.2.4 添加 service

  1. public List<Blog> getAll() {
  2. return userMapper.getAll();
  3. }

4.2.5 添加 mapper

  1. List<Blog> getAll();

4.2.6 测试运行

4.3 一对多的表映射

4.3.1 xml中具体的实现

一对多使用 <collection> 标签, 用法和 <association>相同

  1. <resultMap id="BaseMap2" type="com.example.demo.model.Blog">
  2. <id column="blogId" property="blogId"></id>
  3. <result column="title" property="title"></result>
  4. <result column="content" property="content"></result>
  5. <result column="postTime" property="postTime"></result>
  6. <result column="userId" property="userId"></result>
  7. <collection property="user"
  8. resultMap="com.example.demo.mapper.UserMapper.baseMap"
  9. columnPrefix="u_">
  10. </collection>
  11. </resultMap>
  12. <select id="getUserById" resultMap="BaseMap2">
  13. select b.*,u.username u_username,u.userId u_userId,u.password u_password from blog b left join user u on b.userId=u.userId where u.userId=#{userId}
  14. </select>

4.3.2 添加 controller

  1. @RequestMapping("/getUserById")
  2. public List<Blog> getUserById(Integer userId) {
  3. return userService.getUserById(userId);
  4. }

4.3.3 添加 service

  1. public List<Blog> getUserById(Integer userId) {
  2. return userMapper.getUserById(userId);
  3. }

4.3.4 添加 mapper接口

  1. List<Blog> getUserById(Integer userId);

4.3.5 测试运行

5. MyBatis 的一些注意事项

5.1 参数占位符 #{} 和 ${}

  • #{} : 预编译处理
  • ${} : 字符直接替换

编译预处理: MyBatis 在处理 #{} 时, 会将SQL 中的 #{} 替换为 ? 号, 使用 PreparedStatementset 方法来赋值.

字符直接替换: MyBatis 在处理 ${} 时, 就是把 ${} 替换成变量的值.(缺点SQL注入)

注意: 当使用 #{} 的时候, 传递值为 String则会加单引号. 使用${}的时候, 就不会加单引号

5.1.1 ${} 的优点

在对一些商品进行排序的时候, 使用${}就可以, 而使用#{}就不行

  1. <select id="getall2" resultType="com.example.demo.model.User">
  2. select * from user order by userId ${sort};
  3. </select>

5.2 SQL 注入问题

  1. <select id="getAll3" resultType="com.example.demo.model.User">
  2. select * from user where username= '${username}' and password='${password}'
  3. </select>

当注入 'or 1='1 时, 所有的信息就暴露了

需要用户传递的就尽量使用 #{}, 程序员自己传递的就可以使用 ${}

5.3 like 查询

like 使用 #{} 会报错
例如一段sql代码
select * from user where username like '%#{username}%';
username=admin 相当于
select * from user where username like '%'admin'%'

这里也不能直接使用 ${}.

可以使用mysql内置函数 concat() 来处理

  1. <select id="findLike" resultType="com.example.demo.model.User">
  2. select * from user where username like concat('%',#{username},'%')
  3. </select>

5.4 实体类中的字段和mysql中的字段不匹配

例如:
这里就查询不到 name了

除了把名字改过来, 还可以使用 resultMap

  1. <resultMap id="baseMap" type="com.example.demo.model.User">
  2. <!-- 主键映射 -->
  3. <id column="userId" property="userId"></id>
  4. <!-- 普通映射 -->
  5. <result column="username" property="name"></result>
  6. <result column="password" property="password"></result>
  7. </resultMap>
  8. <select id="getAll" resultMap="baseMap">
  9. select * from user
  10. </select>

注意这里的resultMap的写法

5.5 想要在控制台查看 mybatis 的日志

在配置文件中添加代码

  1. logging.level.com.example.demo=debug
  2. mybaits.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

通过这样配置就能查看日志了

5.6 编写 MyBatis 更方便的插件

搜索 MyBatisX

下载之后 重启Idea
有这种鸟就是安装好了

6. 动态 SQL

6.1 if 标签

在填写表单的时候 经常会有一些字段必须要填写, 一些字段不必要填写, 那么这种情况就需要用的动态SQL的if标签

xml的演示

  1. <insert id="insert4" useGeneratedKeys="true" keyColumn="blogId" keyProperty="blogId">
  2. insert into blog(
  3. title,
  4. <if test="content != null">
  5. content,
  6. </if>
  7. postTime,userId) values (#{title},
  8. <if test="content != null">
  9. #{content},
  10. </if>
  11. #{postTime},#{userId})
  12. </insert>

注意这里的 if标签后面的test中的content是传入的属性,不是数据库中的字段.

6.2 trim 标签

当所有字段都是非必填项, 此时使用 if 标签就满足不了了

如 title是必填项, 后面都是非必填项, 此时sql拼装出来 就会变成
insert into blog(title,) values (title,) 这里的逗号就会导致sql报错.
<trim> 标签中有如下属性:

  • prefix: 表示整个语句块, 以prefix的值作为前缀
  • suffix: 表示整个语句块, 以suffix的值作为后缀
  • prefixOverrides: prefixOverrides的值表示整个语句块要去掉的前缀
  • suffixOverrides: suffixOverrides的值表示整个语句块要去掉的后缀
  1. <insert id="insert5" useGeneratedKeys="true" keyProperty="userId" keyColumn="userId">
  2. insert into blog
  3. <trim prefix="(" suffix=")" suffixOverrides=",">
  4. <if test="title != null">
  5. title,
  6. </if>
  7. <if test="content != null">
  8. content,
  9. </if>
  10. <if test="postTime != null">
  11. postTime,
  12. </if>
  13. <if test="userId != null">
  14. userId,
  15. </if>
  16. </trim>
  17. values
  18. <trim prefix="(" suffix=")" suffixOverrides=",">
  19. <if test="title != null">
  20. #{title},
  21. </if>
  22. <if test="content != null">
  23. #{content},
  24. </if>
  25. <if test="postTime != null">
  26. #{postTime},
  27. </if>
  28. <if test="userId != null">
  29. #{userId},
  30. </if>
  31. </trim>
  32. </insert>

6.3 where 标签

如代码 select * from blog where userId=#{userId}
如果这里的 userId 是非必填项, 为空, 那么sql也会报错

下面的<where> 标签也可以使用<trim prefix="where" prefixOverrides="and">替换。

  1. <select id="selectAll" resultType="com.example.demo.model.User">
  2. select * from blog
  3. <where>
  4. <if test="blogId != null">
  5. blogId = #{blogId}
  6. </if>
  7. <if test="userId != null">
  8. and userId = #{userId}
  9. </if>
  10. </where>
  11. </select>
  • <where>标签, 如果有查询条件就会生成where, 如果没有查询条件就不会生成where
  • where会判断第一个条件前面有没有and, 如果有就会去掉.

6.4 set 标签

更新的时候也会出现问题, 使用 <set> 标签来解决
set标签和where标签差不多

  1. <update id="testUpdate">
  2. update user
  3. <set>
  4. <if test="username != null">
  5. username=#{username},
  6. </if>
  7. <if test="password != null">
  8. password=#{password},
  9. </if>
  10. </set>
  11. where userId=#{userId}
  12. </update>

6.5 foreach 标签

<foreach>标签有如下属性:

  • collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串
  1. <delete id="testDe">
  2. delete from user where userId in
  3. <foreach collection="list" item="item" open="(" close=")" separator=",">
  4. #{item}
  5. </foreach>
  6. </delete>

相关文章