MyBatis学习笔记,快速入门

MyBatis

MyBatis中文官网https://mybatis.net.cn/

本篇笔记参照黑马程序员视频 教程 记录。

视频链接

黑马程序员-MyBatis快速入门

MyBatis简介

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

持久层

  • 负责将数据保存到数据库的那一层代码就是持久层
  • JavaEE三层框架:表现层、业务层、持久层

JDBC缺点

  1. 硬编码
  2. 操作繁琐

MyBatis快速入门

步骤

  1. 创建表,添加数据
  2. 创建模块,导入坐标(MyBatis坐标、MySQL驱动坐标)
  3. 编写MyBatis核心配置文件--------》替换连接信息,解决硬编码问题
  4. 编写SQL映射文件------》统一管理SQL语句,解决硬编码问题
  5. 编码,写程序
    1. 定义POJO类
    2. 加载核心配置文件,获取SQLSessionFactory对象
    3. 获取Session对象,执行SQL语句
    4. 释放资源

第一次使用MyBatis

  1. 创建表,添加数据就不说了
  2. 在项目中导入MyBatis的jar包
  3. 在项目的resource目录下,编写mybatis的核心配置文件,MyBatis官网会有,直接复制过来即可,文件名称随意,但习惯是mybatis-config.xml,修改配置文件中的连接信息
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 连接信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybase"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 指定当前SQL映射文件-->
<mappers>
<!-- SQL映射文件,相对路径-->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>

注意

  • MySQL8.0及以上版本,需要导入8.x的jar包,并且Driver地址为com.mysql.cj.jdbc.Driver, 之前版本不用变
  • url的写法,一般是jdbc:mysql://localhost:3306/数据库名,也可以这样写jdbc:mysql:///数据库名,默认就是localhost:3306
  1. 同样,在resources目录下编写SQL映射文件,这个文件也可以从官网直接复制过来,文件名称随意,但是一般都是以ClassNameMapper.xml
<?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">
<!--
namespace 命名空间
-->
<mapper namespace="test">
<!-- id是这条SQL语句的唯一标识
resultType是返回时的封装类型
-->
<!-- 对应类的全限名-->
<select id="selectAll" resultType="com.mybatis.Person">
select * from user;
</select>
</mapper>
  1. 编写数据库对应的类,并设置setter和getter方法,这个类名称一定要与SQL映射文件中的resultType相对应
package com.mybatis;
public class Person {
private int id ;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
  1. 加载MyBatis核心配置文件,获取SqlSessionFactory对象,这个官网也是直接复制过来即可:happy:
package com.mybatis;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyBatisDemo {
public static void main(String[] args) throws IOException {
// 1.加载MyBatis核心配置文件,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.执行SQL,对应SQL语句的 namespace.id
List<Person> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
// 4.释放资源
sqlSession.close();
}
}

这就是最简单、入门的MyBatis流程了,刚开始确实感到繁琐

解决SQL语句报红提示

在入门案例映射配置文件中存在报红的情况。问题如下:

  • 产生的原因:Idea和数据库没有建立连接,不识别表信息。但是大家一定要记住,它并不影响程序的执行。
  • 解决方式:在Idea中配置MySQL数据库连接。

IDEA中配置MySQL数据库连接

  • 点击IDEA右边框的 Database ,在展开的界面点击 + 选择 Data Source ,再选择 MySQL

  • 在弹出的界面进行基本信息的填写

  • 点击完成后就能看到如下界面

    而此界面就和 navicat 工具一样可以进行数据库的操作。也可以编写SQL语句

Mapper代理开发

概述

我们刚开始写的代码,也存在类似JDBC硬编码的问题

image-20220922192908537

这个地方传递参数namespace.id仍然是硬编码,不便于后期的维护。

如果使用Mapper代理方式则不存在硬编码问题,MyBatis官网也推荐使用Mapper的代理方式。

Mapper代理开发的规则

  • 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和映射文件放置在同一目录下
  • 设置SQL映射文件的namespace.id属性为Mapper接口权限名
  • 在Mapper接口中定义方法,方法名就是SQL映射文件中的sql语句的id,并保持参数类型和返回值类型一致

实现

  1. 在源码目录下,创建Mapper包,包中创建PersonMapper接口

    image-20220922194641833

  2. 将SQL映射文件与mapper接口同目录下,有两种方法

    1. 第一种方式,我们可以直接将xml文件拖拽到mapper包下

      image-20220922194838560

      但是这样不符合我们的规范,导致目录混乱

      Maven中规定配置文件应该放置到ressources目录下

    2. 第二种方式,在resources目录下,创建与mapper接口同结构目录

      image-20220922195148292

      这样,Maven在编译时,会自动将配置文件放置到mapper接口目录下

      image-20220922200716071

    注意:在SQL映射文件中,namespace修改为对应接口的权限名,mybatis核心配置文件中映射文件的目录也要改

  3. 编写程序

    package com.mybatis;
    import com.mybatis.mapper.PersonMapper;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    public class MyBatisDemo02 {
    public static void main(String[] args) throws Exception {
    // 1.加载mybatis配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    // 2.获取SqlSession对象,用它来执行SQL语句
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 3.执行SQL
    // 3.1 获取PersonMapper接口代理对象
    PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
    List<Person> perons = personMapper.selectAll();
    System.out.println(perons);
    // 4.关闭资源
    sqlSession.close();
    }
    }

    注意:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以在mybatis配置文件中,通过包扫描的方式简化SQL映射文件的加载

    <!-- 指定当前SQL映射文件-->
    <mappers>
    <!-- <mapper resource="com/mybatis/mapper/PersonMapper.xml"/>-->
    <!-- 包扫描的方式-->
    <package name="com.mybatis.mapper"/>
    </mappers>

核心配置文件

MyBatis的核心配置文件有这些配置

image-20220922202803780

在MyBatis的配置文件中的<configuration>下,各种不同的标签应该按照这样的特点定的前后顺序来放置

environments

在核心配置文件的environments标签中,可以配置多个environment,使用id给每个environment做标识,在environments标签中使用default=环境id来指定使用哪一个环境

这些环境可以是不同的库,甚至可以是不同品牌的数据库

<environments default="test">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 连接信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybase"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybase"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>

类型别名

在SQL映射配置文件中,resultType属性需要我们填写类的全限定名,特别麻烦。

MyBatis提供了typeAliases可以简化这部分书写,别名不区分大小写

可以使用这种方式来为某一个特定的类起别名

<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

我们还可以使用包扫描的方式来为包下的每一个类起一个别名,默认就是类名,且不区分大小写

<typeAliases>
<package name="com.mybatis"/>
</typeAliases>

这样,在SQL映射文件中可以直接使用类的名称

<select id="selectAll" resultType="Person">
select * from user;
</select>

配置文件完成增删改查

安装MyBatisX插件

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

直接在IDEA中setting —>plugins搜索安装即可

主要功能

  • XML映射配置文件和接口方法 间相互跳转
  • 根据接口方法生成statement

查询所有数据

  1. 编写Mapper接口

    package com.mybatis.mapper;
    import com.mybatis.pojo.Brand;
    import java.util.List;
    public interface BrandMapper {
    List<Brand> selectAll();
    }
  2. 编写SQL映射文件

    <?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">
    <!--
    namespace 命名空间
    -->
    <mapper namespace="com.mybatis.mapper.BrandMapper">
    <!-- id是这条SQL语句的唯一标识
    resultType是返回时的封装类型
    -->
    <select id="selectAll" resultType="Brand">
    select * from tb_brand;
    </select>
    </mapper>
  3. 编写测试程序

    package com.mybatisTest;
    import com.mybatis.mapper.BrandMapper;
    import com.mybatis.pojo.Brand;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    public class testMybatis {
    @Test
    public void testSelectAll() throws IOException {
    // 1.加载mybatis配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    // 2.获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 3.获取对应的mapper
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    // 4.执行SQL
    List<Brand> brands = mapper.selectAll();
    System.out.println(brands);
    // 4.释放资源
    sqlSession.close();
    }
    }

表字段与类属性名转换

我们发现这样一个问题,查询出来的结果并没有为实体类成功赋值

image-20220922215804789

这是因为数据库中表的字段名与实体类的属性名不一致导致的

解决方法

  1. 使用别名

    <select id="selectAll" resultType="Brand">
    select id,brand_name as brandName,company_name as companyName,ordered,description,status from tb_brand;
    </select>

    这样是可以解决的,但是如果查询的语句多了,这样写就会非常繁琐

  2. 使用SQL片段

    我们将需要复用的SQL片段抽取到sql标签中,并为这段SQL片段设置id

    <sql id="brandColumn">id,brand_name as brandName,company_name as companyName,ordered,description,status </sql>

    在原来的sql语句上直接拼接即可,使用<include refid="">来引用

    <select id="selectAll" resultType="Brand">
    select <include refid="brandColumn"/> from tb_brand;
    </select>

    但是这种SQL片段仍然存在局限性,例如其他查询的字段名并不是这些,那么就需要重新抽取SQL片段,依然是很繁琐,不灵活

  3. 使用resultMap

    就是给数据库表的字段名与类属性名之间做一个映射

    只需要对不一样的字段做映射,使用<resultMap>来定义字段和属性的映射

    <resultMap id="mapBrand" type="brand">
    <result column="brand_name" property="brandName"></result>
    <result column="company_name" property="companyName"></result>
    </resultMap>

    SQL语句的返回值类型,需要指定结果映射id

    <select id="selectAll" resultMap="mapBrand">
    select * from tb_brand;
    </select>

查询一条数据

查看某一条具体的数据,在SQL语句中就需要传参了

  1. 编写BrandMapper接口中方法

    Brand selectById(int id);
  2. 编写SQL语句

    注意: 使用的是resultMap不是resultType

    <select id="selectById" resultMap="mapBrand">
    select * from tb_brand where id = #{id};
    </select>
  3. 编写测试方法

    @Test
    public void testSelectById() throws IOException {
    int id = 1;
    // 1.加载mybatis配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    // 2.获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 3.获取对应的mapper
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    // 4.执行SQL
    Brand brand = mapper.selectById(id);
    System.out.println(brand);
    // 4.释放资源
    sqlSession.close();
    }

参数占位符

在Mapper接口中的方法需要传入参数,在与之对应的SQL映射文件中的SQL语句需要来接收这个参数。

mybatis提供了两种参数占位符

  • #{}:执行SQL时,会将#{}占位符替换为?,将来运行时自动设置参数,底层用的是PreparedStatement

    image-20220922223735911

  • ${}:拼接SQL,底层是Statement,存在SQL注入的问题

    image-20220922223823603

parameterType使用

对于有参数的mapper接口方法,我们在映射配置文件中可以使用parameterType来指定参数类型,只不过该属性可以省略

<select id="selectById" parameterType="int" resultMap="mapBrand">
select * from tb_brand where id = #{id};
</select>

特殊字符处理

当sql 语句中存在特殊字符时,比如小于号<

解决方法

  • 转义字符

    <select id="selectById" parameterType="int" resultMap="mapBrand">
    select * from tb_brand where id &lt; #{id};
    </select>
  • <!CDATA[内容]]>

    <select id="selectById" parameterType="int" resultMap="mapBrand">
    select * from tb_brand where id
    <![CDATA[
    <
    ]]> #{id};
    </select>

多条件查询

  1. 编写接口方法

    该方法有三个参数,我们就需要考虑在定义接口时,参数应该如何定义,这些参数等会传到SQL语句那,如何才能让SQL语句辨别?MyBatis针对参数有多重实现方式

  • 使用@Param("参数名称")标记一个参数,在SQL语句中需要用#{参数名称}来占位

    Brand selectByCondition(@Param("status") int status, @Param("brandName") String brandName, @Param("companyName") String companyName);
  • 将多个参数封装成一个实体对象,将该实体对象作为方法的参数。

    要求实体对象中的属性名与SQL语句中的#{占位符}一致

    List<Brand> selectByCondition(Brand brand);
  • 将这多个参数封装到Map集合中,将map集合作为方法的参数。

    同样,也是要求Map集合中的键与sql语句中的#{占位符名}保持一致

    List<Brand> selectByCondition(Map map);
  1. 编写SQL语句
<select id="selectByCondition" resultMap="mapBrand">
select *
from tb_brand
where status = #{status}
and brand_name like #{brandName}
and company_name like #{companyName};
</select>
  1. 编写测试方法
@Test
public void testSelectByCondition() throws IOException {
// 假设的参数
int status = 1;
String brandName = "华为";
String companyName = "华为";
brandName = "%" + brandName + "%";
companyName = "%" + companyName + "%";
// 1.加载mybatis配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应的mapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 方式一:直接传参,注解的方式
// List<Brand> brands = mapper.selectByCondition(status, brandName, companyName);
// List<Brand> brands = mapper.selectByCondition(brand);
// 方式二:封装成对象
// Brand brand = new Brand();
// brand.setStatus(status);
// brand.setBrandName(brandName);
// brand.setCompanyName(companyName);
// List<Brand> brands = mapper.selectByCondition(brand);
// 方式三:封装成一个Map集合
Map map = new HashMap<String, String>();
map.put("status", status + "");
map.put("brandName", brandName);
map.put("companyName", companyName);
// 4.执行SQL
List<Brand> brands = mapper.selectByCondition(map);
System.out.println(brands);
// 4.释放资源
sqlSession.close();
}
}

动态SQL

多条动态查询

其实上面的代码处理还是有些问题:用户必须同时选择三个条件才可以查询得到。但是现实生活中,往往用户只会输入一个或两个条件,这样也应该查询出相对应的数据。

这就需要动态SQL了

当用户只输入当前状态时,SQL语句应该是这样的

select * from tb_brandd where status = #{status};

当用户只输入企业名称时,SQL语句应该是这样的

select * from tb_brand where company_name like #{companyName};

针对这种情况,就需要在SQL拼接时进行判断

MyBatis对动态SQL有很强大的支持

if

choose(when, otherwise)

trim(where,set)

foreach

  • if标签:条件判断

    • 属性:test逻辑表达式
    <!-- 动态SQL查询-->
    <select id="selectByCondition" resultMap="mapBrand">
    select *
    from tb_brand
    where
    <if test="status != null">
    status = #{status}
    </if>
    <if test="brandName != null and brandName != '' ">
    and brand_name like #{brandName}
    </if>
    <if test="companyName != null and companyName != '' ">
    and company_name like #{companyName}
    </if>
    ;
    </select>

    查看运行结果

    image-20220923121520351

    上面的SQL语句仍然存在Bug,当我们不给status值时,SQL语句就变成了这样

    select * from and brand_name like #{brandName} and company_name like #{companyName};

    显然不符合sql语句的规范,会导致出错

    • 解决方案

      • 添加恒等式,像这样,SQL语句就不会出错
      <!-- 动态SQL查询-->
      <select id="selectByCondition" resultMap="mapBrand">
      select *
      from tb_brand
      where 1=1
      <if test="status != null">
      and status = #{status}
      </if>
      <if test="brandName != null and brandName != '' ">
      and brand_name like #{brandName}
      </if>
      <if test="companyName != null and companyName != '' ">
      and company_name like #{companyName}
      </if>
      ;
      </select>
      • MyBatis提供了<where>标签,可以用来替代where关键字

        MyBatis会动态的判断某个条件前面需不需要加and

      <!-- 动态SQL查询-->
      <select id="selectByCondition" resultMap="mapBrand">
      select *
      from tb_brand
      <where>
      <if test="status != null">
      and status = #{status}
      </if>
      <if test="brandName != null and brandName != '' ">
      and brand_name like #{brandName}
      </if>
      <if test="companyName != null and companyName != '' ">
      and company_name like #{companyName}
      </if>
      </where>
      ;
      </select>

单条动态查询

当用户对条件作出选择时,选择出一个,类似于Java中的switch

对于这样的switch结构,MyBatis中也是支持的

<choose> <!--相当于switch> -->
<when></when> <!--相当于case -->
<otherwise></otherwise> <!-- 相当于default -->
</choose>
<select id="selectBySingleCondition" resultMap="mapBrand">
select *
from tb_brand
where
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="brandName != null and brandName != '' ">
brand_name like #{brandName}
</when>
<when test="companyName != null and companyName != '' ">
company_name like #{companyName}
</when>
</choose>
;
</select>

当用户 一个都不选的时候,我们的SQL语句就变成了这样

select * from tb_brand where;

可以通过<otherwise>来指定默认的情况

<select id="selectBySingleCondition" resultMap="mapBrand">
select *
from tb_brand
where
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="brandName != null and brandName != '' ">
brand_name like #{brandName}
</when>
<when test="companyName != null and companyName != '' ">
company_name like #{companyName}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
;
</select>

这样写还是有些牵强,这时候<where>标签又派上用场了,它能够判断里面的条件有没有成立的,从来来生成正确的SQL语句

<select id="selectBySingleCondition" resultMap="mapBrand">
select *
from tb_brand
<where>
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="brandName != null and brandName != '' ">
brand_name like #{brandName}
</when>
<when test="companyName != null and companyName != '' ">
company_name like #{companyName}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
</where>
;
</select>

添加数据

当在页面中添加一个商品时,就需要用到插入的功能了

商品的ID应该是不需要我们手动输入的,自增的主键

<insert id="add">
insert into tb_brand(brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>

编写测试程序

@Test
public void testAdd() throws IOException {
// 假设的参数
int status = 1;
String brandName = "蓝翔挖掘机学校";
String companyName = "山东蓝翔";
String description = "挖掘技术哪家强,中国山东找蓝翔";
int orderd = 1999;
// 1.加载mybatis配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应的mapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 封装成对象
Brand brand = new Brand();
brand.setStatus(status);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setDescription(description);
brand.setOrdered(orderd);
// 4.执行SQL
mapper.add(brand);
// 4.释放资源
sqlSession.close();
}

通过控制台的日志输出,我们知道添加成功了,但是在数据库查询却没有

image-20220923154018767

image-20220923153813083

这是因为MyBatis在执行这条SQL语句时,帮我们开启了事务,当SQL执行完成了,它又进行了事务回滚,就导致没有成功插入,这就需要我们手动提交事务。

可以在执行完成SQL语句后,通过调用方法来提交事务

// 4.执行SQL
mapper.add(brand);
// 提交事务
sqlSession.commit();

当然,我们也可以在获得SqlSession对象的时候,设置参数为true,这样就能帮我们自动提交事务

// 2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);

主键返回

返回添加数据的主键

在数据添加成功后,有时候我们需要获取插入数据的主键,来用于接下来的操作

来看一下,通过该对象来获取id,发现是null

image-20220923155207605

image-20220923155145045

其实我们插入成功后,id值也就有了,但是没有绑定到我们的这个对象身上

可以在SQL语句部分这样写

<!-- useGenerateKeys:获取自动增长的主键值,true表示获取
keyProperty:指定主键是表的哪一个字段
-->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand(brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>

这样就绑定到了对象身上

image-20220923155639549

修改功能

修改全部字段

写SQL

<update id="update">
update tb_brand
set brand_name = #{brandName},
company_name = #{companyName},
brand_name = #{brandName},
description = #{description},
status = #{status}
where id = #{id};
</update>

注意 : 提交事务

修改动态字段

当用户需要修改一个字段时,并不需要修改全部字段,这时候就需要做出判断,之前也做过

<update id="update">
update tb_brand
set
<if test="brandName != null">
brand_name = #{brandName},
</if>
<if test="companyName != null">
company_name = #{companyName},
</if>
<if test="ddescription != null">
description = #{description},
</if>
<if test="status != null">
status = #{status}
</if>
where id = #{id};
</update>

经过前几次的学习,我们肯定能判断出这个SQL语句是有问题的,因为假如没有一个if条件成立,那么SQL语句就会出错

同样,Mybatis中提供了与<where>标签类似的功能,<set>标签,他能够判断哪些条件成立,哪些条件不成立,做出争取的SQL语句

<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName != '' ">
brand_name = #{brandName},
</if>
<if test="companyName != null and companyName != '' ">
company_name = #{companyName},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null">
status = #{status}
</if>
<if test="ordered != null">
ordered = #{ordered}
</if>
</set>
where id = #{id};
</update>

删除功能

删除一个

没啥说的

<delete id="delete">
delete from tb_brand where id = #{id};
</delete>

批量删除

当用户需要批量删除时,对应的SQL语句就要发生变化了

在实际开发中,批量删除时,我们会将多个参数封装成一个数组,那么在接口中应该这样定义

void deleteByIds(int[] ids);

我们一般需要删除多条数据时,会这样写

delete from tb_brand where id in (?,?,?);

但是我们并不知道这个数组中有几个数据,所以就不知道写多少个占位符。

MyBatis中提供了<foreach>标签来遍历容器

foreach标签

  • collection属性,用来指定遍历的容器名

    注意:MyBatis会将数组参数,封装为一个Map集合

    • 默认: array = 数组
    • 可以在方法定义时,用@Param注解来指定map集合默认的key名称
  • item属性:本次迭代获取的元素名称

  • separator属性:集合迭代之间的分隔符

  • open属性:该属性值是在拼接SQL语句时的符号

  • close属性:拼接结束时的符号

<!-- 批量删除-->
<delete id="deleteByIds">
delete from tb_brand
where
id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>

image-20220923165741689

这样,当我们有数组中有几个元素,就会动态的生成几个?

参数传递

MyBatis的对接口中的参数以及在对应SQL语句之间参数是如何封装、传递的。

MyBatis接口方法中可以接收各种各样的参数

  • 多个参数
  • 单个参数: 可以是一下类型
    • POJO类型:自定义类
    • Map集合类型
    • Collection集合类型
    • List集合类型
    • Array类型
    • 其他类型

多个参数

当我们的接口方法中定义了多个参数时,MyBatis会将这些参数封装成Map集合对象,值就是参数值,当我们没有使用@Param时,Map中默认的的键是这样的

  • 以arg开头

    第一个参数的键是"arg0",第二个参数的键是"arg1",以此类推

    map.put(“arg0”,参数值1);

    map.put(“arg1”,参数值2);

  • 还有一个键,是以param开头的

    map.put(“param1”,参数值1);

    map.put(“param2”,参数值2);

这两个键都是适用的,可以掩饰一波

这是接口方法

Person select(Integer id, String name);

这是SQL映射文件中 的SQL语句

<select id="select" resultMap="personMap">
select *
from user
where id = #{arg0}
and name = #{arg1};
</select>

<select id="select" resultMap="personMap">
select *
from user
where id = #{param1}
and name = #{param2};
</select>

这两种SQL写法 都是可以查询到同样的结果

image-20220923234305395

当我们使用了@Param注解后,MyBatis会将arg替换成注解中的名称,但是param的键还是会存在的

接口方法

Person select(@Param("id") Integer id, String name);

SQL语句

<select id="select" resultMap="personMap">
select *
from user
where id = #{id}
and name = #{param2};
</select>

不推荐使用Map默认设置的两种键的方式,推荐使用注解参数的方式,因为这样代码的可读性就会变强

单个参数

  • POJO类型,也就是我们自定义的对象类型

    直接使用,只要保证属性名和SQL语句的参数占位符名称一致即可

  • Map集合类型

    直接使用,只要Map集合中的键与SQL语句的参数占位符名称一致即可

  • 其他类型

    直接使用,比如说,String , Integer等常用的类型

接下来的这几个对象就有些特殊了😄

  • Collection集合类型

    MyBatis会将此类对象封装到map集合中

    map.put("arg0",collection对象);
    map.put("collection",collection对象);
  • List集合类型

    也会封装到Map集合中

    map.put("arg0",list对象);
    map.put("collection",list集合);
    map.put("list",list集合);
  • Array类型

    照样封装到Map集合中

    map.put("arg0",数组);
    map.put("array",数组);

只需要记住,用注解@Param来即可,书写起来更方便,代码的可读性更强

注解开发

使用配置文件和注解开发的本质是一样的,但是使用注解会更加方便

@Select("select * from user where id = #{id}")
Person select(int id);

针对不同类型的SQL语句,MyBatis提供了四种注解

  • 查询:@Select
  • 添加:@Insert
  • 修改:@Update
  • 删除:@Delete

使用注解来完成简单的SQL语句,使用SQL配置文件来完成复杂的SQL语句

posted @   秋天Code  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示