1.MyBatis基础操作

  • 根据资料中提供的页面原型及需求,完成员工管理的需求开发(curd)

1.1、准备

  • 准备数据库表 emp
  • 创建springboot工程,起步依赖(mybatis、mysql、lombok)
  • application.properties中引入数据连接信息
  • 创建对应实体类EmpModel
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EmpModel {
    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;
}
  • 准备接口
@Mapper
public interface EmpDao {

}

1.2、删除

  • 根据主键id删除员工信息

  • SQL语句

    delete from emp where id = 17;
    
  • 接口方法

    @Delete("delete from emp where id = #{id}")
    void deleteEmp(Integer id);
    
  • 测试

    @SpringBootTest
    class SpringbootWebCurdApplicationTests {
        @Autowired
        private EmpDao empDao;
        @Test
        public void deleteEmp(){
            empDao.deleteEmp(17);
        }
    }
    
  • 注意事项

    • 如果mapper接口方法形参只有一个普通类型的参数,#{...} 里面的属性名可以随意改写
  • 日志输出

    • 可以在application.properties中,打开mybatis日志,并指定输出到控制台
    # 配置MyBatis日志,指定输入到控制台
    mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
    
  • 预编译SQL

image-20230810233927232.png

  • 性能更高
  • 更安全(防止SQL注入)
  • SQL注入

    • 是通过操作输入的数据来修改实现定义好的SQL语句,以达到执行代码对服务器进行攻击的方法
  • {...}

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

    • 拼接SQL,直接将参数拼接在SQL语句中,存在SQL注入问题
    • 使用实际:如果对表名、列表进行动态设置时使用

1.3、新增

image-20230810233933955.png

  • SQL语句

    insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values ('songyuanqiao','宋远桥',1,'1.jpg',2,'2012-10-09',2,'2022-10-01 10:00:00','2022-10-01
    
  • 接口方法

    @Insert("insert emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
                " values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
    void insertEmp(EmpModel emp);
    
  • 新增(主键返回)

    • 在数据添加成功后,需要获取插入数据库数据的主键,如:多对多关系时,需要同时添加,中间表则需要刚刚添加信息的主键id
  • 实现

    //表示 需要获取返回回来的主键值, keyProperty 返回的值往那个字段里封装
    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
                " values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
    void insertEmp(EmpModel emp);
    

1.4、更新

image-20230810233943222.png

  • SQL(根据ID更新员工信息)

    update emp set username = 'songdaxia', name = '宋大侠', gender = 1 , image = '1.jpg' , job = 2, entrydate = '2012-01-01', dept_id = 2, update_time = '2022-10-01 12:12:12' where id = 19;
    
  • 接口方法

    @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}")
    void updateEmp(EmpModel emp);
    

1.5、查询

  • SQL语句(根据ID查询)

    select * from emp where id = 18;
    
  • 接口方法

    @Select("select * from emp where id = #{id}")
    EmpModel getEmpById(Integer id);
    
  • 发现问题

image-20230810233951257.png

  • 数据封装

    • 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装
    • 如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装

image-20230810233958726.png

image-20230810234002505.png

  • 解决问题方案一:起别名

    • 在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样
    @Select("select id, username, password, name, gender, image, job, entrydate," +
                " dept_id deptID, create_time createTime, update_time updateTime from emp where id = #{id}")
    EmpModel getEmpById(Integer id);
    
  • 方案二:手动结果映射

    • 通过@Results,@Result进行手动结果映射
    @Results({
                //column 表中字段,property 实体类映射属性
                @Result(column = "dept_id",property = "deptId"),
                @Result(column = "update_time",property = "updateTime"),
                @Result(column = "create_time",property = "createTime")
        })
    @Select("select * from emp where id = #{id}")
    EmpModel getEmpById(Integer id);
    
  • 方案三:开启驼峰命名

    • 如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射
    #开启mybatis的驼峰命名自动映射开发
    mybatis.configuration.map-underscore-to-camel-case=true
    
  • SQL(条件查询)

    select *  from emp where name like '%张%' and gender = 1 and entrydate between '2010-01-01' and '2020-01-01 ' order by update_time desc;
    
  • 接口方法

    @Select("select * from emp where name like '%${name}%' and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time DESC")
    List<EmpModel> getEmpsByConditions(String name, Short gender, LocalDate begin,LocalDate end);
    
    • '%${name}%'存在安全问题,可以使用MySQL中函数concat()来拼接
    //根据MySQL concat拼接字符串函数来解决${name} 防止注入问题
    @Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time DESC")
    List<EmpModel> getEmpsByConditions(String name, Short gender, LocalDate begin,LocalDate end);
    

2.XML映射文件

  • 规范

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

image-20230810234012563.png

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

  • XML映射文件中sql语句的id与Mapper/Dao接口中的方法名一致,并保持返回类型一致

    <?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.mhn.dao.EmpDao">
      <select id="list" resultType="com.mhn.model.EmpModel">
          select * from emp where name like concat('%',#{name},'%') and
          gender = #{gender} and entrydate between #{begin} and #{end} order by update_time DESC
      </select>
    </mapper>
    
    @Mapper
    public interface EmpDao {
      public List<Emp> list (String name, Short gender , LocalDate begin , LocalDate end);
    }
    
  • MybatisX是一款基于IDEA的快速开发Mybatis的插件,为效率

  • 安装

image-20230810234020255.png

使用MyBatis的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句

3.MyBatis动态SQL

image-20230810234025857.png

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

3.1、if

  • if

    • 用于判断条件是否成立,使用test属性进行条件判断,如果条件为true,则拼接SQL
    select id, username, password, name, gender, image, job,entrydate, dept_id, create_time, update_time
    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>
    
  • 遇见问题,如果name没有传送值,则预编译的sql会遇到 where 后直接跟and

  • where标签

    select id, username, password, name, gender, image, job,entrydate, dept_id, create_time, update_time
    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>
    

where 会灵活的删除后面多余的and或or,来防止问题的发生

  • 案例:完善更新员工功能,修改为动态更新员工数据信息
    • set:同理where,多余的,会自动消除
<update id="update2">
    update emp
    <set>
        <if test="username != null">username=#{username},</if>
        <if test="name != null">name=#{name},</if>
        <if test="gender != null">gender=#{gender},</if>
        <if test="image != null">image=#{image},</if>
        <if test="job != null">job=#{job},</if>
        <if test="entrydate != null">entrydate=#{entrydate},</if>
        <if test="deptId != null">dept_id=#{deptId},</if>
        <if test="updateTime != null">update_time=#{updateTime}</if>
    </set>
    where id = #{id}
</update>

3.2、foreach

  • 场景

    • 批量删除
  • SQL语句

    delete from emp where id in(1,2,3);
    
  • 接口方法

    public void deleteByIds(List<Integer> ids);
    
  • XML映射问及那

    <delete id="deleteByIds">
        delete from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>
    
    • collection:集合名称
    • item:集合遍历出来的元素
    • spearator:每一次遍历使用的分隔符
    • open:遍历开始前拼接的片段
    • close:遍历结束后拼接的片段

3.3、sql、include

  • 问题原由
    • 存在多种查询情况,而查询的字段和表名都属于一样的,则可封装复用来简化代码的开发和维护
  • sql片段
    • 定义可重用的SQL片段
  • include
    • 通过属性refid,指定包含的sql片段
<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="com.mhn.model.EmpModel">
    <include refid="commonSelect"></include>
    <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>

results matching ""

    No results matching ""