Mybatis-详细笔记

MyBatis

Mybatis是什么

MyBatis 是一个开源、轻量级的数据持久化框架,是 JDBC 和 Hibernate 的替代方案。MyBatis 内部封装了 JDBC,简化了加载驱动、创建连接、创建 statement 等繁杂的过程,开发者只需要关注 SQL 语句本身。

数据持久化是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中数据模型的统称。例如,文件的存储、数据的读取以及对数据表的增删改查等都是数据持久化操作。

JavaEE三层架构:表现层、业务层、持久层

表现层:页面展示

业务层:逻辑处理

持久层:对数据持久化,将其保存到数据库

MyBatis 支持定制化 SQL、存储过程以及高级映射,可以在实体类和 SQL 语句之间建立映射关系,是一种半自动化的 ORM 实现。其封装性低于 Hibernate,但性能优秀、小巧、简单易学、应用广泛。

ORM(Object Relational Mapping,对象关系映射)是一种数据持久化技术,它在对象模型和关系型数据库之间建立起对应关系,并且提供了一种机制,通过 JavaBean 对象去操作数据库表中的数据。

MyBatis 的主要思想是将程序中的大量 SQL 语句剥离出来,使用 XML 文件或注解的方式实现 SQL 的灵活配置,将 SQL 语句与程序代码分离,在不修改程序代码的情况下,直接在配置文件中修改 SQL 语句。

MyBatis 与其它持久性框架最大的不同是,MyBatis 强调使用 SQL,而其它框架(例如 Hibernate)通常使用自定义查询语言,即 HQL(Hibernate查询语言)或 EJB QL(Enterprise JavaBeans查询语言)。

MyBatis 官方文档:https://mybatis.org/mybatis-3/zh/

优点
  • MyBatis 是免费且开源的。
  • 与 JDBC 相比,减少了 50% 以上的代码量。JDBC缺点:1.硬编码,改动参数时工作量巨大,代码维护性低2.操作繁琐,手动设置参数,手动封装结果集
  • MyBatis 是最简单的持久化框架,小巧并且简单易学。
  • MyBatis 相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 中,和程序逻辑代码分离,降低耦合度,便于同一管理和优化,提高了代码的可重用性。
  • 提供 XML 标签,支持编写动态 SQL 语句。
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射。
  • 支持存储过程。MyBatis 以存储过程的形式封装 SQL,可以将业务逻辑保留在数据库之外,增强应用程序的可移植性、更易于部署和测试。

在这里插入图片描述

缺点
  • 编写 SQL 语句工作量较大,对开发人员编写 SQL 语句的功底有一定要求。
  • SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
使用场景

MyBatis 专注于 SQL 本身,是一个足够灵活的 DAO 层解决方案。适用于性能要求高,且需求变化较多的项目,如互联网项目。

Mybatis快速入门

步骤

在这里插入图片描述

1.创建user表,添加数据
create database mybatis;
use mybatis;

drop table if exists tb_user;

create table tb_user(
	id int primary key auto_increment,
	username varchar(20),
	password varchar(20),
	gender char(1),
	addr varchar(30)
);



INSERT INTO tb_user VALUES (1, 'zhangsan', '123', '男', '北京');
INSERT INTO tb_user VALUES (2, '李四', '234', '女', '天津');
INSERT INTO tb_user VALUES (3, '王五', '11', '男', '西安');

2.创建模块,导入坐标
<!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
        <!-- mysql 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        <!-- junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

        <!-- 添加slf4j日志api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.20</version>
        </dependency>
        <!-- 添加logback-classic依赖 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- 添加logback-core依赖 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>	

将logback(Java 开源日志框架)的配置文件复制到resources中

logback官方文档 (qos.ch)

在这里插入图片描述

3.编写MyBatis核心配置文件–>替换连接信息,解决硬编码问题

建议使用类路径下的资源文件进行配置,在resources中添加mybatis-config.xml

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

${}替换为相应的jdbc参数

4.编写SQL映射文件(mapper 映射器)–>统一管理SQL语句,解决硬编码问题

在resources中添加映射器配置文件,例子:UserMapper.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">
<!--namespace:名称空间-->
<mapper namespace="test">
    <!--查询语句-->
    <!--id:sql语句的唯一标识--><!--resultType:包装类的返回类型-->
    <select id="selectAll" resultType="org.example.pojo.User">
        select * from tb_user;
    </select>
</mapper>

参数介绍:

id:sql语句的唯一标识

resultType:包装类的返回类型,填入包装类所在的位置

表示查询语句

select * from tb_user;即sql语句的内容

5.加载sql映射文件

进入mybatis-config.xml,找到

<mappers>
        <!--加载sql映射文件-->
        <mapper resource="UserMapper.xml"/>
    </mappers>

由于mybatis-config.xml与UserMapper.xml在同级目录下,直接写映射器配置文件名称UserMapper.xml

6.编码

1定义pojo类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6UGjasmZ-1666955956659)(Mybatis.assets/image-20221028121105675.png)]

添加对应数据库表 中的私有变量,添加setter getter方法,添加toString方便显示。

2.加载核心配置文件,获取SqlSessionFactory对象

String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

3.获取SqlSession对象,执行SQL语句

SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("test.selectAll");//名称空间.id
System.out.println(users);	//打印出来查询结果

4.释放资源

sqlSession.close();

IDEA连接数据库

点击最右侧Database

在这里插入图片描述

输入数据库名称(Database),User、password

OK

Mapper代理开发(重点)

需求分析:

执行SQL的语句中用了namespace.id来指定唯一的sql语句。这种形式仍存在硬编码问题。

而且后期执行sql还要去配置文件中手动找id

步骤

1.定义与SQL映射文件同名的Mapper接口,名且将Mapper接口和SQL映射文件放置在同一目录下

在resources中新建文件夹,名称为Mapper接口所在的包名称,将.改为\

例:UserMapper接口位于org.example.mapper包中,那么在resources中新建的文件名为org\example\mapper,将SQL映射文件拖入mapper中
在这里插入图片描述

2.加载SQL映射文件

此时由于UserMapper.xml配置文件位置移动到了和Mapper接口同一个目录下,所以也要更改mybatis-config.xml中的sql映射文件路径

  • 老方法:

copy UserMapper.xml的Path From Source Root,paste到
在这里插入图片描述

  • 包扫描方法:

    由于此时mapper配置文件与mapper接口位于同一目录下,可使用包扫描方法。方便添加多个映射文件

<package name="org.example.mapper"/>
3.设置SQL映射文件的namespace属性为Mapper接口全限定名
<mapper namespace="org.example.mapper.UserMapper">
4.在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致

在这里插入图片描述

由于查询出的是多个User记录,所以类型为集合List。

selectAll()与sql语句的id相同

5.编码

执行sql步骤改为

//获取UserMapper接口的代理对象
 UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 //调用selectAll方法
        List<User> users = userMapper.selectAll();

Mybatis核心配置文件

详情见官方文档

环境配置environemnts

配置数据库连接环境信息,可以配置多个environment,通过default属性切换到不同的environment

类型别名typeAliases

在<configuration></configuration>中配置typeAliases
<typeAliases>
        <package name="org.example.pojo"/>
    </typeAliases>
    相当于给org.example.pojo下的类都起了个别名,默认情况下,sql映射文件中resultType的名称就是类名称(不区分大小写)

配置文件完成增删改查

准备环境

数据库表 tb_brand

在这里插入图片描述

实体类 Brand
在这里插入图片描述

测试用例

安装 MyBatisX 插件

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

安装完成后红色小鸟代表sql映射文件,蓝色小鸟代表Mapper接口

查询-查询所有数据

1.编写接口方法:Mapper接口
List<Brand> selectAll();
2.编写SQL语句:SQL映射文件

在这里插入图片描述

粘贴进Mapper配置文件中

<?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">
<!--namespace:名称空间-->
<mapper namespace="org.example.mapper.BrandMapper">



</mapper>

点击小蓝鸟

跳转到BrandMapper接口,点击方法名,alt+enter,快速生成statement
在这里插入图片描述

填写要执行的sql语句

在这里插入图片描述

3.执行方法,测试
public class MyBatisTest {
    @Test
    public void testSelectAll() throws IOException {
        //1.获取SqlSeeesionFactory对象
        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 brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4.执行方法
        List<Brand> brands = brandMapper.selectAll();
        System.out.println(brands);

        //5.释放资源
        sqlSession.close();

    }
}

在这里插入图片描述

发现问题:发现有些数据被封装了,有些数据没有被封装,查询结果为null

原因:数据库表的字段名称和实体类的属性名称不一样,不能自动封装

解决:

方式1:给数据库字段名称起别名,让别名和实体类属性名称一样。逻辑简单,但是操作麻烦。

在这里插入图片描述

方式2:定义sql片段

在名称空间内添加sql片段

<sql id="brand_column">
        id, brand_name as brandName, company_name as companyName, ordered, description, status
    </sql>
<select id="selectAll" resultType="org.example.mapper.BrandMapper">
        select
            <include refid="brand_column"/>
            from tb_brand;
    </select>

在这里插入图片描述

缺点:不灵活

方式3:resultMap(重点)
<resultMap id="brandResultMap" type="org.example.pojo.Brand">
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>

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

1.定义标签

  • id:唯一标识 type:映射的类型,支持别名,相当于select标签中的resultType,填写对应的实体类的路径
  • column:表的列名
  • property:实体类中对应的属性名

2.在标签中,使用resultMap属性替换 resultType 属性

在这里插入图片描述

查询-查看详情

分析

查询一个表中指定id对应的详细记录

步骤

1.编写接口方法:Mapper接口

参数:id

结果:Brand

在BrandMapper接口中添加selectById方法

Brand selectById(int id);

2.编写SQL语句:SQL映射文件

alt+enter快速生成selectById方法对应的statement

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

3.执行方法,测试

查询-多条件查询

分析需求

通过

  1. 当前状态 0或1
  2. 企业名称 模糊查询或正则
  3. 品牌名称 模糊查询或正则

三个条件查询

1.可能查询出不止一条记录,所以用List接收参数

2.条件如何连接?and

步骤

1.编写接口方法:Mapper接口

  • 参数:所有查询条件
  • 结果:List

方式1

使用 @Param(“参数名称”) 标记每一个参数,在映射配置文件中就需要使用 #{参数名称} 进行占位

List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String
        companyName, @Param("brandName") String brandName);

方式2

将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内 容} 时,里面的内容必须和实体类属性名保持一致。

List<Brand> selectByCondition(Brand brand);

方式3

将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容} 时,里面的内容必须和map集合中键的名称一致。

 List<Brand> selectByCondition(Map map)

2.编写SQL语句:SQL映射文件

<select id="selectByCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        where status = #{status}
          and company_name like #{companyName}
          and brand_name like #{brandName}
    </select>

like 模糊匹配

3.执行方法,测试

值得注意的是,要对公司名和品牌名进行模糊处理,要处理参数

//接收参数
        int status = 1;
        String companyName = "华为";
        String brandName = "华为";

        //处理参数
        companyName = "%" + companyName + "%";
        brandName = "%" + brandName + "%";

成功查询出华为和状态为1的记录

方式1

//4.执行方法
        List<Brand> brands = brandMapper.selectByCondition(status,companyName,brandName);
        System.out.println(brands);

方式2

//封装对象
        Brand brand = new Brand();
        brand.setStatus(status);
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);
//4.执行方法
	List<Brand> brands = brandMapper.selectByCondition(brand);
        System.out.println(brands);

方式3

Map map = new HashMap();
        map.put("status",status);
        map.put("companyName",companyName);
        map.put("brandName",brandName);
        
	List<Brand> brands = brandMapper.selectByCondition(map);
        System.out.println(brands);

查询-多条件动态条件查询

问题

用户可能只想通过一个或两个条件查询。而我们的条件查询语句为三个条件查询。不灵活

解决

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

在这里插入图片描述

if条件标签
<select id="selectByCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        where 
          <if test="status != null">
              status = #{status}
          </if>
        <if test="status != null">
            and company_name like #{companyName}
          </if>
        <if test="status != null">
            and brand_name like #{brandName}
          </if>
    </select>
问题

当用户传入后面的条件而没有传入第一个条件时,会造成语法错误

解决

1.添加恒等式,如1=1,并让第一个条件的格式与其他条件一致(加and)

<select id="selectByCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        where 1=1
          <if test="status != null">
              and status = #{status}
          </if>
        <if test="status != null">
            and company_name like #{companyName}
          </if>
        <if test="status != null">
            and brand_name like #{brandName}
          </if>
    </select>

2.where标签

用替换where

<select id="selectByCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <if test="status != null">
                and status = #{status}
            </if>
            <if test="status != null">
                and company_name like #{companyName}
            </if>
            <if test="status != null">
                and brand_name like #{brandName}
            </if>
        </where>
    </select>

查询-单条件动态查询

需求:用户从多个条件中选择一个条件进行查询

choose(when,otherwise):选择,类似于switch语句

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

#{companyName}


and brand_name like #{brandName}



### 查询-单条件动态查询

需求:用户从多个条件中选择一个条件进行查询

choose(when,otherwise):选择,类似于switch语句

select * from tb_brand status = #{status} company_name like #{companyName} brand_name like #{brandName} ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fantasy`

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值