当前位置:   article > 正文

Mybatis

Mybatis

Mybatis是一款优秀的持久层(Dao层/数据访问层)框架,用于简化JDBC的开发

JDBC

Java DataBase Connectivity,就是使用Java语言操作关系型数据库的一套API
这个只是一套接口,而具体的实现则由各个厂商自己去实现,这也就是我们引入的驱动jar包,真正执行的代码是驱动jar包中的实现类
特点:复杂,硬编程

Mybatis

只需要关注application.properties 和 mapper接口

数据库连接池

是一个容器,负责分配、管理数据库连接(Connection),允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。并且会释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏(类似线程池)
标准接口DataSource,由第三方实现该接口(默认使用Hikari)
在这里插入图片描述
切换连接池:在pom.xml中加入

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.2.8</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

获取连接Connection getConnection() throws SQLException;

lombok

是一个实用的Java类库,能通过注解的形式自动生成构造器,getter/setter、equals、hashcode、toString等方法,并可以自动生成日志变量,简化Java开发、提高效率。
在这里插入图片描述使用方法:在pom.xml中加入

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4

@Mapper 在mapper的接口上加上此注解表示运行时会自动创建该接口的代理对象,并且放入IOC容器中,

Mybatis操作-基于注解

通过在Mapper接口中的对应接口方法上加上对应的注解,通过注解指定执行的操作和sql语句。

Mybatis删除

使用注解@Delete

@Delete("delete from emp where id = #{id}")
    public void delete(Integer id);
  • 1
  • 2

如果mapper接口方法形参中只有一个普通类型的参数,#{}里面的属性名可以随便写,但是原则上更希望保持一致

日志输出

可以在application.properties中,打开mybatis的日志,并指定输出到控制台。

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
  • 1

SQL注入

这种使用预编译方式的占位符的访问方式可以防止SQL注入
SQL注入是指通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方式
比如我们在登录时,要输入用户名和密码,如果我们使用非预编译的方法,此时我们的密码会直接输入到sql语句中的password=' '中,而如果我们的密码处输入'or'1'='1,此时拼接进sql语句后,where password='' or '1' = '1',由于’1’一定等于’1’,因此这就为一个恒true的判断,不管password是否有等于''的项,就代表where后的条件永远为true,因此我们在select count(*) from 用户表的时候就永远count>0,从而登录成功。

防SQL注入-预编译

使用预编译,此时不管你输入了什么,都会将输入的整个字符串当作参数传入,并且在传入前就对其余固定过的SQL语句部分进行了编译,而不是进行简单拼接成为SQL语句的一部分
在这里插入图片描述
而我们在使用Mybatis时用的#{}这个占位符就是预编译的sql语句,这个占位符最终会被?代替

占位符

#{}

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

${}

  • 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题。
  • 使用时机:如果对表名,列表进行动态设置时使用。
    (Tips:在springboot1.x版本和单独使用mybatis时,不会自动替换占位符需要我们对每个参数进行注解在这里插入图片描述

Mybatis新增

如果新增表项有多个参数,可以使用实体类先去封装参数,之后用占位符去赋值,字段名和属性名要一一对应
使用注解@Insert

@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);

//Emp实体类属性
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Short gender;
    private String image;
    private Short job;
    private LocalDate entrydate;
    private Integer deptId;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

通过参数传递后进行占位符赋值。

新增数据时的主键返回

在数据添加成功后,需要获取插入数据库数据的主键。eg:添加套餐数据时,还需要维护套餐菜品关系表数据。即修改一个表后,可能还要对关联表修改信息,而此时就需要当前表的主键,这样才可以定位到关联表的对应表项。
实现方法:在mapper接口方法上加上注解
@Options(useGeneratedKeys = true,keyProperty = "id"),true表示要获取主键值,"id"表示最后封装到实体类对象的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);
  • 1
  • 2
  • 3
  • 4

Mybatis更新

使用注解@Update,需要用到主键

@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);
  • 1
  • 2
  • 3

Mybatis查询

根据ID

返回单个记录,因此用一个单个的实体类就可以存储
使用注解@Select

@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
  • 1
  • 2

自动封装规则:实体类属性名和数据库查询返回的字段名一致,mybatis会自动封装;如果实体类属性名和数据库查询返回的字段名不一致,不能自动封装
解决方案

  • 方法一:给字段取别名,让别名与实体类的属性名一致,在select语句中进行取别名
  • 方法二:通过在mapper接口上加入@Results注解,@Result注解手动映射封装,由column字段封装到property属性中
@Results({
            @Result(column = "dept_id", property = "deptId"),
            @Result(column = "create_time", property = "createTime")
    })
    @Select("select * from emp where id = #{id}")
    public Emp getById(Integer id);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 方法三:开启mybatis的驼峰命名自动映射开关,将a_column字段自动封装到aColumn属性中,符合我们开发的规范
    在application.properties中加入
    mybatis.configuration.map-underscore-to-camel-case=true

根据条件

查询结果可能为多条记录,所以我们需要封装到一个List集合内
在进行模糊匹配时,如果使用#{},则在预编译时会变为?,但是在模糊匹配时,匹配字符串会用‘’包裹,如果变为?则为,‘%?%’这样就变为带?的模糊查询,所以我们在此时使用${},即?不可以出现在引号内

    @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);
  • 1
  • 2
  • 3

要解决这种可能引起sql注入的风险,就需要使用到sql语法里的concat函数
concat(‘hello’, ‘mysql’)=hellomysql

    @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);
  • 1
  • 2
  • 3

Mybati操作-基于XML配置文件

XML文件规范

  • List item在这里插入图片描述
    在这里插入图片描述

resources内XML的包名要和java内的mapper接口包名一致,这样就是属于同一个包内。
全限定名指全类名
EmpMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--resultType为单条记录所封装的类型,也要全类名-->
    <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and
                            entrydate between #{begin} and #{end} order by update_time desc
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

EmpMapper.java

public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
  • 1

Mybatisx

基于IDEA的快速开发Mybatis的插件,为效率而生。
可以快速定位到两个关联的xml内的sql语句和mapper接口函数
可以自动构建xml配置
在这里插入图片描述在写出mapper接口时使用 Alt+Enter就会自动构建
在这里插入图片描述

Mybatis动态SQL

随着用户的输入或外部条件的变化而变化的SQL语句,我们成为动态SQL
比如我们在进行条件查询的时候,可能只要用1、2、3个条件,此时我们的SQL查询语句就要进行变化才可以。

< if >

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

< where >

用于动态生成where关键字,并且会自动删除语句中多余的and逻辑判断

<select id="list" resultType="com.itheima.pojo.Emp">
        select *
        from emp
        <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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

< set >

用于在update语句中包裹更新字段,提供set关键字,并且去除多余的

< foreach >

eg:批量删除
sql语句:delete from emp where id in (1,2,3);
< foreach collection="遍历的集合" item="遍历出来的元素" separator="元素分隔符" open="遍历开始前拼接的SQL片段" close="遍历结束后拼接的SQL片段" >遍历出来的元素< /foreach >

<delete id="deleteByIds">
        delete from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

public void testDeleteByIds(){
        List<Integer> ids = Arrays.asList(16,18,19);
        empMapper.deleteByIds(ids);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

< sql >和< include >

提高代码的复用性
将XML文件中,将重复的代码片段抽取出来放在标签< sql >内,并且给此标签一个id,之后在需要使用这个代码片段的地方加上< include >标签,并且带上属性refid=“此sql标签id”

< sql id = "xxx" > ..... < /sql >
< include refid = "xxx"/>
  • 1
  • 2
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/523054
推荐阅读
相关标签
  

闽ICP备14008679号