利用MyBatis框架操作数据库

目录

一、MyBatis框架简介

二、创建Mybatis项目 

1、在Mysql中创建要进行操作的数据库和数据表。

2、创建项目并添加MyBatis依赖。

3、配置MyBatis连接字符串以及保存的xml目录。 

4、添加业务代码

三、利用MyBatis操作数据库

增加数据

删除数据 

修改数据 

查询数据 

like 模糊查询

多表查询 

四、动态SQL 

if标签 

trim标签 

where标签 

set标签 

foreach标签 


一、MyBatis框架简介

MyBatis是一个持久化框架,支持自定义SQL、存储过程以及高级映射,是一个优秀的ORM(对象关系映射)的框架。

MyBatis框架的特点就是比较灵活。

二、创建Mybatis项目 

1、在Mysql中创建要进行操作的数据库和数据表。

2、创建项目并添加MyBatis依赖。

利用MyBatis框架操作数据库_第1张图片

#配置数据库的连接信息
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

3、配置MyBatis连接字符串以及保存的xml目录。 

配置数据库连接信息:

#配置数据库的连接信息
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

xml文件保存路径:

#设置MyBatis的xml保存路径
mybatis:
  mapper-locations: classpath:mybatis/**Mapper.xml

4、添加业务代码

a、创建model包,添加UserInfo实体类:

@Data
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private String photo;
    private String createTime;
    private String updateTime;
    private int state;
}

b、创建mapper包,定义UserMapper接口:

@Mapper
public interface UserMapper {
    public UserInfo getUserInfoById(@Param("id") Integer id);

}

在resources目录下创建mybatis文件夹,创建UserMapper.xml文件,文件内容如下,其中select标签的id表示要执行的方法名,resultType表示返回的类的路径:





    

创建service包,创建UserService类,获取到UserMapper并实现getUserInfoById方法:

@Service
public class UserService {
    @Resource
    public UserMapper userMapper;
    public UserInfo getUserInfoById(Integer id){
        return userMapper.getUserInfoById(id);
    }
}

创建controller包,创建UserController类,获取到UserService类并实现getUserInfoById方法:

@Controller
public class UserController {
    @Autowired
    private UserService userService;
    @ResponseBody
    @RequestMapping("/getuserinbyid")
    public UserInfo getUserInfoById(Integer id){
        if(id == null){
            return null;
        }
        return userService.getUserInfoById(id);
    }
}

访问验证:

三、利用MyBatis操作数据库

在操作数据库之前,首先了解一下单元测试,单元测试可以针对某一方法进行测试,并且不需要再启动SpringBoot项目,使用单元测试有如下好处:

  • 使用单元测试可以非常直观、简单地测试某一功能的正确性;
  • 使用单元测试可以帮助在打包的时候发现一些错误,因为在打包之前要求所有的单元测试都必须通过。
  • 使用单元测试不会对原有的数据库造成污染。

如果不想对数据库造成污染,就需要添加@Transactional注解,其原理是先执行sql语句,在进行回滚操作。

使用单元测试的一般步骤:

先生成单元测试的类:

 在接口中右击鼠标,单击generate:

利用MyBatis框架操作数据库_第2张图片

选择test,出现如下界面:

利用MyBatis框架操作数据库_第3张图片

 点击ok之后就会自动生成测试类。

增加数据

增加一条用户信息,并返回受影响的行数。

首先需要在UserMapper接口中声明方法。

 //添加用户信息,返回受影响的行数
    public int addUserInfo(UserInfo userInfo);

然后需要在resources文件夹下的MyBatis文件下的UserMapper.xml文件中新增如下的insert标签:


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

在生成的测试类中编写代码:

    @Test
    void addUserInfo() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(2);
        userInfo.setUsername("lucy");
        userInfo.setPassword("1234");
        userInfo.setPhoto("test.jpg");
        int i =userMapper.addUserInfo(userInfo);
        Assertions.assertEquals(1,i);//使用断言测试返回受影响的行数是否为1
    }

启动单元测试的结果:

由于当时在新建数据表时id是默认自增的,就需要在xml文件中的 insert添加如下属性:


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

删除数据 

删除指定id的用户信息,并返回受影响的行数。

在UserMapper接口中定义删除数据的方法:

@Transactional //删除用户信息不污染数据库
    //根据ID查询User信息
    public int deleteUserInfo(@Param("id") Integer id);

在xml文件下添加delete标签:

    
    
        delete from userinfo where id=#{id}
    

在测试类中编写代码:

    //根据ID删除UserInfo信息
    @Test
    void deleteUserInfo() {
        int i =userMapper.deleteUserInfo(3);
        Assertions.assertEquals(1,i);//使用断言测试返回受影响的行数是否为1
    }

启动单元测试运行结果:

利用MyBatis框架操作数据库_第4张图片

修改数据 

修改指定id的用户名。

在UserMapper接口中定义修改数据方法:

//根据id修改用户名
    public int updateUserInfo(@Param("id") Integer id,@Param("username") String username);

在xml文件中添加update标签:


    
        update userinfo set username=#{username} where id=${id}
    

在生成的测试类中编写测试代码:

//根据id修改用户名
    @Test
    void updateUserInfo() {
        int i = userMapper.updateUserInfo(2,"mary");
        Assertions.assertEquals(1,i);//使用断言测试返回受影响的行数是否为1
    }

测试运行结果:

利用MyBatis框架操作数据库_第5张图片

查询数据 

根据id查询用户信息。

在UserMapper中定义查询方法:

@Transactional
    //根据id查询UserInfo信息
    public UserInfo getUserInfoById(@Param("id") Integer id);

在xml文件中添加select标签,其中resultType标签表示返回的对象所属类的路径


    

在测试类中编写测试代码:

//通过id查询用户信息
    @Test
    void getUserInfoById() {
        UserInfo userInfo = userMapper.getUserInfoById(1);
        Assertions.assertNotNull(userInfo);
    }

测试运行结果:

利用MyBatis框架操作数据库_第6张图片

在之前的xml文件中使用${}和#{} 这两种参数占位符,那么这两种占位符有如下区别:

定义不同:${}直接替换,#{}会进行预处理;

用法不同:${}只适用于整数替换,#{}适合所有的数据类型;

安全性不同:${}会导致sql注入安全问题,#{}的性能高,并且不存在安全问题。

${}如何会引起sql注入呢?

在userinfo信息表中有username和password两个属性,那么在查询的时候给password属性传入‘or 1= ‘1’’就会导致查出所有的用户信息包含用户的密码:

xml文件中新增如下的select标签:


    

使用如下测试代码:

 //根据用户名和密码查询用户信息
    @Test
    void getUserInfoByNameAndPwd() {
        String username = "admin";
        String password = "''or 1 ='1'";
        userMapper.getUserInfoByNameAndPwd(username,password);
    }

查询到了所有的userinfo导致sql注入问题:
利用MyBatis框架操作数据库_第7张图片 但是将参数占位符换为#{},再进行测试:

 #{}占位符会进行预处理,不会直接进行替换,就不会出现sql注入的问题。

那么?{}就没有应用场景了吗?答案当然是否定的,任何东西存在即合理,当传递的参数是sql关键字或sql命令时就需要使用?{}占位符,因为需要直接替换,不需要#{}来进行预处理为字符串,否则就会报错。

like 模糊查询

在sql语句进行查询时也会经常用到like模糊查询,%表示0或多个字符,_表示一个字符,那么先使用?{}占位符来查询username中含有‘a’字符的用户信息。

xml的select标签的信息如下:

测试结果:

并不能完成直接替换,那么使用#{}参数占位符来进行测试,测试结果如下:

这两种参数占位符都不能直接实现模糊查询,就需要使用mysql中的内置函数concat来进行处理,将xml文件中的select标签的内容修改如下: 

    
    

测试结果如下:

利用MyBatis框架操作数据库_第8张图片

多表查询 

上述的操作都是在单表的基础上进行,但是查询还存在多表查询,常见的表关系有一对一、一对多和多对多,那么利用MyBatis就可以实现一对一和一对多的多表查询。

一对一的多表查询 

在mycnblog数据库中有userinfo和articleinfo表,两个表的字段设置如下所示:

利用MyBatis框架操作数据库_第9张图片

利用MyBatis框架操作数据库_第10张图片

其中articleinfo表的uid对应userinfo表的的id。 

查询文章对应的用户信息。 

首先在model包下创建ArticleInfo类,将articleinfo表的字段作为ArticleInfo类的属性,并添加UserInfo属性。 

@Data
public class ArticleInfo {
    private int id;
    private String title;
    private String content;
    private String createtime;
    private String updatetime;
    private int uid;
    private int rcount;
    private int state;
    private UserInfo userInfo;
}

在Mapper包下创建ArticleMapper接口,定义id获取文章信息的方法:

 //通过文章id来获取文章信息
    public ArticleInfo getUserInfoByArticleInfoId(@Param("id") Integer id);

在mybatis包下创建ArticleMapper.xml文件,添加select标签,由于要实现多表查询,select标签的ResultType标签就无法满足需求了,就需要添加一个resultMap标签, 其id为标签名,type为要映射的实体类的路径,在该标签中设置主键(id)和其他普通的字段(result),其中column为数据库字段名,property为程序中的属性名,并且在UserMapper.xml文件中也添加resultMap标签,然后在ArticleMapper.xml的resultMap标签中继续添加association标签,property代表要连接的表在程序中的属性名,resultMap为UserMapper.xml文件中的resultMap标签名称,由于userinfo表和articleinfo表中有同名的字段名,就使用columnPrefix属性,表示在原有字段名前添加设置的columnPrefix属性值,UserMapper.xml文件的resultMap标签如下:


        
        
        
        
        
        
        
        
        
        
 

ArticleMapper.xml文件的内容如下:


        
        
        
        
        
        
        
        
        
        
        
        
    
    

最后在生成的test类中编写测试方法:

 //通过id获取文章信息,实现一对一的多表查询
    @Test
    void getUserInfoByArticleInfoId() {
        ArticleInfo articleInfo  = articleMapper.getUserInfoByArticleInfoId(1);
        log.info(String.valueOf(articleInfo));
    }

测试结果:

 日志中的信息:

 createtime等字段为null因为在查询的时候就没有select这些字段。

一对多的多表查询

一个用户对应多篇文章,就需要使用一对多的多表查询。

先在UserInfo类中增加一个存放文章信息的集合:

private List atrlist;

然后再UserMapper接口中定义查询方法:

 //根据id查询用户信息,并实现一对多的多表查询
 public UserInfo getUserInfoAndArtInfoById(@Param("id") Integer id);

在UserMapper.xml文件的resultMap标签中添加collection标签,其属性与association标签的属性值类似:


再添加select标签:

    
    

在生成的测试类中编写如下的代码:

    @Test
    void getUserInfoAndArtInfoById() {
        UserInfo userInfo = userMapper.getUserInfoAndArtInfoById(1);
        log.info(String.valueOf(userInfo));
    }

测试结果:

 日志中的文章信息如下:

四、动态SQL 

在上述的操作中都使用的是固定的参数,并且有时会多写,等都会出现报错,但动态SQL就能很好的解决上述问题。

if标签 

if标签的test属性可以判断参数是否有值,如果没有值,就会隐藏if标签中的参数。

非必传的参数就可以使用if标签。

例如新增一个Userinfo信息,username和id为必传信息,但是photo信息为非必传。

那么UserMapper的insert标签如下:


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

在传入参数的时候未传入photo参数:

@Test
    void addUserInfoByIf() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("老6");
        userInfo.setPassword("1234");
        int i = userMapper.addUserInfoByIf(userInfo);
        Assertions.assertEquals(1,i);
    }

测试结果:

利用MyBatis框架操作数据库_第11张图片

trim标签 

trim标签有如下的属性:

  • prefix:整个语句块,以prefix的值作为前缀;
  • suffix:整个语句块,以suffix的值作为后缀;
  • prefixOverrides:表示整个语句块要去除掉的前缀;
  • suffixOverrides:表示整个语句块要去除掉的后缀。

那么, 上面新增一个Userinfo信息就可以使用trim标签,修改xml标签的内容如下:


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

测试结果:

利用MyBatis框架操作数据库_第12张图片

where标签 

where标签可以实现查询中的where语句替换,如果where中没有任何查询条件,那么就会删除where语句,如果有查询条件,就会自动生成相应的sql语句,并可以自动去除最前面的and标签,where标签通常搭配if标签来进行使用。

例如利用名字和密码查询用户信息: 

UserMapper.xml的查询标签如下所示:

 
    

当传入用户名和密码之后测试结果如下:

利用MyBatis框架操作数据库_第13张图片

where标签也可以使用标签进行替换:

 

set标签 

set标签是针对update更新语句的,可以代替update标签中的set关键字来完成。

set标签通常需要搭配if标签来进行使用。

例如利用id来修改用户信息。

在xml文件中的update标签如下:

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

在测试类中的测试代码如下:

    @Test
    void updateUserInfoById() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("王五");
        userInfo.setPassword("9087");
        userInfo.setId(3);
        int i = userMapper.updateUserInfoById(userInfo);
        Assertions.assertNotNull(i);
    }

测试结果:

 

set标签也可以用trim标签进行替代 

foreach标签 

对集合遍历时通常会使用该标签,在in关键字之后通常使用,该标签有如下的属性:

collection:绑定方法参数的集合,如List、Set、Map以及数组等;

item:遍历时的每个对象;

open:语句块开头的字符串;

close:语句块结束的字符串;

separator:每次遍历之间的字符串。 

例如删除id在指定集合的用户信息:

xml文件中的delete标签如下:

    
        delete
        from userinfo
        where id in 
        #{uid}
    
    

在生成的test类编写的测试代码如下:

    @Test
    void deleteUserInfoByList() {
        List list = new LinkedList<>();
        list.add(4);
        list.add(3);
        list.add(5);
        int i = userMapper.deleteUserInfoByList(list);
        log.info(String.valueOf(i));
    }

测试结果:

 ​​​​​​​

 

你可能感兴趣的:(JavaEE,mybatis,数据库,mysql)