Mybatis基础操作

在这里插入图片描述

一. Mybatis单表操作

删除操作

在这里插入图片描述
我们接着使用昨天的表和程序,我们来实现通过id删除数据:
在这里插入图片描述
我们这样就可以实现将id = 1的数据进行删除了,但是这样有什么问题呢?这样把代码写死了,所以我们需要动态的接收id来进行删除。
这里介绍两种MyBatis获取参数的两种实现:
1.#{} 占位符替换
2.${} 字符串拼接
这会我们先用,后面给大家讲解区别

// 注解方式
@Delete("delete from userinfo where id = #{id}}")
    int deleteById(Integer id);

xml方式:
在这里插入图片描述
我们来测试一下结果,但是我们并不想真正的进行落盘操作,所以我们在执行方法时开启事务:
在这里插入图片描述
在这里插入图片描述
但是我们目前并不能看到Mybatis底层到底执行了什么样的sql语句,我们其实可以借助Mybatis的日志看到的,但是默认是关闭的,我们需要手动开启。
在yml配置文件配置以下信息:

# 配置mybatis的日志,指定输出到控制台
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

再次执行test,我们发现不仅打印了sql信息,而且还显示了我们在Test中执行完毕进行Rolled back
在这里插入图片描述

查询操作

根据id查询员工信息
在这里插入图片描述

<select id="getById" resultType="com.example.demo.entity.User">
        select * from userinfo where id = #{id}
</select>

在这里插入图片描述

在这里插入图片描述

这里大家需要注意一件事:
当我们进行查询操作时,会进行数据库信息到实体对象是数据封装,这里分为两种情况:
1.实体类属性名和数据库查询返回的字段名一致,mybatis会自动进行封装
2.如果实体类属性名和数据库查询返回的字段名不一致,则不能自动封装,会出现null值的情况
在这里插入图片描述
因为我们这里是一致的所以没有出现空的情况,我们来将数据库字段名改一下再来试一下。
在这里插入图片描述
在这里插入图片描述
我们发现当我们实体类属性名和数据库查询返回的字段名不一致,则不能自动封装,那么如何进行封装呢? 有以下三种方案:
1.起别名: 在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样

<select id="getById" resultType="com.example.demo.entity.User">
        select id,username,password,photo,create_time createTime,updatetime,state
        from userinfo where id = #{id}
</select>

在这里插入图片描述

2.开启驼峰命名: 如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰映射规则

# 开启驼峰命名自动映射,从数据库字段名create_time映射到属性名createTime
mybatis:
  configuration:
    map-underscore-to-camel-case: true

在这里插入图片描述
3.返回字典映射:resultMap 字段名称和程序中属性名不同时,可使用resultMap配置映射

<resultMap id="usermap" type="com.example.demo.entity.User">
        <id column="id" property="id"></id>
        <result column="create_time" property="createTime"></result>
</resultMap>

在这里插入图片描述
在这里插入图片描述

如果我们要进行条件查询呢?
在这里插入图片描述
我们先使用sql写一下我们需要查询的sql:

select * from userinfo where username like '%张%' and updatetime between 2023-05-12 11:09:01 and 2023-05-12 11:09:01 order by desc;

在这里插入图片描述

在这里插入图片描述
但是我们的#{}是不能出现在’'之内的,因为我们的#{}生成的是占位符? 所以我们这里不能使用#{},这里我们可以使用${}进行字符串拼接

<select id="getList" resultType="com.example.demo.entity.User">
        select * from userinfo
                 where username like '%${username}%'
                   and updatetime between #{createTime} and #{updateTime}
                    order by updatetime desc
</select>
@Test
    void getList() {
    
    
        User user = new User();
        user.setUsername("张三");
        user.setCreateTime(LocalDateTime.of(2023,05,12,11,9,01));
        user.setUpdateTime(LocalDateTime.of(2023,05,12,11,9,01));
        List<User> list = userMapper.getList(user);
        list.stream().forEach(System.out::println);
    }

在这里插入图片描述
我们发现这里是直接拼接到sql语句中,但是${}性能低、不安全、存在SQL注入问题
我们可以使用concat函数,concat函数是干什么的呢?我先给大家演示一下:
在这里插入图片描述
我们可以发现,其实concat就是一个字符串拼接函数
在这里插入图片描述
我们就可以将代码改为#{}的方式
在这里插入图片描述
参数名说明:
在SpringBoot的2.x版本:

在这里插入图片描述
在SpringBoot的1.x版本/单独使用mybatis:
:
为啥不是参数直接映射呢?
在这里插入图片描述
因为在该版本在编译时,并不会保留参数名,因此我们参数名不能对应,因此需要使用@Param

#{} 与 ${}的区别

1.#{paramName} -> 占位符模式
在这里插入图片描述
2.${paramName} -> 直接替换
在这里插入图片描述
#{}预编译的SQL有以下优势:
性能更高,更安全(防止SQL注入)
在这里插入图片描述
SQL注入是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法

我们来写一个简单的SQL注入的案例:
在这里插入图片描述
在这里插入图片描述
因为使用${}传递字符串类型参数时,只会传递数值,所以我们需要手动加’ '转换为字符串

在这里插入图片描述

这是我们数据库里的两组数据,我们来测试一下登录功能
在这里插入图片描述

我们使用正确的账号密码是可以登录的
在这里插入图片描述
使用错误的密码是登录不上去的,我们现在使用SQL注入的方式进行登录
在这里插入图片描述
为什么呢?我们这里的密码输入的是错误的,为什么登录成功了
在这里插入图片描述
看到这里是不是恍然大悟了。
${}拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题,我们在开发中尽量避免使用。

更新操作

在这里插入图片描述
修改id用户的密码为password
在这里插入图片描述
在这里插入图片描述

新增操作

我们给userinfo新增一个用户
在这里插入图片描述
在这里插入图片描述

@Test
    void addUser() {
    
    
        User user = new User();
        user.setUsername("zhangsan");
        user.setPassword("123456");
        int count = userMapper.addUser(user);
        System.out.println("新增了"+ count + "行" );
    }

我们没有加@Transactional注解,直接进行落盘操作。
在这里插入图片描述
如果我们仅仅只是想获取该操作受影响的行数,操作起来也是比较简单的。
如果返回值想要获取id主键值呢?
我们需要在里面设置两个属性值
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二. Mybatis多表操作

我们先在mycnblog下在建一张表
在这里插入图片描述
在这里插入图片描述
然后插入一条数据,我们创建ActicleInfo的实体类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Article {
    
    
    private Integer id;
    private String title;
    private String content;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Integer uid;
    private Integer rcount;
    private Integer state;
}

但是我们还需要username属性,但不再Article中,我们创建一个Article的扩展类
在这里插入图片描述
我们创建Article的Mapper接口

@Mapper
public interface ArticleMapper {
    
    

    //查询文章详情
    ArticleVO getDetail(Integer id);
}

在这里插入图片描述

<select id="getDetail" resultType="com.example.demo.entity.vo.ArticleVO">
        select a.*,u.username from articleinfo a left join userinfo u on u.id = a.uid
        where a.id = #{
    
    id}
    </select>

测试类:

@SpringBootTest
class ArticleMapperTest {
    
    

    @Autowired
    private ArticleMapper articleMapper;
    @Test
    void getDetail() {
    
    
        ArticleVO articleVO = articleMapper.getDetail(1);
        System.out.println(articleVO);
    }
}

在这里插入图片描述
为什么我们这里打印了username,我们来查看ArticleVO的字节码
在这里插入图片描述
我们发现我们@Data注解的toString只会打印自己的属性不会打印父类属性的信息,这里我们自己重写一下toString()方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
再去执行,信息就可以全部打印了

猜你喜欢

转载自blog.csdn.net/buhuisuanfa/article/details/130634382
今日推荐