11. Mybatis 的增删查改【万字详解】

目录

1. 数据的查找 select

1.1 查询所有数据

1.2 通过 id 进行查找

2. 插入数据 insert

3. 修改数据 update

4. 删除数据 delete

5. $ 和 # 的区别

5.1 SQL 注入 用户登录

6. Spring Boot 打印 SQL 日志

7. order by 排序

8. like 查询

9. 通过页面返回数据

10. 总结


在上篇文章中我们介绍了 mybatis 的相关概念,通过 mybatis 对数据库中的数据进行查找,接下来我们将具体的介绍 Mybatis 的增删查改。

同时本篇文章还详细介绍了 $ 和 # 的区别(重点)。

1. 数据的查找 select

1.1 查询所有数据

通过 workbench,我们可以看到数据库中的现有数据:

11. Mybatis 的增删查改【万字详解】_第1张图片

 接下来我们在 UserMapper.xml 文件中添加以下内容:




    

接下来在 UserMapper 类中添加查找方法: 

@Mapper
public interface UserMapper {
    List queryAll();
}

在上述类的方法中右键,选择生成,选择测试,即可生成测试类。接下来,在 UserMapperTest 类中进行自测: 

@Slf4j
@SpringBootTest
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void queryAll() {
        List users = userMapper.queryAll();
        log.info(users.toString());
    }
}

运行结果如下图所示,可以看到查找到了数据库中现有的所有数据: 

1.2 通过 id 进行查找

首先,我们在 UserMapper.xml 文件中添加以下内容:




    
    

接下来在 UserMapper 类中添加查找方法: 

@Mapper
public interface UserMapper {
    // 查询所有数据
    List queryAll();
    // 通过 id 查询数据
    User queryById(@Param("uid") Integer id);
}

 在上述类的方法中右键,选择生成,选择测试,生成测试类:

11. Mybatis 的增删查改【万字详解】_第2张图片

11. Mybatis 的增删查改【万字详解】_第3张图片

 可以看到生成的测试类中包含以下方法:

11. Mybatis 的增删查改【万字详解】_第4张图片

接下来,我们编写测试的代码:

@Slf4j
@SpringBootTest
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void queryAll() {
        List users = userMapper.queryAll();
        log.info(users.toString());
    }

    @BeforeEach
    void setUp() {
        log.info("before...");
    }

    @AfterEach
    void tearDown() {
        log.info("after...");
    }

    @Test
    void queryById() {
        log.info("queryById...");
        User user = userMapper.queryById(1);
        log.info(user.toString());
    }
}

运行结果如下: 

需要注意的是,当我们只有一个参数时,可以不写注解;但是写了注解时,SQL 语句需要和注解中使用的参数保持一致

11. Mybatis 的增删查改【万字详解】_第5张图片

当只有一个参数时,不仅可以不写参数,参数的名称也可以不同,以下两条语句均可以成功执行:

User queryById(Integer id);
User queryById(Integer aaa);

2. 插入数据 insert

我们先来看一下数据库中都有哪些数据:

11. Mybatis 的增删查改【万字详解】_第6张图片

可以看到 id 是自增的,createtime 和 updatetime 都是当前时间,因此我们在插入数据时不用添加。

接下来我们在 UserMapper.xml 文件中添加以下内容:


        insert into userinfo (username,password,photo)values(#{username},#{password},#{photo})

在 UserMapper 类中添加插入方法: 

@Mapper
public interface UserMapper {
    // 查询所有数据
    List queryAll();
    // 通过 id 查询数据
    User queryById(@Param("uid") Integer id);
    // 插入数据
    Integer insert(User user);
}

在上述类的方法中右键,选择生成,选择测试,即可生成测试类,编写测试方法:

@Slf4j
@SpringBootTest
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void queryAll() {
        List users = userMapper.queryAll();
        log.info(users.toString());
    }

    @BeforeEach
    void setUp() {
        log.info("before...");
    }

    @AfterEach
    void tearDown() {
        log.info("after...");
    }

    @Test
    void queryById() {
        log.info("queryById...");
        User user = userMapper.queryById(1);
        log.info(user.toString());
    }

    @Test
    void insert() {
        User user = new User();
        user.setUsername("Danny");
        user.setPassword("123456");
        user.setPhoto("123");
        Integer result = userMapper.insert(user);
        log.info("insert result:"+ result);
    }
}

接下来,在 UserMapperTest 类中进行自测: 

 在 workbench 中可以看到数据插入成功:

11. Mybatis 的增删查改【万字详解】_第7张图片


还可以通过第二种方法插入数据:

Integer insert2(@Param(("userinfo")) User user);
 
        insert into userinfo (username,password,photo)values(#{userinfo.username},#{userinfo.password},#{userinfo.photo})
 

 添加测试方法:

 @Test
    void insert2() {
        User user = new User();
        user.setUsername("Danny");
        user.setPassword("123456");
        user.setPhoto("123");
        Integer result = userMapper.insert2(user);
        log.info("insert result:"+ result);
    }

可以看到,同样能够运行成功:

11. Mybatis 的增删查改【万字详解】_第8张图片

需要注意的是,如果使用了 @Param 注解,就必须使用 @Param 注解的命名

获取自增 id

在 UserMapper.xml 文件中添加以下内容:


        insert into userinfo (username,password,photo)values(#{userinfo.username},#{userinfo.password},#{userinfo.photo})
    

在 UserMapperTest 类中添加以下内容:

@Test
    void insert2() {
        User user = new User();
        user.setUsername("Danny");
        user.setPassword("123456");
        user.setPhoto("123");
        Integer result = userMapper.insert2(user);
        log.info("insert result:"+ result + ", 自增id:" + user.getId());
    }

此时可以看到自增 id 为:5. 

11. Mybatis 的增删查改【万字详解】_第9张图片

3. 修改数据 update

在修改数据库的数据之前,我们先来看一下此时数据库中的数据:

11. Mybatis 的增删查改【万字详解】_第10张图片

接下来我们修改 id = 3 的这行数据:

在 UserMapper.xml 文件中添加以下内容:


        update userinfo set username = #{username},password = #{password} where id = #{id}
    

在 UserMapper 类中添加修改方法:

@Mapper
public interface UserMapper {
    // 查询所有数据
    List queryAll();
    // 通过 id 查询数据
    User queryById(@Param("uid") Integer id);
    // 插入数据
    Integer insert(User user);
    Integer insert2(@Param(("userinfo")) User user);
    // 修改数据
    void update(User user);
}

在上述类的方法中右键,选择生成,选择测试,即可生成测试类,编写测试方法:

 @Test
    void update() {
        User user = new User();
        user.setId(3);
        user.setUsername("Jenny");
        user.setPassword("root123456");
        userMapper.update(user);
    }

接下来,在 UserMapperTest 类中进行自测: 

运行成功后,可以看到数据库中 id =3 这一行的数据已经被修改了:

11. Mybatis 的增删查改【万字详解】_第11张图片

4. 删除数据 delete

我们先来看一下此时数据库中的数据:

11. Mybatis 的增删查改【万字详解】_第12张图片

接下来我们删除 id = 4 的这行数据:

在 UserMapper.xml 文件中添加以下内容:


        delete from userinfo where id = #{id}
    

在 UserMapper 类中添加修改方法: 

@Mapper
public interface UserMapper {
    // 查询所有数据
    List queryAll();
    // 通过 id 查询数据
    User queryById(@Param("uid") Integer id);
    // 插入数据
    Integer insert(User user);
    Integer insert2(@Param(("userinfo")) User user);
    // 修改数据
    void update(User user);
    // 通过 id 删除数据
    void delete(Integer id);
}

在上述类的方法中右键,选择生成,选择测试,即可生成测试类,编写测试方法:

 @Test
    void delete() {
        userMapper.delete(4);
    }

接下来,在 UserMapperTest 类中进行自测: 

运行成功后,可以看到数据库中 id =4 这一行的数据已经被删除了:

11. Mybatis 的增删查改【万字详解】_第13张图片

5. $ 和 # 的区别

我们将通过 id 查询的 xml 文件中的 # 改成 $:

 

可以看到依然可以查询到数据: 

11. Mybatis 的增删查改【万字详解】_第14张图片

接下来我们使用 # 通过名称来查询:

User queryByName(String name);
 
@Test
    void queryByName() {
        log.info("queryByName...");
        User user = userMapper.queryByName("Jenny");
        log.info(user.toString());
    }

可以看到成功查询到数据: 

接下来我们使用 $ 通过名称来查询:

修改 xml 文件:

运行代码后出现以下报错:

11. Mybatis 的增删查改【万字详解】_第15张图片

是因为 $ 符号传递的参数是没有加引号,直接放在参数中的

那么,如果我们自行添加引号呢?

此时我们可以看到成功运行了: 

11. Mybatis 的增删查改【万字详解】_第16张图片

综上,我们来看一下其中的本质原因:

  • #{} :预编译处理(占位)
  • ${}:字符直接替换(字符的内容直接当作 SQL 的一部分来运行,SQL 注入影响程序的安全

 当我们执行以下 SQL 语句时,会发现数据库中的所有数据都被查出来了:

SELECT * FROM userinfo where username = '' or 1 = '1'

11. Mybatis 的增删查改【万字详解】_第17张图片

5.1 SQL 注入 用户登录

我们先在数据库中保留以下信息:

我们先来测试 # 正确查询:

User queryByNameAndPassword(@Param("username") String username,@Param("password") String password);
 @Test
    void queryByNameAndPassword() {
        String username = "admin";
        String password = "admin";
        User user = userMapper.queryByNameAndPassword(username,password);
        log.info(user.toString());
    }

可以看到查询成功: 

再来测试 # 错误查询,直接修改测试方法:

@Test
    void queryByNameAndPassword() {
        String username = "admin";
        String password = "admin123";
        User user = userMapper.queryByNameAndPassword(username,password);
        log.info(user==null?null:user.toString());
    }

可以看到查询为空:

11. Mybatis 的增删查改【万字详解】_第18张图片

接下来测试 SQL 注入的情况:

@Test
    void queryByNameAndPassword() {
        String username = "admin";
        String password = "'or 1 ='1";
        User user = userMapper.queryByNameAndPassword(username,password);
        log.info(user==null?null:user.toString());
    }

可以看到使用错误的 password 显示为 null ,数据没有被查询出来:


接下来测试 $ 正确查询:

@Test
    void queryByNameAndPassword() {
        String username = "admin";
        String password = "admin";
        User user = userMapper.queryByNameAndPassword(username,password);
        log.info(user==null?null:user.toString());
    }

可以看到成功查询到: 

接下来我们输入错误的 password :

@Test
    void queryByNameAndPassword() {
        String username = "admin";
        String password = "admin123";
        User user = userMapper.queryByNameAndPassword(username,password);
        log.info(user==null?null:user.toString());
    }

可以看到没有查询到数据,显示为 null: 

接下来我们来看 SQL 注入的情况:

@Test
    void queryByNameAndPassword() {
        String username = "admin";
        String password = "'or 1 ='1";
        User user = userMapper.queryByNameAndPassword(username,password);
        log.info(user==null?null:user.toString());
    }

 可以看到数据仍然被查询出来了:

那么 SQL 注入简单来说就是将本来不该被查询出来的数据,查询出来了。

6. Spring Boot 打印 SQL 日志

添加配置文件:

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

11. Mybatis 的增删查改【万字详解】_第19张图片

可以看到直接将对应的 SQL 语句打印在了控制台:

11. Mybatis 的增删查改【万字详解】_第20张图片

以上就是 $ 打印的结果,是直接进行替换了。

接下来我们看一下 # 打印的结果:

11. Mybatis 的增删查改【万字详解】_第21张图片

所以,# 就是进行预编译,采用占位的方式。

7. order by 排序

我们先来看一下此时数据库中的数据:

11. Mybatis 的增删查改【万字详解】_第22张图片

接下来我们根据 id 进行降序排列:

List queryByOrder(String order);
@Test
    void queryByOrder() {
        List users = userMapper.queryByOrder("desc");
        log.info(users.toString());
    }

我们可以看到运行之后的结果并没有像我们想象之中的那样降序排列,而是直接报错:

11. Mybatis 的增删查改【万字详解】_第23张图片

那么上述这种情况下,就无法使用 # 必须使用 $ 符号才可以。

所以排序时只能使用 $。

修改 xml 文件:

 

此时可以看到成功进行了降序排列:

11. Mybatis 的增删查改【万字详解】_第24张图片

但是只要使用了 $ 就存在 SQL 注入的问题,该如何解决呢?

要从根源上解决以上问题就是不让用户输入 SQL 语句,用户只能点击,参数由后端进行拼接,后端在查询之前,对参数进行校验,只能传两个值:desc(降序) 和 asc(升序)。

8. like 查询

我们先来看一下 SQL 语句的 like 查询:

SELECT * FROM userinfo where username like "%m%";

11. Mybatis 的增删查改【万字详解】_第25张图片

接下来我们使用 # 来查询: 

List queryByLike(String name);
@Test
    void queryByLike() {
        List users = userMapper.queryByLike("m");
        log.info(users.toString());
    }

可以看到无法正确查询: 

11. Mybatis 的增删查改【万字详解】_第26张图片

接下来我们改成 $ 进行查询:

 

此时,我们可以看到查询到了数据: 

11. Mybatis 的增删查改【万字详解】_第27张图片

但是使用了 $ 就存在 SQL 注入的问题,因此我们需要使用 MySQL 的一个内置函数。

SELECT * FROM userinfo where username like concat('%','m','%');

可以看到使用以上 SQL 语句也可以进行查询: 

11. Mybatis 的增删查改【万字详解】_第28张图片

因此,我们修改 xml 文件如下:

可以看到使用 concat 函数后可以查询成功:

11. Mybatis 的增删查改【万字详解】_第29张图片

9. 通过页面返回数据

11. Mybatis 的增删查改【万字详解】_第30张图片

新建 UserController 类: 

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/selectAll")
    public List selectAllUser(){
        return userService.selectAllUser();
    }
}

 新建 UserService 类:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public List selectAllUser() {
        return userMapper.queryAll();
    }
}

接下来我们运行启动类,即可在页面中看到查找的数据库信息: 

10. 总结

  1. $ 存在 SQL 注入问题,因为 # 是预编译而 $ 是字符替换;
  2. orde by 只能使用 $,通过后端控制参数的输入(只能为 desc 和 asc);
  3. # 直接用于 like 查询会报错,需要使用 MySQL 的内置函数 concat 进行字符连接

11. Mybatis 的增删查改【万字详解】_第31张图片

你可能感兴趣的:(java,ee,mybatis)