MyBatis(MyBatis环境搭建,单表操作)

目录

MyBatis 环境搭建

 1.添加 Mybatis 框架支持

2.设置 MyBatis 配置信息

2.1.设置数据库连接的相关信息

2.2 Mybatis xml 保存路径和 xml命名格式

​编辑 MyBatis 模式开发

Mybatis xml 模板

查询表内容

单元测试

以根据id,查询用户对象这个方法为例

 获取动态参数的俩种方式 ${param} #{param}

${param}

 #{param}

各种MyBatis单表操作

如果传递的参数为一个对象,如何获取对象里面的属性?

 用户的修改

删除用户

添加用户

1.返回值为受影响行数

​编辑2.返回受影响的行数和id

根据用户名模糊查询

返回字典映射 resultMap


什么是MyBatis?:更加简单的帮助程序实现数据库操作的工具

MyBatis 环境搭建

 1.添加 Mybatis 框架支持

MyBatis项目不仅要添加MyBatis Framework的依赖,还要添加添加MySql Driver依赖(用于指定连接数据库的类型,这里我们使用MySql数据库,所以需要引入MySql Driver依赖,如果是别的类型数据库类型同理,比如使用MariaDB数据库,此处就可以引用MariaDB Driver依赖)

2.设置 MyBatis 配置信息

2.1.设置数据库连接的相关信息

在配置文件中配置如下信息

#设置数据库连接信息
spring:
  datasource:
    url:  jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=false
    usename: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

2.2 Mybatis xml 保存路径和 xml命名格式

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

这里交代了Mybatis xml的保存路径,在本地一个叫mybatis包底下,后缀为Mapper.xml的文件

 MyBatis 模式开发

1. interface: 让其他层可以注入使用的接口

2.mybatis: xml 具体实现sql(它是上述interface的实现)

Mybatis 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.example.demo.mapper.UserMapper">
   
</mapper>

注意这里的namespace表示当前xml实现的类是哪个类,这里就表示当前xml实现的类是UserMapper这个类

查询表内容

以实现查询操作为例,现在有一个mycnblog数据库,里面有一张用户表(userinfo)

表里的内容如下

.
这张表映射到Java中的UserEntity的实体类如下 

@Data
public class UserEntity {
    private Integer id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private Integer state;
}

首先实现实现一个MyBatis的接口

@Mapper//表示这是一个Mybatis接口,需要和xml对应起来
public interface UserMapper {
    List<UserEntity> getAll();
}

 实现这个接口对应的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.example.demo.mapper.UserMapper">
    <select id="getAll" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo
    </select>
</mapper>

此处我们需要进行查询操作,所以需要使用select标签,同理如果是添加操作.需要使用insert标签
此处的id,是我们要实现的这个类里面的某个方法的方法名
此处的resultType是我们要返回的数据类型

使用service层调用该接口

import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    public List<UserEntity> getAll(){
        return userMapper.getAll();
    }
}

使用controller调用service层的接口

package com.example.demo.controller;

import com.example.demo.entity.UserEntity;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("getAll")
    public List<UserEntity> getAll(){
        return userService.getAll();
    }
}

我们此时在网页中访问这个getAll方法

 上述测试getAll方法的过程比较繁琐,需要调用controller层,service层.且如果测试的是修改,添加等方法也会污染数据库.所以接下来我们使用单元测试的方法

单元测试

单元测试优点

1.可以非常简单,直观,快速的测试某一个功能是否正确

2.使用单元测试可以帮助我们在快速打包时发现一些问题,在打包之前,所有的单元测试必须通过,否则不能打包成功

3.使用单元测试在测试功能的时候,不污染连接的数据库,可以不对数据库进行任何改变的情况下,测试功能

4.可以跳过系统限制(登录校验,权限检验),直接测试想要测试的方法

SpringBoot项目会默认自带一个单元测试的框架(由JUnit实现),咱们直接用就好了

以根据id,查询用户对象这个方法为例

同样实现一个mapper接口

@Mapper//表示这是一个Mybatis接口,需要和xml对应起来
public interface UserMapper {
    List<UserEntity> getAll();
    //根据id 查询用户对象
    UserEntity getUserById(@Param("id")Integer id);
}

这里的@Param("id"),意思是给这个叫做id的参数,重新起了个叫id的名字,之后在xml中,就以Param里面的名字为准

实现这个接口对应的xml

<select id="getUserById" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo where id = ${id}
    </select>

这里 id = ${id} 左边的"="号左边的id是数据库userinfo表里面的叫id的字段,右边的id就是我们之前在mapper接口传入的参数id,这里使用${}的方式是为了获取到属性中的id的值,如果直接写id=id,那么左边的id拿到的就是id这个字符串,而不是传入给id的值.

在我们想要测试的方法上右键生成

点击Test,勾中我们想要测试的方法

 会在test底下和main一样的包路径下,生成一个Test的类,里面有我们要测试的方法

此时我们需要在这个自动生成的类 添加一些注解@SpringBootTest

@SpringBootTest // 表示当前单元测试的类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper; //把我们需要测试的方法的类注入过来
    @Test
    void getUserById() {
        UserEntity user = userMapper.getUserById(1);
        System.out.println(user);
    }
}

点击此处运行该方法 

 在控制台有我们输出的user打印信息,测试成功

 获取动态参数的俩种方式 ${param} #{param}

${param}

把${param}直接替换成传过来的参数,所见即所得,比如如果我们需要的参数是字符类型,这种获取参数的方式默认是没有字符需要的引号的.且这种方式会出现sql注入的问题,容易出现安全性问题,适用于我们需要传递一些sql指令的场景(如传递排序方式),在使用时,我们需要保证我们输入的值可以被枚举(保证不被sql注入).

 #{param}

把#{param}用一个占位符代替,再把参数传给这个占位符,是预处理

各种MyBatis单表操作

如果传递的参数为一个对象,如何获取对象里面的属性?

例如实现一个登录的方法

mapper接口

@Mapper//表示这是一个Mybatis接口,需要和xml对应起来
public interface UserMapper {
    //根据名称查询用户对象
    UserEntity login(UserEntity user);
}

xml

<select id="login" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo where username = #{username} and password = #{password}
    </select>

这里我们没有使用user.getUserName的方式获取username,而是直接输入username,password原因是MyBatis已经帮我们映射好了.

进行单元测试

 @Test
    void getUserByName() {
        UserEntity userLogin = new UserEntity();
        userLogin.setUsername("admin");
        userLogin.setPassword("admin");
        UserEntity user = userMapper.login(userLogin);
        System.out.println(user);
    }

 用户的修改

修改用户密码

mapper接口

//修改密码  返回值为受影响的行数
    int updatePassword(@Param("id") Integer id,
                       @Param("password") String password,
                       @Param("newPassword")String newPassword);

xml

<update id="updatePassword">
    update userinfo set password = #{newPassword} where id = #{id} and password=#{password}
</update>

update标签设置一个参数就可以了,不需要设置返回值,当使用upadate标签时,默认会返回一个受影响的行数,不需要再设置了

单元测试

 @Transactional // 事务 加了此注解单元测试就不会污染数据库了
 @Test
    void updatePassword() {
        int result = userMapper.updatePassword(1,"admin","123456");
        UserEntity user = userMapper.getUserById(1);
        System.out.println("修改  "+result);
        System.out.println(user);
    }

删除用户

mapper接口

//删除用户
    int delById(@Param("id") Integer id);

xml

<delete id="delById">
        delete from userinfo where id = #{id}
    </delete>

使用delete标签来进行删除操作,和修改操作一样,delete标签不需要设置返回值,默认返回值是int,受影响的行数

单元测试

 @Transactional
    @Test
    void delById() {
        int result = userMapper.delById(1);
        UserEntity user = userMapper.getUserById(1);
        System.out.println("删除 "+result);
        System.out.println(user);
    }

添加用户

1.返回值为受影响行数

mapper接口

 //添加用户
    int addUser(UserEntity user);

 xml

<insert id="addUser">
        insert into userinfo(username,password) values(#{username},#{password})
    </insert>

同样,当我们返回值是受影响行数时,不需要设置返回值

单元测试

 @Test
    void addUser() {
        UserEntity user = new UserEntity();
        user.setUsername("白杨");
        user.setPassword("123456");
        int result = userMapper.addUser(user);
        UserEntity user2 = userMapper.getUserByName("白杨");
        System.out.println(result);
        System.out.println(user2);
    }


2.返回受影响的行数和id

mapper接口

int addUserGetId(UserEntity user);

xml

<insert id="addUserGetId" useGeneratedKeys="true" keyProperty="id">
        insert into userinfo(username,password) values(#{username},#{password})
    </insert>

 useGeneratedKeys为是否要拿到数据库自增的id,keyProperty = id 为把刚刚拿到的id赋值给userinfo对象中的id属性

单元测试

@Test
    void addUserGetId() {
        UserEntity user = new UserEntity();
        user.setUsername("杰尼龟");
        user.setPassword("123456");
        int result = userMapper.addUserGetId(user);
        UserEntity user2 = userMapper.getUserByName("杰尼龟");
        System.out.println(result);
        System.out.println(user2);
        System.out.println(user.getId());
    }

 

注意在单元测试代码中,我们并没有给user的id属性赋值,而执行流addUserGetId方法后,我们却能拿到Id,这就是  useGeneratedKeys和keyProperty的作用了

根据用户名模糊查询

mapper接口

 //根据用户名模糊查询
    List<UserEntity> getListByName(@Param("username")String username);

xml

<select id="getListByName" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo where username like concat('%','#{username}','%')
    </select>

使用concat字符串拼接,如果写成'%#{username}%',此时如果传入的username为"白",在数据库里面看到的会是:'%'白'%',占位符会自动添加双引号,所以我们这里用字符串拼接的方式

单元测试

@Test
    void getListByName() {
        String username = "白";
        List<UserEntity> list = userMapper.getListByName(username);
        list.stream().forEach(System.out::println);
    }

返回字典映射 resultMap

使用场景:字段名称和程序中的属性名不同,可以使用 resultMap 配置映射
一对一和一对多关系可以使用 resultMap 映射并查询数据库

例如当我们程序中UserEntity这个类映射数据库userinfo这张表时,UserEntity的属性名为pwd,而userinfo的字段名为password

@Data
public class UserEntity {
    private Integer id;
    private String username;
    private String pwd;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private Integer state;
}

userinfo表内容

同样以根据用户名模糊查询这个方法为例

mapper接口

//根据用户名模糊查询
    List<UserEntity> getListByName(@Param("username")String username);

xml

 <resultMap id="BaseMap" type="com.example.demo.entity.UserEntity">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="pwd" column="password"></result>
    </resultMap>
    <select id="getListByName" resultMap="BaseMap">
        select * from userinfo where username like concat('%',#{username},'%')
    </select>

id="BaseMap"表示给当前resultMap字典起了个叫BaseMap的名字,type表示当前这个resultMap这个字典,用来映射哪个实体类 
<id></id>这里面放的是主键  property = "id",column = "id"意思是程序中的属性id对应数据库中的id字段
<result></result>放的是普通的字段 property = "pwd" column = "password"意思是程序中的属性 pwd,对应数据库中的password字段
我们想要映射几个属性和字段,就需要写几个

单元测试

  @Test
    void getListByName() {
        String username = "白";
        List<UserEntity> list = userMapper.getListByName(username);
        list.stream().forEach(System.out::println);
    }

 当然上述方法可能有点繁琐,我们也可以通过调整sql语句实现这种功能(通过as重命名)

xml:

  <select id="getListByName" resultType="com.example.demo.entity.UserEntity">
        select id,username,password as pwd from userinfo where username like concat('%',#{username},'%')
    </select>

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值