MyBatis 查询数据库

一. MyBatis 框架的搭建

本篇所用sql 表:

drop table if exists  userinfo;
create table userinfo(
    id int primary key auto_increment,
    username varchar(100) not null,
    password varchar(32) not null,
    photo varchar(500) default '',
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    `state` int default 1
) default charset 'utf8mb4';

添加 MyBatis 框架

设置  MyBatis 配置

(i) 设置数据库的连接信息

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/blog?characterEncoding=utf8
spring.datasource.name=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

(ii) 设置MyBatis配置信息

# 设置 MyBatis XML 存放路径和命名规则
mybatis.mapper-locations=classpath:mybatis/*Mapper.xml

#设置 MyBatis 执行时打印 SQL(可选配置项)
mybatis.configuration.log_impl=org.apache.ibatis.logging.stdout.StdOutImpl
#上述MyBatis 打印设置默认是debug级别,因此需要在demo路径下的日志级别设置为debug,否则上述配置是没用的
logging.level.com.example.demo=debugout.StdOutImpl

二. 根据 MyBatis 完成数据库的操作

1. 定义接口

@Mapper
public interface UserMapper {
    List<Userinfo> getAll();
}

2. 生成数据库表对应的类对象 

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

类中的属性和数据库表中的字段名不一致时,那么查询结果为null, 解决方案:

将类中的属性和表中的字段名保持一致

在 SQL 语句中使用 as 将字段名进行重命名

<!--假设我的数据库中的字段名为username,类中的属性名为name-->
select username as name from userinfo where id=#{id}

定义一个 resultMap ,将属性名和字段名进行手动映射。

<!--    type: 要映射的实体类-->
    <resultMap id="MyMap" type="com.example.demo.model.Userinfo">
<!--        id标签中写的是主键的字段,column 对应的是数据库中的字段, property 对应的是类中的属性名-->
        <id column="id" property="id"></id>
<!--        result 标签中是普通的字段与属性-->
        <result column="username" property="name"></result>
        <result column="password" property="password"></result>
    </resultMap>

<!--    <select id="getUsrByID" resultType="com.example.demo.model.Userinfo">-->
    <select id="getUsrByID" resultMap="com.example.demo.dao.UserMapper.MyMap">
        select * from userinfo where id=#{id}
    </select>

MyBatis Plus : @TableField("数据库字段名")

3. 使用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.dao.UserMapper">
<!--    id 为方法名,resultType是返回类型,resultType使用全路径-->
    <select id="getAll" resultType="com.example.demo.model.Userinfo">
        select * from userinfo;
    </select>
</mapper>

4. 生成测试类验证 

//告诉当前测试程序,目前项目时运行在Spring Boot 容器中的
@SpringBootTest
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void getAll() {
        List<Userinfo> list=userMapper.getAll();
        System.out.println(list);
    }
}

三. 增删查改操作

3.1 查询操作

    //参数名以注解中的为准
    Userinfo getUsrByID(@Param("id")Integer uid);

    <select id="getUsrByID" resultType="com.example.demo.model.Userinfo">
        <!--select * from userinfo where id=${id}-->
        select * from userinfo where id=#{id}
    </select>

3.2 SQL注入

    //SQL注入
    Userinfo getUser(@Param("username") String name,@Param("password")String password);


    <select id="getUser" resultType="com.example.demo.model.Userinfo">
        select * from userinfo where username='${username}' and password='${password}'
    </select>

    @Test
    void getUser() {
        String username="admin";
        String password="'or 1='1";
        Userinfo user=userMapper.getUser(username,password);
        System.out.println(user);
    }

//替换后语句:
//select * from userinfo where username='admin' and password=''or 1='1'

#{} 和 ${} 的区别:

• ${} 是直接替换; #{} 是预执行.

• ${} 是不安全的,存在SQL注入;而#{} 是安全的,不存在SQL注入

• 如果是非数值类型,${} 替换需要手动添加 '' ,而#{}不需要

从上述的事例可以看出${}可以实现的功能 #{}都能实现,并且${}还有SQL的问题,那${}存在的意义是什么?

    //使用${}排序
    List<Userinfo> getByOrder(@Param("myorder")String myorder);

    <select id="getByOrder" resultType="com.example.demo.model.Userinfo">
    <!--        select * from userinfo order by id #{myorder}-->
    select * from userinfo order by id ${myorder}
</select>

    @Test
    void getByOrder() {
        List<Userinfo> list=userMapper.getByOrder("desc");
        System.out.println(list);
    }

${} 适用场景: 当业务需要传递 SQL 命令时, 只能使用 ${}, 不能使用 #{}。(例如需要排序时)

${} 注意事项:如果要使用${},那么传递的参数一定要能够被穷举,否则是不能使用的。(引起 SQL 注入问题

3.3 删除操作

    //删除操作
    int delete(@Param("id")Integer id);

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

    //操作不影响数据库
    @Transactional
    @Test
    void delete() {
        int row=userMapper.delete(1);
        System.out.println("受影响的行数: "+row);
    }

3.4 修改操作

    //更行操作
    int update(Userinfo userinfo);

    <update id="update">
        update userinfo set username=#{username} where id=#{id}
    </update>

    @Test
    void update() {
        Userinfo userinfo=new Userinfo();
        userinfo.setId(2);
        userinfo.setUsername("lisi");
        int n=userMapper.update(userinfo);
    }

3.5 插入操作

    //插入操作
    int add(Userinfo userinfo);

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

    @Test
    void add() {
        Userinfo userinfo=new Userinfo();
        userinfo.setUsername("王五");
        userinfo.setPassword("23456");
        int num=userMapper.add(userinfo);
        System.out.println("受影响的行数: "+num);
    }

3.6 特殊的添加: 返回自增的 id

默认情况下返回的是受影响的行号,如果想要返回自增id,具体实现如下

    //返回自增id
    int insert (Userinfo userinfo);

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

    @Test
    void insert() {
        Userinfo userinfo=new Userinfo();
        userinfo.setUsername("zhangsan");
        userinfo.setPassword("23456");
        int num=userMapper.insert(userinfo);
        System.out.println("受影响的行数: "+num +" | ID: "+userinfo.getId());
    }

• useGeneratedKeys:使MyBatis 使用JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键

• keyColumn:数据库自增主键字段名

• keyProperty:数据库自增的id 在类对象中对应的属性名,会将数据库中的自增主键的值赋值给该属性

3.7 like 查询

List<Userinfo> selectLike(@Param("username")String username);

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

    @Test
    void selectLike() {
        String usename="san";
        List<Userinfo> userinfo=userMapper.selectLike(usename);
        System.out.println(userinfo);
    }

这里不使用${}的原因是因为传入的参数不能穷举。除了使用concat函数,还可以将参数拼接后在进行传入。例如:传入的是"san",可以在业务层先拼接为"%san%",再进行传参。

3.8 多表查询

3.8.1 一对一

@Data
public class Articleinfo {
    int id;
    String title;
    String content;
    LocalDateTime createtime;
    LocalDateTime updatetime;
    int uid;
    int rcount;
    int state;
    //用户表关联字段
    private String username;
}
//使用注解替代xml来实现SQL   
 @Select("select a.*, u.username from articleinfo a left join userinfo u on u.id=a.uid")
    List<Articleinfo> select();

    @Autowired
    ArticleMapper articleMapper;
    @Test
    void select() {
        List<Articleinfo> list=articleMapper.select();
        System.out.println(list);
    }

3.8.2  一对多 

    @Select("select * from userinfo where id=#{id}")
    Userinfo getUserById(@Param("id") Integer id);

    @Select("select * from Articleinfo where uid=#{uid}")
    List<Articleinfo> selectByUid(@Param("uid")Integer id);

    @Test
    void selectMuch() throws ExecutionException, InterruptedException {
        ThreadPoolExecutor pool=new ThreadPoolExecutor(2, 2, 10,
                                                  TimeUnit.SECONDS,
                                                  new LinkedBlockingDeque(),
                                                  Executors.defaultThreadFactory(),
                                                  new ThreadPoolExecutor.AbortPolicy());
        Callable<Userinfo> callable=new Callable<Userinfo>() {
            @Override
            public Userinfo call(){
                return userMapper.getUserById(4);
            }
        };
        Callable<List<Articleinfo>> callable1=new Callable<List<Articleinfo>>() {
            @Override
            public List<Articleinfo> call() throws Exception {
                return articleMapper.selectByUid(4);
            }
        };
        FutureTask<Userinfo> futureTask= (FutureTask<Userinfo>) pool.submit(callable);
        FutureTask<List<Articleinfo>> futureTask1= (FutureTask<List<Articleinfo>>) pool.submit(callable1);
//        while (pool.getTaskCount()!= pool.getCompletedTaskCount());
        Userinfo userinfo=futureTask.get();
        List<Articleinfo> list=futureTask1.get();
        userinfo.setList(list);
        System.out.println(userinfo);
    }

四. 复杂情况: 动态SQL使用

在某些场景,如再添加用户的时候不确定某些字段是否会传递,为了不使数据库中对应的值为null,就需要用到下面的标签.

4.1 <if> 标签

int add2(Userinfo userinfo);

    <insert id="add2">
        insert into userinfo(username,password
        <if test="photo!=null">
            ,photo
        </if>
        )values(#{username},#{password}
        <if test="photo!=null">
            ,#{photo}
        </if>
        )
    </insert>

    @Test
    void add2() {
        Userinfo userinfo=new Userinfo();
        userinfo.setUsername("张三");
        userinfo.setPassword("123");
//        userinfo.setPhoto("");
        int result=userMapper.add2(userinfo);
        System.out.println("成功操作: "+result);
    }

4.2 <trim> 标签

<if>标签,只适用于一个非必填的字段,如果所有要插入的属性都是非必填的属性,就考虑使用<trim>标签结合<if> 标签,对多个字段都采取动态生成的方式.

<trim>标签的属性:

• prefix: 表示整个语句块,以prefix 的值作为前缀

• suffix: 表示整个语句块,以suffix 的值作为后缀

• prefixOverrides: 表示整个语句块要去掉的前缀

• suffixOverrides: 表示整个语句块要去掉的后缀

    <insert id="add3">
        insert into userinfo
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username!=null">
                username,
            </if>
            <if test="password!=null">
                password,
            </if>
            <if test="photo!=null">
                photo,
            </if>
        </trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username!=null">
                #{username},
            </if>
            <if test="password!=null">
                #{password},
            </if>
            <if test="photo!=null">
                #{photo},
            </if>
        </trim>
    </insert>

 

4.3 <where> 标签

<where>标签会动态的生成where

    List<Userinfo> selectByWhere(Userinfo userinfo);

    <select id="selectByWhere" resultType="com.example.demo.model.Userinfo">
        select * from userinfo
        <where>
            <if test="id>0">
                id=#{id}
            </if>
            <if test="username!=null">
                and username=#{username}
            </if>
            <if test="password!=null">
                and password=#{password}
            </if>
            <if test="photo!=null">
                and photo=#{photo}
            </if>
        </where>
    </select>

    @Test
    void selectByWhere() {
        Userinfo userinfo=new Userinfo();
//        userinfo.setId(2);
        userinfo.setUsername("lisi");
//        userinfo.setPassword("234567");
//        userinfo.setPhoto("cat.png");
        List<Userinfo> list=userMapper.selectByWhere(userinfo);
        System.out.println(list);
    }

4.4 <set> 标签

int updateByID(Userinfo userinfo);

    <update id="updateByID">
        update userinfo
        <set>
            <if test="username!=null">
                username=#{username},
            </if>
            <if test="password!=null">
                password=#{password},
            </if>
            <if test="photo!=null">
                photo=#{photo}
            </if>
        </set>
        where id=#{id}
    </update>

    @Test
    void updateByID() {
        Userinfo userinfo=new Userinfo();
        userinfo.setId(12);
        userinfo.setUsername("张三");
        userinfo.setPassword("123");
        userinfo.setPhoto("cat.png");
        int result=userMapper.updateByID(userinfo);
        System.out.println("成功操作: "+result);
    }

4.5 <foreach> 标签

<foreach>标签属性:

• collection: 绑定方法参数中的集合,如List,Set,Map或数组对象(值和传入的参数名相同)

• item: 遍历时的每一个对象

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

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

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

List<Userinfo> selectByIds(List<Integer> IDs);

    <select id="selectByIds" resultType="com.example.demo.model.Userinfo">
        select * from userinfo where id in
        <foreach collection="IDs" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </select>

    @Test
    void selectByIds() {
        List<Integer> list=new ArrayList<>() {{
            add(2);
            add(12);
        }};
        List<Userinfo> list1=userMapper.selectByIds(list);
        System.out.println(list1);
    }

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/325061.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot 全局异常统一处理:BindException(绑定异常)

概述 在Spring Boot应用中&#xff0c;数据绑定是一个至关重要的环节&#xff0c;它负责将HTTP请求中的参数映射到控制器方法的入参对象上。在这个过程中如果遇到任何问题&#xff0c;如参数缺失、类型不匹配或验证失败等&#xff0c;Spring MVC将会抛出一个org.springframewo…

Hive 数据迁移

一、需求 同步集团的数据到断直连环境。 二、思路 三、同步数据&#xff08;方案&#xff09; 1、环境&#xff1a;断直连模拟环境 2、操作机器&#xff1a;ETL 机器 XX.14.36.216 3、工作路径&#xff1a;cd /usr/local/fqlhadoop/hadoop/bin 4、执行命令&#xff1a; 命令…

python 元组的详细用法

当前版本&#xff1a; Python 3.8.4 文章目录如下 1. 介绍元组 2. 定义元组 3. 访问元组 4. 查询元组 1. 介绍元组 元组&#xff08;Tuple&#xff09;是一个有序的、不可变的数据序列。它可以包含各种类型的数据&#xff0c;例如数字、字符串、列表等。元组使用圆括号()来…

书生·浦语大模型实战营第四节课笔记及作业

XTuner 大模型单卡低成本微调实战 1 Finetune简介 大语言模型LLM是在海量的文本内容基础上&#xff0c;以无监督或半监督方式进行训练的。海量的文本内容赋予了大模型各种各样的行业知识。但是如果直接把大模型的知识用于生产实践&#xff0c;会发现回答不大满意。微调的目的…

【RL】(task1)绪论、马尔科夫过程、动态规划、DQN(更新中)

note 文章目录 note一、马尔科夫过程二、动态规划DQN算法时间安排Reference 一、马尔科夫过程 递归结构形式的贝尔曼方程计算给定状态下的预期回报&#xff0c;这样的方式使得用逐步迭代的方法就能逼近真实的状态/行动值。 有了Bellman equation就可以计算价值函数了马尔科夫过…

微服务架构设计核心理论:掌握微服务设计精髓

文章目录 一、微服务与服务治理1、概述2、Two Pizza原则和微服务团队3、主链路规划4、服务治理和微服务生命周期5、微服务架构的网络层搭建6、微服务架构的部署结构7、面试题 二、配置中心1、为什么要配置中心2、配置中心高可用思考 三、服务监控1、业务埋点的技术选型2、用户行…

Burp Suite如何拦截站点请求

Burp Suite是一款强大的Web渗透测试工具&#xff0c;可以用于拦截、修改和分析Web应用程序的请求和响应。要使用Burp Suite拦截站点请求有两个方案。我会倾向选用方案二&#xff0c;因为它不会影响本地电脑代理配置。 1. 方案一 安装Burp Suite&#xff1a;首先&#xff0c;您…

【C语言】ipoib驱动 - ipoib_cm_post_receive_nonsrq_rss函数

一、ipoib_cm_post_receive_nonsrq_rss函数定义 static int ipoib_cm_post_receive_nonsrq_rss(struct net_device *dev,struct ipoib_cm_rx *rx, int id) {struct ipoib_dev_priv *priv ipoib_priv(dev);struct ipoib_recv_ring *recv_ring priv->recv_ring rx->ind…

提升开发效率的google插件

在如今的软件开发领域&#xff0c;Google Chrome浏览器的开发者插件扮演着至关重要的角色&#xff0c;为开发人员提供了丰富的工具和功能&#xff0c;从而提高了开发效率。下面介绍几款强大的 Google 插件&#xff0c;它们在不同方面为开发者提供了便利&#xff0c;并能显著提升…

力扣每日一题--2088. 统计农场中肥沃金字塔的数目

看到这道题有些人很容易放弃&#xff0c;其实这道题不是很难&#xff0c;主要是题目长&#xff0c;读的容易让人放弃&#xff0c;但是 只要抓住一些性质就可以解决该问题。 本题中的定义放到图像里其实就是个金字塔&#xff0c;下层的那部分比上一层的那部分&#xff0c;长度加…

51单片机HC-SR04超声波测距lcd1602显示(程序+ad硬件设计+文档说明)

本帖主控使用STC89C52单片机&#xff0c;超声波测距采用HC-SR04模块&#xff0c;包含ad硬件设计和文档。 测距原理 超声波测距是通过不断检测超声波发射后遇到障碍物所反射的回波&#xff0c;从而测出发射和接收回波的时间差t,然后求出距SCt/2,式中的C为超声波波速。由于超声…

【GitHub】如何删除GitHub仓库里的文件夹(区分 rm/git rm)

删除GitHub仓库里的一个文件夹 1、复制仓库地址2、在本地新建一个空文件夹3、在空文件夹内&#xff0c;右键选择Git Bash Here4、弹出GIT Bash框5、克隆远程仓库6、拉取远程仓库7、查看仓库里的文件8、选择想要删除的文件夹进行删除9、提交删除说明10、更新GitHub远程仓库 在gi…

微信小程序-----wxss模版样式

目录 前言 一、WXSS 1. 什么是 WXSS 2. WXSS 和 CSS 的关系 二、rpx 1. 什么是 rpx 尺寸单位 2. rpx 的实现原理 3. rpx 与 px 之间的单位换算 三、样式导入 1. 什么是样式导入 2. import 的语法格式 四、全局样式和局部样式 1. 全局样式 2. 局部样式 前言 上一期…

伪装目标检测模型论文阅读之:Zoom in and out

论文链接&#xff1a;https://arxiv.org/abs/2203.02688 代码;https://github.com/lartpang/zoomnet 1.摘要 最近提出的遮挡对象检测&#xff08;COD&#xff09;试图分割视觉上与其周围环境融合的对象&#xff0c;这在现实场景中是非常复杂和困难的。除了与它们的背景具有高…

漏洞复现-金和OA jc6/servlet/Upload接口任意文件上传漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

【RT-DETR有效改进】ShapeIoU、InnerShapeIoU关注边界框本身的IoU(包含二次创新)

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…

【Linux】Linux系统编程——pwd命令

文章目录 1.命令概述2.命令格式3.常用选项4.相关描述5.参考示例 1.命令概述 pwd&#xff08;Print Working Directory&#xff09;命令用于显示用户当前工作目录的完整路径。这是一个常用的命令&#xff0c;帮助用户确定他们目前所在的目录位置。 2.命令格式 基本的 pwd 命令…

基于Redis+Lua的分布式限流

本文已收录至我的个人网站&#xff1a;程序员波特&#xff0c;主要记录Java相关技术系列教程&#xff0c;共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源&#xff0c;让想要学习的你&#xff0c;不再迷茫。 前面我们了解了如何利用Nginx做网关层限流&#xf…

2024年AMC8历年真题练一练和答案详解(9),以及全真模拟题

“熟读唐诗三百首,不会作诗也会吟”&#xff0c;反复做真题、吃透真题、查漏补缺并举一反三是在各类考试、比赛中得高分的重要学习方法之一&#xff0c;参加AMC8竞赛也是如此。 六分成长继续为您分享AMC8历年真题&#xff0c;最后几天&#xff0c;通过高质量的真题来体会快速思…

爬虫-8-数据存储-mysql

#mysql占空间最小吧&#xff0c;数据存储没问题吧 (//∇//)