[Java]MyBatis轻松拿下

介绍

在业务开发过程中, 都是使用java程序完成数据库的操作, 目前最主流的技术就是MyBatis

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

  1. 官网: https://mybatis.org/mybatis-3/zh/index.html
  2. mybatis是Apache的一个开源项目iBatis, 2010年迁移到了google code 并改名为Mybatis
  3. 2013年11月迁移到Github

快速入门

1.使用流程

1.1准备工作

  1. 创建springboot工程, 勾选
  • Mybatis Framework (Mybatis依赖)
  • MySQL Druver (MySQL驱动依赖)
  • 清理原始工程

  1. 准备实体类
  • 用于封装查询出来的数据
  • 实体类的属性名与表中的字段名一一对应。
  • 实体类的属性类型建议使用包装类型
  • 生成get/set方法
  • 生成有参构造器和无参构造器
  • 重写toString()方法
  1. 准备数据库表

1.2配置Mybatis

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

1.3编写SQL语句

  1. 创建Mapper包, 定义持久层接口XxxMapper,
  2. 使用@Mapper注解标识接口;
  • 作用: 把接口交给Mybatis管理
  • 在运行时, mybatis会自动生成该接口的实现类对象, 并且把该对象交给IOC容器管理
  • 作用: 简化数据库的操作
  1. 定义抽象方法, 书写SQL语句
  • 通过注解执行SQL语句

1.4启动测试

@SpringBootTest //springboot整合单元测试的注解
class Day03MybatisApplicationTests {

    // 注入Mapper接口的实现类对象
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testListUser() {
        // 调用实现类对象的方法完成数据库操作
        List<User> userList = userMapper.list();
        userList.stream().forEach(user -> {
            System.out.println(user);
        });
    }

}

2.配置提示

打开语法提示: 默认在mybatis中编写sql语句是不识别的, 可以做一些配置

关联数据库: 在IDEA和数据库默认没有建立连接, 所以不能提示表信息, 需要在idea中配置Mysql数据库信息

3.JDBC

JDBC是java语言操作关系型数据库的一套API

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

JDBC操作数据库存在的问题

  1. 注册驱动这块的代码存在硬编码现象
  2. 封装数据库数据的代码非常繁琐, 需要一条一条的封装
  3. 每次操作数据库都要创建和释放资源, 性能降低

  1. 在mybatis中, 通过配置的方式连接数据库
  2. 通过注解执行sql语句, 就可以完成数据库操作以及数据封装
  3. 通过数据库连接池, 管理数据库连接对象, 避免频繁创建和释放资源
  4. 使用mybatis操作数据库, 只需要配置连接信息, 编写mapper接口, 非常高效

4.数据库连接池

数据库连接池是个容器, 负责分配 管理数据库连接对象.

标准接口

  1. DetaSource 是官方(sun)提供的数据库连接池接口, 供第三方公司实现
  2. 如果想要开发连接池驱动, 就必须实现该接口
  3. 该接口的作用就是获取数据库连接对象
  4. 核心方法: Connection getConnection() thows SQLException;
  5. 常见产品

  1. Hikari(追光者)是springboot默认使用的连接池技术
  2. Druid(德鲁伊)是阿里巴巴开源的连接池技术, 功能强大, 性能优秀

切换连接池

  1. 德鲁伊官网:

  2. 切换到Druid连接池, 只需要引入德鲁伊连接池依赖就可以了

  1. 切换的效果

5.lombok

lombok的作用就是简化实体类的定义, 提高开发效率

  1. Lombok是一个实用的java类库,
  2. 通过注解的形式, 可以自动生成构造器, getter/setter. equals, hashcide, toString等方法,
  3. 还可以自动生成日志变量

引入

// 无需指定版本
// 因为lombok已经集成到springboot父工程中, 统一管理版本
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
</dependency>

注解

插件

  1. lombok在编译时, 会自动生成对应的java代码, 使用lombok时, 还需要安装插件
  2. ieda自带该插件, 较老版本的ieda可能需要手动安装

注解

通过Mybatis提供的注解, 完成数据库的增删改查操作

1.删除数据

@mapper // 把接口交给myBatis管理
public interface EmpMapper {
    //指定sql语句: 根据id删除数据
    @Delete("delete from emp where id = #{id}")
    public void delete(Integer id);
}
@SpringBootTest //springboot整合单元测试的注解
class SpringbootMybatisCrudApplicationTests {
    // 注入empMapper对象
    @Autowired
    private EmpMapper empMapper;

    @Test
    public void testDelete () {
        // 执行对象的删除方法
        empMapper.delete(17);
    }
}
  1. 删除操作会返回一个int类型的数值, 表示删除成功的个数, 需要的时候获取
  2. mybatis提供了参数占位符 #{}, 用于读取方法传递的参数

2.参数占位符

1.开启日志输出

在application.prpperties文件中开启日志输出功能, 我们就能在控制台看到mybatis执行的slq语句

#指定mybatis输出日志的位置(输出控制台)
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3.演示sql注入

SQL注入是通过操作输入的数据来修改系统的sql语句, 达到对服务器进行攻击的方法

执行jar包

// 打开cmd窗口, 定位到文件所在目录
java -jar 文件名

访问项目

// 正常访问
select count(*) from emp where username = 'zhangwuji' and posseord = '123456';
// 登录失败
select count(*) from emp where username = 'zhangwuji' and posseord = '11111';
// sql攻击
select count(*) from emp where username = 'aaass' and posseord = '' or '1' = '1';
3.预编译sql

在mybatis中, 使用 #{ ... } 占位的SQL语句, 生成的就是预编译SQL

  1. 当SQL真正执行时, 会自动将 #{} 内的值替换到 ? 号位置, 形成完整的语句
  2. 参数的传递, 都使用#{...}, 安全可靠

预编译sql拥有更好的执行性能(缓存机制) 和 更好的安全防护(sql注入)

  1. 拼接sql: 每次执行的sql语句都是不同的, 所以无法命中缓存中的sql语句
  2. 动态sql: 每次执行的sql语句都是相同的, 可以命中缓存中的sql语句, 在执行阶段拼接具体的值
4.拼接SQL

在mybatis中, 使用 #${ ... } 占位的SQL语句, 生成的就是拼接SQL

  1. 直接将参数拼接在SQL语句中, 一般很少使用
  2. 如果对表名, 列表进行动态设置时使用

4.新增数据

@mapper // 把接口交给myBatis管理
public interface EmpMapper {
    // 开启主键返回, 并指定将主键值赋值给实体类的id属性
    @Options(useGeneratedKeys = true, keyProperty = "id")
     //指定sql语句: 新增员工
    @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);
}
@SpringBootTest //springboot整合单元测试的注解
class SpringbootMybatisCrudApplicationTests {
    // 注入empMapper对象
    @Autowired
    private EmpMapper empMapper;

    @Test
    public void testDelete () {
        // 构建员工对象
        Emp emp = new Enm();
        // 为对象添加数据
        emp.setUsername("Tom");
        emp.setName("汤姆");
        emp.setGender((short) 1);
        emp.setJob((short) 1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);
        
        // 执行对象的新增方法
        empMapper.insert(emp);
        // 如果开启了主键返回, 就可以拿到新增数据的id主键值
        System.out.printIn(emp.getId());
    }
}
  1. 主键返回: 新增操作默认不会返回主键的值, 如果需要主键值时, 通过添加注解开启
  2. 开启主键返回后, 新增操作完成, 可以通过实体类, 拿到新增数据的id主键值

5.修改数据

@mapper // 把接口交给myBatis管理
public interface EmpMapper {
     //指定sql语句: 更新员工
     @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);
}
@SpringBootTest //springboot整合单元测试的注解
class SpringbootMybatisCrudApplicationTests {
    // 注入empMapper对象
    @Autowired
    private EmpMapper empMapper;

    @Test
    public void testDelete () {
        // 构建员工对象
        Emp emp = new Enm();
        // 为对象添加数据
        emp.setUsername("Tom");
        emp.setId(18);
        emp.setName("汤姆");
        emp.setGender((short) 1);
        emp.setJob((short) 1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);
        
        // 执行对象的更新方法
        empMapper.update(emp);
    }
}

6.数据封装

实体类属性名 和 数据库表的字段名一致, Mybatis会自动封装

实体类属性名 和 数据库表的字段名不一致, 不能自动封装

  1. 通过查询语句查到数据, 把数据封装到实体中, 返回给前端
  2. 由于实体类采用驼峰命名法, 数据库中采用下划线分割, 会导致有些数据无法自动封装

1.起别名

在SQL语句中, 给不一样的字段名设置一个别名, 别名和实体类的属性名一致, 就可以正确封装数据

2.手动结果映射

通过@Results 和 @Result 注解, 手动对映射结果进行调整, 以正确的封装数据

3.开启驼峰命名转换

让Mybatis自动把 下划线的字段名 转成 驼峰命名风格, 以完成封装数据

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

7.查询数据

@mapper // 把接口交给myBatis管理
public interface EmpMapper {
    //指定sql语句:  根据id查询员工
    @Select("select * from emp where id= #{id}")
    public Emp getById(Integer id);
}
@mapper // 把接口交给myBatis管理
public interface EmpMapper {
    //指定sql语句:  根据条件查询员工
    @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);
}
@SpringBootTest //springboot整合单元测试的注解
class SpringbootMybatisCrudApplicationTests {
    // 注入empMapper对象
    @Autowired
    private EmpMapper empMapper;

    @Test
    public void testGetById () { 
        // 执行对象的查询方法
        Emp emp = empMapper.getById(1);
        System.out.printIn(emp);
    }

      @Test
    public void testList () { 
        // 执行对象的条件查询方法
        List<Emp> list = empMapper.list("张", (short) 1, LocalDate.of(2010,1,1), LocalDate.of(2020,1,1));
        System.out.printIn(list);
    }
}
  1. #{}不能在引号内使用, ${}可以在引号内使用, 但是不推荐使用
  2. 建议使用mysql提供的 concat() 拼接函数, 用于拼接字符串
  3. concat('hello', 'Mysql' ,'!!!') 执行结果是 'helloMysql!!!'

8.版本差异

在早期或者单独使用mybatis时, 需要使用 @Param()注解 声明形参, 才能在 #{} 中使用数据, 原因是spinrgboot2.x版本 中引用了一个插件, 可以在编码后记住形参的名字, 有名字才能正确的访问数据

XML

使用mybatis的注解, 主要用来完成简单的增删改查, 如果是复杂的sql, 建议使用 xml 文件来映射sql语句

1,创建xml文件

XML映射文件的名称与Mapper接口名称一致,并且XML文件和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="待定">
    
</mapper>

2,设置namespace属性

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

复制接口全类名:

<mapper namespace="com.itheima.mapper.EmpMapper">
</mapper>

3.编写sql, 设置id属性

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

<mapper namespace="com.itheima.mapper.EmpMapper">

  // resultType: 单条记录所封装的类型(指定返回值的类型)
  // id="xx":  id与mapper文件的方法名一致
   <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>

4.插件

MybatisX是一款基于IDEA的快速开发Mabatis的插件, 为效率而生

生成XML文件中的sql标签

  1. alt +enter -> Generate statement -> 自动生成SQL语句

  1. ctrl +alt + L : 格式化sql语句

动态SQL

随着条件变化而变化的SQL语句称为动态sql

if标签

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

需求: 根据条件查询员工, 筛选字段有值, 则作为条件, 没有值则忽略

<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>
   order by update_time desc
</select>
  1. 以上代码通过 if标签 实现了条件的动态拼接
  2. 但是代码存在问题, 不传name, 只根据gender查询, sql语句中就会多出一个 and关键字
  3. 所以在书写动态sql时, 会使用where标签 替换 where关键字

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

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

动态的在行首插入 SET 关键字, 并会删除多余的逗号, 用在update语句中

需求: 动态更新员工数据, 如果更新时传递有值,则更新该字段, 否则不更新

<update id="update">
    update emp
    <set>
        <if test="username != null">username = #{username},</if>
        <if test="name != null">name = #{name},</if>
        <if test="gender != null">gender = #{gemder},</if>
        <if test="job != null">job = #{job},</if>
        <if test="updateTime != null">update_time = #{updateTime}</if>
     </set>
     where id = #{id}
</select>
  1. 如果不使用set标签替换set关键字, 代码就会有问题
  2. 比如只传入username字段, 后面的字段不传, sql语句中就会多出一个逗号
  3. 所以在动态更新数据时, 会使用set标签替换set关键字

foreach标签

循环遍历, 主要用在批量操作中

// 批量删除员工
public void deleteByIds(List<Integer> ids);
// 批量删除员工(18,19,20)
<delete id="deleteById">
    delete from emp where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
         #{id}
    </foreach>
</delete>

sql标签

封装重复性的SQL语句

<mapper namespace="com.itheima.mapper.EmpMapper">
    // 定义可重用的sql片段
    <sql id="唯一名称">
      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">
      // 通过refid属性, 引入sql片段
      <include refid = "唯一名称"  />
      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>
       order by update_time desc
    </select>
</mapper>
  • 23
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值