自学内容网 自学内容网

MyBatis学习笔记

MyBatis

  • controller 控制层
  • service 业务层
  • dao 持久层

MyBatis是一款优秀的持久层框架,用于简化JDBC的开发。

MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis。2013年11月迁移到GitHub

MyBatis入门

快速入门

使用MyBatis查询所有用户数据

  • 准备工作(创建SpringBoot工程、数据库表user、实体类User)
  • 引入MyBatis的相关依赖、配置MyBatis
  • 编写SQL语句(注解/XML)
package com.itheima;

import com.itheima.mapper.UserMapper;
import com.itheima.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest //springboot整合单元测试的注解
class SpringbootMybatisQuickstartApplicationTests {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testListUser(){
        List<User> userList = userMapper.list();

        userList.stream().forEach(user -> {
            System.out.println(user);
        });
    }
}


package com.itheima.pojo;

public class User {
    private Integer id;
    private String name;
    private Short age;
    private Short gender;
    private String phone;

    public User() {
    }

    public User(Integer id, String name, Short age, Short 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 Short getAge() {
        return age;
    }

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

    public Short getGender() {
        return gender;
    }

    public void setGender(Short 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 + '\'' +
                '}';
    }
}


package com.itheima.mapper;

import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper //运行时,会自动生成该接口的实现类对象(代理对象),并且将对象交给IOC容器管理
public interface UserMapper {
    /*查询所有用户信息*/
    @Select("select * from user")
    public List<User> list();
}

JDBC介绍

JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。

本质

  • sun公示官方定义的一套操作所有关系型数据库的规范,即接口。
  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包
  • 可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

数据库连接池

数据库连接池

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

优势

  • 资源重用
  • 提升系统的响应速度
  • 避免数据库连接遗漏问题

标准接口: DataSource

  • 官方(sun)提供的数据库连接池接口,由第三方组织实现此接口
  • 功能:获取连接 Connection getConnection() throws SQLException;

com.zaxxer.hikari.HikariDataSource

  • 产品: C3P0、DBCP、Druid、Hikari

lombok

  • Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化Java开发,提高效率
注解作用
@Getter/@Setter为所有的属性提供get/set方法
@ToString会给类自动生成易于阅读的toString方法
@EqualsAndHashCode根据类所拥有的非静态字段自动重写equals方法和hashCode方法
@Data提供了更综合的生成代码功能(@Getter+@Setter+@ToString+@EqualsAndHashCode)
@NoArgConstructor为实体类生成无参的构造器方法
@AllArgConstructor为实体类生成除了static修饰的字段之外带有各参数的构造器方法。

引入lombok依赖

<dependency>
    <groupld>org.projectlombok</groupld>
    <artifactld>lombok</artifactld>
</dependency>
//不使用lombok注解
package com.itheima.pojo;

public class User {
    private Integer id;
    private String name;
    private Short age;
    private Short gender;
    private String phone;

    public User() {
    }

    public User(Integer id, String name, Short age, Short 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 Short getAge() {
        return age;
    }

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

    public Short getGender() {
        return gender;
    }

    public void setGender(Short 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 + '\'' +
                '}';
    }
}

//使用lombok注解
package com.itheima.pojo;
import lombok.*;

@Data
@NoArgsConstructor  //无参构造
@AllArgsConstructor //全参构造
public class User {
    private Integer id;
    private String name;
    private Short age;
    private Short gender;
    private String phone;
}

注意事项

Lombok会在编译时,自动生成对应的Java代码。使用Lombok时,需要安装一个Lombok插件(IDEA自带)

MyBatis基础操作

环境准备

准备工作

  • 准备数据库表emp
  • 创建一个新的springboot工程,选择引入对应的起步依赖(Mybatis、MySQL)
  • application.properties中引入数据库连接信息
  • 创建对应的实体类Emp(实体类属性采用驼峰命名)
  • 准备Mapper接口EmpMapper

删除功能

  • SQL语句
delete from emp where id = 17;
  • 接口方法
@Delete("delete from emp where id = #{id}")
public void delete(Integer id)

注意事项

如果mapper接口方法形参只有一个普通类型的参数,#{…}里面的属性名额可以随便写,如#{id}、#{value}

日志输出

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

预编译SQL

  • 优势:

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

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

参数占位符

  • #{…}
    • 执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值
    • 使用时机:参数传递,都是用#{…}
  • ${…}
    • 拼接SQL,直接将参数拼接在SQL语句,存在SQL注入问题
    • 使用时机:如果对表名、列表进行动态设置时使用

新增功能

# 插入数据的SQL语句
insert into emp(username,name,gender,image,job,entrydate,dept_id,create_time,update_time)
values ('Tom','汤姆',1,'1.jpg',1,'2005-01-01',1,now(),now())
//EmpMapper中   
//新增员工
    @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);

//SpringBootMybatisQuickstartApplicationTest中
    @Test
    public void testInsert(){
        //构造员工对象
        Emp emp = new Emp();
        emp.setUsername("Tom");
        emp.setName("汤姆");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);

        //执行新增员工信息操作

        empMapper.insert(emp);
    }

新增(主键返回)

  • 描述:在数据添加成功后,需要获取插入数据库数据的主键。
    @Test
    public void testInsert(){
        //构造员工对象
        Emp emp = new Emp();
        emp.setUsername("Tom2");
        emp.setName("汤姆2");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);

        //执行新增员工信息操作

        empMapper.insert(emp);
        System.out.println(emp.getId());
    }
//System.out.println(emp.getId())
//null
  • 实现:使用@Options注解
    //新增员工
    @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);
    @Test
    public void testInsert(){
        //构造员工对象
        Emp emp = new Emp();
        emp.setUsername("Tom3");
        emp.setName("汤姆3");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);

        //执行新增员工信息操作

        empMapper.insert(emp);
        System.out.println(emp.getId());
    }

//输出20

更新功能

#MySQL语句的更新
update emp set username='',name = '',gender = '',image = '',job = '',entrydate = '',dept_id = '',update_time = '' where id = 1;
    //更新员工
    @Test
    public void testUpdate(){
        //构造员工对象
        Emp emp = new Emp();
        emp.setId(18);
        emp.setUsername("Tom1");
        emp.setName("汤姆1");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setDeptId(1);
        //执行更新员工操作
        empMapper.update(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);

查询(根据ID查询)

#MySQL语句
select * from emp where id = 1;
    //根据ID查询员工
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);


public void testSelectEmp(){
    Emp emp = empMapper.getById(20);
    System.out.println(emp);
}


//输出dept_id create_time update_time为null

数据封装

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

解决方案(数据封装)

  • 方案一:手动起别名
 @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);
  • 方案二:使用@Result注解
@Results({
        @Result(column = "dept_id" ,property = "deptId"),
        @Result(column = "create_time" ,property = "createTime"),
        @Result(column = "update_time" ,property = "updateTime")
})
@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);
  • 方案三:开启mybatis的驼峰自动映射开关

在application.properties中

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

查询(条件查询)

MySQL语句—条件查询

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 ")
public List<Emp> list(@Param(value = "name") String name,
                      @Param(value = "gender") Short gender,
                      @Param(value = "begin") LocalDate begin,
                      @Param(value = "end") LocalDate end);
//不是预编译,可能存在SQL注入

改进方法:

使用SQL提供的concat字符串拼接函数:

select * from emp where name like concat('%','张','%') 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 concat('%',#{name},'%') and gender = #{gender} and " +
         "entrydate between #{begin} and #{end} order by update_time desc ")
 public List<Emp> list(@Param(value = "name") String name,
                       @Param(value = "gender") Short gender,
                       @Param(value = "begin") LocalDate begin,
                       @Param(value = "end") LocalDate end);

XML映射文件

规范:

  • XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
  • XML映射文件的namespace属性为Mapper接口全限定名一致
  • XML映射文件中SQL语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
<?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="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

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

MyBatis动态SQL

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

<if>标签

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

<where>标签

where元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR.

<mapper namespace="com.itheima.mapper.EmpMapper">
    <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>
</mapper>
    @Test
    public void testList(){
//        List<Emp> empList = empMapper.list(
//                "张", (short) 1, LocalDate.of(2010, 1, 1), LocalDate.of(2020, 1, 1));
        List<Emp> empList = empMapper.list("张", null, null, null);
        //List<Emp> empList = empMapper.list("张", (short)1, null, null);
        //List<Emp> empList = empMapper.list(null, (short)1, null, null);
//        List<Emp> empList = empMapper.list(null, null, null, null);
        System.out.println(empList);
    }

案例

使用动态更新员工 - 更新id为18的员工,username更新为Tom111,name更新为汤姆111,gender更新为2

@Test
public void testUpdate(){
   //构造员工对象
   Emp emp = new Emp();
   emp.setId(18);
   emp.setUsername("Tom111"
   emp.setName("汤姆111");
   emp.setImage("1.jpg");
   emp.setGender((short)2);
   //执行更新员工操作
   empMapper.update(emp);
}

会导致其他信息为null

需要:动态更新员工信息,如果更新时有传递值,则更新;如果更新时没有传递值,则不更新

 <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>

<foreach>标签

批量删除SQL语句:

delete
from emp
where id in (18,19,20);

使用Mybatis完成批量删除需求

//测试类
@Test
public void testDeleteByIds(){
    List<Integer> ids = Arrays.asList(13, 14, 15);
    empMapper.deleteByIds(ids);
}
//Mapper接口
//批量删除员工
public void deleteByIds(@Param(value = "ids") List<Integer> ids);
<!--SQL映射-->    
<!--批量删除员工 (18,19,20)-->
    <!--
        collection: 遍历的集合
        item: 遍历出来的元素
        separator: 分隔符
        open: 遍历开始前拼接的SQL片段
        close: 遍历结束后拼接的SQL片段
    -->
    <delete id="deleteByIds">
        delete  from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

<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.itheima.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>

原文地址:https://blog.csdn.net/qq_35899077/article/details/144276260

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!