Mybatis入门——基础操作(基于springboot项目)

Mybatis入门

介绍

什么是Mybatis?
  • Mybatis是一款优秀的 持久层 框架,用于简化JDBC的开发。

image

快速入门

使用mybatis查找所有用户
  1. 准备工作(创建springboot工程,数据表user、实体类User)
  2. 引入Mybatis的相关依赖,配置Mybatis
  3. 编写SQL语句(注解/XML)

创建springboot模块
image

点击下一步
springboot版本
具体含义,如下文所示:

  • SNAPSHOT:快照版,表示开发版本,随时可能修改;
  • M1(Mn):M是milestone的缩写,也就是里程碑版本;
  • RC1(RCn):RC是release candidates的缩写,也就是发布预览版;
  • Release:正式版,也可能没有任何后缀也表示正式版

image

点击创建,IDEA会自动下载依赖,完成项目的创建
image
可以将这些不需要的文件删除
image
导入MyBatis Framework和Mysql Driver

pox.xml中的依赖
       <!--mybatis起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>
        <!--mysql的驱动包,最新版本的驱动包-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--spring boot单元测试的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
创建user数据库
create table user(
    id int unsigned primary key auto_increment comment 'ID',
    name varchar(100) comment '姓名',
    age tinyint unsigned comment '年龄',
    gender tinyint unsigned comment '性别, 1:男, 2:女',
    phone varchar(11) comment '手机号'
) comment '用户表';

insert into user(id, name, age, gender, phone) VALUES (null,'白眉鹰王',55,'1','18800000000');
insert into user(id, name, age, gender, phone) VALUES (null,'金毛狮王',45,'1','18800000001');
insert into user(id, name, age, gender, phone) VALUES (null,'青翼蝠王',38,'1','18800000002');
insert into user(id, name, age, gender, phone) VALUES (null,'紫衫龙王',42,'2','18800000003');
insert into user(id, name, age, gender, phone) VALUES (null,'光明左使',37,'1','18800000004');
insert into user(id, name, age, gender, phone) VALUES (null,'光明右使',48,'1','18800000005');

image
创建实体类对象

点击查看代码
package minm.pojo;

/**
 * @author minm
 * @version 1.0
 * @description: TODO
 * @date 2024/4/28 上午12:42
 */
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private Integer gender;
    private String phone;

    public User() {
    }

    public User(Integer id, String name, Integer age, Integer gender, String phone) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.phone = phone;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                ", phone='" + phone + '\'' +
                '}';
    }
}

创建接口
image
使用测试类,测试
测试类路径
src/test/java/minm/SpringbootMybatisQuickstartApplicationTests.java
image
image

JDBC介绍

JDBC:就是使用Java语言操作关系型数据库的一套API
image

本质
  • sun公司官方定义的一套操作所有关系型数据库的规范,及接口。
  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包
  • 我们可以使用这套接口(JDBC)变成,真正执行的代码时驱动jar包中的实现类
点击查看代码:JDBC连接数据库
    @Test
    public void testJdbc() throws Exception {
        //连接数据库
        String url = "jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8";
        String username = "root";
        String password = "21MINM";

        //创建连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //创建statement
        Statement statement = connection.createStatement();

        //执行sql
        String sql = "select * from user";
        ResultSet resultSet = statement.executeQuery(sql);

        //处理结果集
        while (resultSet.next()) {
            Integer id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            Integer age = resultSet.getInt("age");
            Integer gender = resultSet.getInt("gender");
            String phone = resultSet.getString("phone");
            System.out.println(id + " " + name + " " + age + " " + (gender == 1 ? "男" : "女") + " " + phone + " \n");
        }

        //关闭资源
        resultSet.close();
        statement.close();
        connection.close();
    }

数据库连接池

  • 数据库连接池是个容器,负责分配、管理数据库连接(connection)
  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
  • 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引发的数据库连接遗漏

image

优势
  • 资源重用
  • 提升系统响应速度
  • 避免数据库连接遗漏
标准接口:DataSource
  • 官方提供的数据库连接池接口,由第三方组织实现此接口
  • 功能:获取连接 connection getConnection() throws SQLException;

image
springboot自带Hikari连接池

  • Druid(德鲁伊)
    • Druid连接池时阿里巴巴开源的数据库连接池项目
    • 功能强大,性能优秀,时java语言最好的数据库连接池之一

导入依赖https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter

点击查看代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.22</version>
</dependency>

配置src/main/resources/application.yml
点击查看代码
spring:
  datasource:

    type: com.alibaba.druid.pool.DruidDataSource #引入druid数据源
    #数据源基本信息,也可放在druid下	
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

    druid:
      #SpringBoot因为默认是hikari数据源所以对于其他数据源默认是不注入这些属性的,需要手动配置
      #druid数据源专有配置
      initialSize: 5
      minIdle: 5
      maxActive: 20
      maxWait: 600000
      # 主要配置以上几个即可

Lombok

  • Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提升效率
注解 作用
@Getter/@Setter 为所有的属性提供get/set方法
@ToString 会给类自动生成易阅读的toString方法
@EqualsAndHashCode 根据类所拥有的非静态字段自动重写equals方法和hashCode方法
@Data 提供了更加综合的生成代码功能(@Getter + @Setter + @ToString + @EqualsAndHashCode)
@NoArgsConstructor 为实体类生成无参的构造器方法
@AllArgConstructor 为实体类生成除了static修饰的字符之外带有个参数的构造器方法
  • Lombok会在编译时,自动生成对应的java代码。我们使用lombok时,还需要安装一个lombok的插件(idea自带)

mybatis基础操作

准备工作

  • 准备数据库表emp
  • 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
  • application.properties中引入数据库连接信息
  • 创建对应的实体类Emp(实体类属性采用驼峰命名)
  • 准备Mapper接口EmpMapper
数据库
create table user(
     id int unsigned primary key auto_increment comment 'ID',
     name varchar(100) comment '姓名',
     age tinyint unsigned comment '年龄',
     gender tinyint unsigned comment '性别, 1:男, 2:女',
     phone varchar(11) comment '手机号'
) comment '用户表';

insert into user(id, name, age, gender, phone) VALUES (null,'白眉鹰王',55,'1','18800000000');
insert into user(id, name, age, gender, phone) VALUES (null,'金毛狮王',45,'1','18800000001');
insert into user(id, name, age, gender, phone) VALUES (null,'青翼蝠王',38,'1','18800000002');
insert into user(id, name, age, gender, phone) VALUES (null,'紫衫龙王',42,'2','18800000003');
insert into user(id, name, age, gender, phone) VALUES (null,'光明左使',37,'1','18800000004');
insert into user(id, name, age, gender, phone) VALUES (null,'光明右使',48,'1','18800000005');


select * from user;




-- 部门管理
create table dept(
     id int unsigned primary key auto_increment comment '主键ID',
     name varchar(10) not null unique comment '部门名称',
     create_time datetime not null comment '创建时间',
     update_time datetime not null comment '修改时间'
) comment '部门表';

insert into dept (id, name, create_time, update_time) values(1,'学工部',now(),now()),(2,'教研部',now(),now()),(3,'咨询部',now(),now()), (4,'就业部',now(),now()),(5,'人事部',now(),now());



-- 员工管理
create table emp (
     id int unsigned primary key auto_increment comment 'ID',
     username varchar(20) not null unique comment '用户名',
     password varchar(32) default '123456' comment '密码',
     name varchar(10) not null comment '姓名',
     gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
     image varchar(300) comment '图像',
     job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
     entrydate date comment '入职时间',
     dept_id int unsigned comment '部门ID',
     create_time datetime not null comment '创建时间',
     update_time datetime not null comment '修改时间'
) comment '员工表';

INSERT INTO emp(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
    (1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
    (2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
    (3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
    (4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
    (5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
    (6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
    (7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
    (8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
    (9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
    (10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
    (11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
    (12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
    (13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
    (14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
    (15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
    (16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2010-01-01',2,now(),now()),
    (17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());
src/main/java/minm/mapper/EmpMapper.java
package minm.mapper;

import minm.pojo.Emp;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.annotations.Mapper;

import java.time.LocalDate;
import java.util.List;

/**
 * @author minm
 * @version 1.0
 * @description: TODO
 * @date 2024/4/29 下午6:01
 */
@Mapper
public interface EmpMapper {

    //根据ID删除数据
    @Delete("delete from emp where id = #{id}")
    public void delete(Integer id);
    //public int delete(Integer id);


    //新增员工
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
            " values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
    public void insert(Emp emp);


    //更新员工
    @Update("update emp set username = #{username}, name = #{name}, gender = #{gender}, image = #{image}," +
            " job = #{job}, entrydate = #{entrydate}, dept_id = #{deptId},update_time = #{updateTime} where id = #{id}")
    public void update(Emp emp);


    //方案三: 开启mybatis的驼峰命名自动映射开关 --- a_cloumn ------> aColumn
    //根据ID查询员工
    @Select("select * from emp where id = #{id}")
    public Emp getById(Integer id);

    //方案一: 给字段起别名, 让别名与实体类属性一致
    //@Select("select id, username, password, name, gender, image, job, entrydate, " +
    //        "dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id}")
    //public Emp getById(Integer id);

    //方案二: 通过@Results, @Result注解手动映射封装
    //@Results({
    //        @Result(column = "dept_id", property = "deptId"),
    //        @Result(column = "create_time", property = "createTime"),
    //        @Result(column = "update_time", property = "updateTime")
    //})
    //@Select("select * from emp where id = #{id}")
    //public Emp getById(Integer id);



    //条件查询员工
    //方式一
    //@Select("select * from emp where name like '%${name}%' and gender = #{gender} and " +
    //        "entrydate between #{begin} and #{end} order by update_time desc ")
    //public List<Emp> list(String name, Short gender, LocalDate begin , LocalDate end);

    //方式二
//    @Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and " +
//            "entrydate between #{begin} and #{end} order by update_time desc ")
//    public List<Emp> list(String name, Short gender, LocalDate begin , LocalDate end);

    //动态条件查询
    public List<Emp> list(String name, Short gender, LocalDate begin , LocalDate end);


    //动态更新员工
    public void update2(Emp emp);


    //批量删除员工
    public void deleteByIds(List<Integer> ids);

}

src/main/java/minm/pojo/Emp.java
package minm.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.time.LocalDateTime;

/**
 * @author minm
 * @version 1.0
 * @description: TODO
 * @date 2024/4/29 下午5:58
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Integer id; //ID
    private String username; //用户名
    private String password; //密码
    private String name; //姓名
    private Short gender; //性别, 1 男, 2 女
    private String image; //图像url
    private Short job; //职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师'
    private LocalDate entrydate; //入职日期
    private Integer deptId; //部门ID
    private LocalDateTime createTime; //创建时间
    private LocalDateTime updateTime; //修改时间

}

src/main/resources/application.properties
spring.application.name=springboot-mybatis-crud

#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=21MINM

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

#开启mybatis的驼峰命名自动映射开关 a_column ------> aCloumn
mybatis.configuration.map-underscore-to-camel-case=true

编写测试案例测试

src/test/java/minm/SpringbootMybatisCrudApplicationTests.java
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {

    @Autowired
    private EmpMapper empMapper;
 
    @Test
    public void testDelete() {
        Integer i = empMapper.delete(17);
        System.out.println(i);
    }

}

/**
 *==>  Preparing: delete from emp where id = ?      预编译sql
 * ==> Parameters: 17(Integer)
 * <==    Updates: 1
 */
预编译SQL

优势

  • 性能更高
  • 更安全(防止SQL注入)
    image
SQL注入
  • SQL注入是通过操作输入的数据来修饰实现定义好的SQL语句,以达到执行代码对服务器进行攻击的方式

文件名称: sql注入案例 分享链接:https://wwf.lanzn.com/b00rn10qpe 提取码:gv1y 分享有效时间: 永久
sql注入演示>java -jar sql_Injection_demo-0.0.1-SNAPSHOT.jar

jar包中默认数据库密码为1234
在IDEA上可以用反编译插件安装 File Expander 插件 反编译jar包进行修改
image
或者

	在jar包所在的路径打开cmd窗口/Powershell窗口

方法是:进入jar包所在的路径,按住shift同时点击右键,选择“打开PowerShell窗口”;

	列出jar包的文件清单(非必须,主要是为了方便查看需要修改的文件的路径)

//输入命令
jar tf abc.jar

	将需要修改的文件解压出来

//命令
jar xf abc.jar BOOT-INF/classes/application.properties

此时,会在当前jar包的同级目录下生成一个相对路径文件夹(所要修改的文件就在这里),然后修改文件中的内容

	使用修改后的文件替换jar包中对应的文件

//使用刚刚修改的文件替换jar包中的对应文件,输入命令
jar uf abc.jar BOOT-INF/classes/application.properties

以上是解压相对的文件,修改内容,再替换掉jar中的对应文件。

运行jar包
java -jar sql_Injection_demo-0.0.1-SNAPSHOT.jar
在游览器中输入http://localhost:9090/login.html

image
日志记录为
image
结果永远为真
java -jar sql_prepared_demo-0.0.1-SNAPSHOT.jar
日志结果为
image

参数占位符

#{...}

  • 执行SQL时,会将#{...}替换为?,生成预编译SQL,会自动设置参数值。
  • 使用时机:参数传递,都使用#

${...}

  • 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入的问题。
  • 使用时机:如果对表名、列表进行动态设置时使用。
数据封装
  • 实体类属性名 和 数据库表查询返回得字段名一致,mybatis回自动封装。
  • 如果实体类属性名 和数据库表查询返回得字段名不一致,不能自动封装。

解决方法

  • 起别名:在SQL语句中,对不一样的列明起别名,别名和实体类属性名一样。
点击查看代码
@Select("select id,username,password,name,gender,image,job,entrydate,dept_id deptID,crerte_time createTime,update_time updateTime from emp where id = #{id}")
public Emp getById(Integer id);
  • 手动结果隐射:通过@Resulte及@Result进行手动结果隐射。
点击查看代码
@Select("select * from emp where id = #{id}")
@Results({
	@Result(column = "dept_id",property="deptId"),
	@Result(column = "create_time",property="createTime"),
	@Result(column = "uodate_time",property="updateTime"),
})
public Emp getBuId(Integer id);
  • 开启驼峰命名:如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射
点击查看代码
#开启驼峰命名自动隐射,即从数据库字段名a_column映射到java属性名aColumn。
mybatis.configuration.map-underscore-to-camel-case=true
条件查询

image

XML映射文件

规范

  • XML映射文件的名称与Mapper接口名称一直,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
    image

  • XML映射文件的namespace属性为Mapper接口全限定名一致

  • XML隐射文件中sql语句id与Mapper接口中方法名一致,并保持返回类型一致。
    image

可以安装MybatisX插件,快速开发。

动态SQL

随着用户的输入和外部条件的变化而变化的SQL语句,我们成为动态SQL

<if>

  • <if>:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL
    image

image

foreach标签

image
image

sql-和-include
写sql片段,id和include的refid一样
    <sql id="commonSelect">
        select id,
               username,
               password,
               name,
               gender,
               image,
               job,
               entrydate,
               dept_id,
               create_time,
               update_time
        from emp
    </sql>
    <select id="list" resultType="minm.pojo.Emp">
        <include refid="commonSelect"/>
        <where>
            <if test="name != null">
                name like concat('%', #{name}, '%')
            </if>
            <if test="gender != null ">and gender = #{gender}</if>
            <if test="begin != null and end != null">and entrydate between #{begin} and #{end}</if>
        </where>
        order by update_time desc
    </select>

image

posted @ 2024-04-27 23:30  21MINM  阅读(7)  评论(0编辑  收藏  举报