本篇博客详细讲解了:编写SQL语句
1.使用注释
2.使用XML
3.多表查询
前言:
Mybatis规范中方法名不能重复,即便参数不同。因为每一个方法名都是有一个唯一的ID标识的。因此不能重复。
我们会将数据库相关的接口放在Mapper包下面。
对,注意我们实现访问数据库的Mapper包下面创建的是接口。
只需要进行方法的声明。
而方法上面的注解/SQL语句才是方法的实现。
@Mapper public interface UserInfoMapper { /** * 单纯返回数据列表 * @return */ @Select("select * from userinfo") //通过注解的方式 进行 方法的实现 *代表Mybatis所有字段名称 List<UserInfo> queryUserList(); //方法的声明
@Select("select * from userinfo") //通过注解的方式 进行方法的实现 *代表Mybatis所有字段名称
List<UserInfo> queryUserList(); //方法的声明
第三步:编写SQL语句
一、通过注解编写SQL语句
1.1查
项目,依赖,数据库,实体类等准备好之后,我们首先建包Mapper(代表操作数据库)(持久层)(因为我们用到Mapper注解)也可以放在dao下面。
新建一个UserInfoMapper类,将它定义成一个接口,我们不做它的实现,这个方法用于返回数据列表。新建一个
List<UserInfo> queryUserList方法来访问这个数据库。
在类上添加@Mapper注解:用来标识它是操作数据库的。表示是MyBatis中的Mapper接口
在方法上添加@select注解:用来标识SQL语句,代表是select查询。对应方法的具体实现
在查的时候我们发现Java属性中下面蓝框字段为null。
由于Java属性和Mybatis字段不一样,因此不会赋值给Java属性。
最好的办法就是上文我们讲到的配置驼峰自动转换
注:ibatis就是mybatis
①单纯打印数据列表 (如上图就是)
SQL语句1 返回数据列表:
select * From 表名
示例:
@Select("select * from userinfo")
//通过注解的方式进行方法的实现
List<UserInfo> queryUserList(); //方法的声明
使用@select(“select * From userinfo”)这样的方式来写SQL语句
*代表Mybatis所有字段名称。
此时我们就完成了数据库的查询。我们可以通过测试来试试,我们是否完成了数据库的查询。
如上图操作。
② 传递一个参数查询数据列表
SQL语句2 传递一个参数
select * From 表名 where 字段 = 参数;
示例:
select * From userinfo where id = #{userId}
@Select(“select * From userinfo where id = #{userId}”)
注:
当参数只有一个的时候,参数名称无所谓,改成别的也可以拿到值。
③ 传递两个参数查询数据列表
SQL语句3 传递两个参数
select * From 表名 where 字段 = 参数 and 字段 = 参数;
示例:
@Select(“select * from userinfo where id = #{param1} and delete_flag = #{param2}”)
我们发现如果按照下面这样写的话。就会报错。因为我使用的是aliyun引入的Mybatis框架。
因此当传递两个参数时,只能使用param1和param2。或者arg1和arg0。作为形参。
1.若是通过aliyun引入的springframework依赖,那么不会帮我们生成可用的我们定义的参数。因此就会报错。可以用param1和param2。或者arg1和arg0
2.官方的依赖就可以,我们也可以手动修改依赖。也就能实现,自已定义参数名称了。
3.我们也可以进行参数的重命名,这样也可以自定义参数名称。也可以编译通过。
下一条就会讲到了
这样就不会报错,我们使用了param1和param2作为了形参。
④参数重命名@param注解
在方法传参列表的参数前使用@Param注解,我们可以通过参数命名来定义我们想要使用的参数名称。
参数绑定
1.默认是注解的参数名称,使用param1和param2等也可以
2.如果使用@param注解进行重命名,那么注解中的参数必须用重命名后的参数
1.2增
SQL语句4 增添数据表信息
insert into 表名(字段1,字段2,...)values(#{参数1},#{参数2},...)
示例:
intert into userinfo(username,password,age,gender,phone) values(#{username},#{password},#{age},#{gender},#{phone})
@insert("intert into userinfo(username,password,age,gender,phone) values(#{username},#{password},#{age},#{gender},#{phone})")
注:value前面的 username 是数据库字段,value后面的#{username} 是Java属性
使用对象来传参
通过对象进传递参数
1.没有@Param重命名,那么 Java属性 直接使用属性名注:
添加的数据在数据库中 id 这个字段是自动生成的。因此无需添加。当然还有时间字段也是自动生成。
@Insert("insert into userinfo(username,password,age,gender,phone)" +
" values(#{username},#{password},#{age},#{gender},#{phone})")
Integer insert (UserInfo userInfo);
测试后我们发现完成添加操作。
返回值默认是影响的条数。
2.使用@Param重命名,那么 Java属性 使用 对象.属性名 来获取参数
@Options(useGeneratedKeys = true,keyProperty = "id") //将自动生成的id的数给id这个属性 //此操作相当于setId 来给id赋值, 这样就可以getId,数据库那边不用传参id而是自动生成,而这边自动生成了这个数,但是没有指定给哪个属性。 @Insert("insert into userinfo(username,password,age,gender,phone)" + " values(#{Info.username},#{Info.password},#{Info.age},#{Info.gender},#{Info.phone})") Integer insertByParam (@Param("Info") UserInfo userInfo);
我们发现如果单纯通过注解重命名那么程序就会报错。会发生绑定异常,如何解决这个问题呢?
我们可以当做@Param(“新参数名”)注解重命名后,新名称的参数我们把它当做一个对象。这样在values()中。我们再绑定属性就需要用新参数名.属性来完成操作了。
@Insert("insert into userinfo(username,password,age,gender,phone)" + " values(#{Info.username},#{Info.password},#{Info.age},#{Info.gender},#{Info.phone})")
通常我们还想获得数据库中生成的 id 字段。我们若想获得到这个 id 这个属性。就需要我们通过这个注解
@Options(useGeneratedKeys = true,keyProperty = "id")
//此操作相当于将数据库自动生成的 id 的值给id这个属性。相当于我们新建了id(java)属性。
//此操作相当于setId 来给id赋值, 这样就可以getId。
1.3删
SQL语句4:通过id删除
delete from 表名 where id = #{id}
示例:
@delete("delete from userinfo where id = #{id}")
Mapper
Test
删除成功!
1.4 改
1.通过传参的方式
SQL语句5:通过id更改数据库某字段值
update 表名 set 字段1 = #{参数1},字段2 = #{参数2},...... where id = #{id参数}
示例:
@Update("update userinfo set password = #{password} where id = #{id} ")
password = #{password}
password:数据库字段#{password}: Java属性,严格来讲是Mybatis的参数名
@Test
void update() {
userInfoMapper.update("nihao",6);
}
成功修改 。
2.通过传递对象的方式
注:
若我们忘了写更新字段值的id,也就是若5已经被删掉了或者本就不存在。IDEA也不会报错,只是影响条数为0。因此没有对数据库进行修改。
二、通过XML方式编写SQL语句
注解和 xml 实现是可以共存的,同一个方法,实现方式选哪个都行。
xml的方式和注解方式的操作基本上是一样的。
操作步骤
1.引入依赖 : 同上
2.配置数据库连接: 同上
3.配置Mapper路径
mybatis: mapper-locations: classpath:mapper/**Mapper.xml # 配置mybatis xml的⽂件路径,在resources/mapper创建所有表的xml⽂件 # classpath对应resources这个目录,接下来说明在mapper这个文件夹下面,以Mapper.xml结束的都可以被加载
4.声明接口
注意加上Mapper注解。
5.使用xml来实现
数据持久成的实现,MyBatis 的固定 xml 格式:我们要实现的代码就在标签<mapper>中。
创建UserInfoXMLMapper.xml, 路径参考yml中的配置
<?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="com.example.demo.mapper.UserInfoMapper"> </mapper>
放在resource/mapper目录下面
下图是一些注意事项:
启动失败常见原因:
1.namespace写错了
2.方法名写错了
3.配置错了
2.1增
1.首先声明insert方法,我们使用传递对象的方式来新增数据。
2.在xml文件中,写SQL语句。我们使用传递对象的方式来新增数据。
因此上方我们不仅要设置id 值为对应方法名 以及 返回类型resultType的值为UserInfo(要写全)
3.测试
通过xml方式拿到自增id
2.2删
和增一样的三个步骤
1.声明方法
2.在xml文件中写sql语句
3.Test测试
2.3改
1.声明方法
2.在xml中写sql语句
3.Test测试
2.4查
查的时候,在xml文件中,有一个resultType它进行了一个映射,把我们的mysql字段映射成java属性。一样的名字会映射,不一样的我们可以在下面的补充看到如何映射。
1.声明方法
2.写SQL语句
3.Test测试
对通过xml+SQL语句查的补充:驼峰转换
1.改别名,和注解是类似的.
2.在xml文件中用resultMap标签进行映射
没写的自动映射,写了的按照我们定义的进行映射,id其实也可以不用写
通过resultMap进行时候用
3.配置文件自动转换
同上
三、多表查询
多表查询特点
慢SQL。
业务中使用多表查询比较少,是因为多表查询sql太长了导致性能不好。会造成慢SQL。:原因是
- 多表查询,我们写一个SQL来查询,那么我们写的就是一个长SQL,这个长SQL是无法被优化的,只能统一交给数据库。可能进行多个表组装。因此大SQL一定会很慢。 影响到整个MySQL数据库集群。它们通过库隔离,但还是一个集群。整个数据库可能都阻塞了。
- 而单表查询,相当于我们把大SQL拆成了多个小SQL,多个小SQL都是单独的,可以优化,比如多线程的方式,可以并行去查。也可以通过加机器的方式。分配到多个机器上。
建议
- 如果业务对性能要求不高,那么使用多表查询比使用Java实现更加合适。(例如公司的内部系统,给员工用的)
- 如果业务对性能要求高,那么使用Java实现更加合适。
- 尽可能避免多表查询。因为每一个大SQL执行起来很慢,并且还可能影响到其他数据库,影响其他项目。而多个小SQL执行起来比较快。且影响小。
再创建一个表
3.1多表查询步骤:
我们再创建一个文章表:比如我们要返回文章标题、正文等信息就会用到这个表
-- 创建⽂章表 DROP TABLE IF EXISTS articleinfo; CREATE TABLE articleinfo ( id INT PRIMARY KEY auto_increment, title VARCHAR ( 100 ) NOT NULL, content TEXT NOT NULL, uid INT NOT NULL, delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0正常, 1删除', create_time DATETIME DEFAULT now(), update_time DATETIME DEFAULT now() ) DEFAULT charset 'utf8mb4'; -- 插⼊测试数据 INSERT INTO articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正⽂', 1);
3.2 第一步:首先进行多表关联(sql语句如下)
3.2.1 SQL语句6(全部查询)
我们在数据库mybatis_test的查询控制台执行那么语句
select * from articleinfo ta LEFT JOIN userinfo tb on ta.uid = tb.id where ta.id = 1
解释:
ta:对表articleinfo进行重命名为ta(table a)
LEFT JOIN:左连接,也就是关联的意思
tb: 对表userinfo进行重命名为tb(table b)
on:使用on进行关联,表a的uid字段和表b的id字段
where:查询表a的id
执行后的结果为:
也可以指定查询(SQL语句如下)
3.2.2 SQL语句7(指定查询)
select ta.*,tb.username,tb.password,tb.age from articleinfo ta LEFT JOIN userinfo tb on ta.uid = tb.id
我们看到查询到了我们想要的数据。这就是进行多表同时查询。如何用Mybatis来实现这个功能呢。
3.3示例
1.多个表
如上已经添加
2..实体类
package com.qiyangyang.mybatisdemo.model;
import lombok.Data;
import java.util.Date;
@Data
public class ArticleInfo {
private Integer id;
private String title;
private String content;
private Integer uid;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}
3. Mapper包
4. Test包
运行结果(成功查询多表)
四、通过URL来访问数据库
如果我们不想通过测试用例来访问,通过浏览器路径来访问数据库,那么我们首先一定要有Controller来写路由的映射,为了访问数据库相关内容,我们可以直接注入UserInofMapper。但是不符合我们企业开发的规范,因此我们为了规范像企业那样:
分三层架构表现层,业务层,持久层。
因此我们用Controller来调用Service。用Service来调用dao(也就是我们这里的UserInfoMapper)。
建包Controller,Service,分别在其中建类UserController,UserService。
在类UserController中创建public List<UserInfo> queryAllUser() 方法。
并在类上使用@RestController和@RequestMapping注解。在方法上使用RequestMapping注解
4.1UserController
4.2UserService
我们用Service来调用Dao(也就是数据访问层)。
4.3UserMapper
ok我们成功的在浏览器访问出来了。
总结:
1.配置数据库
2.写Mapper
①加注解@Mapper
②方法声明+方法实现
获取参数:#{参数名称}
当只有一个参数时,参数名称叫什么都可以。
当有多个参数就需要与字段对应(使用默认的也可以,不过一般不用),重命名的话与重命名的名字对应。....................
注:
1.访问数据库的方法不能像java那样方法名称相同,参数不同而构成方法的重构。这是会报错的。这不符合Mybatis规范。方法名不可以重复(在xml文件中我们看到每一个方法都是会有一个id标识的因此不能重复)
2.若是通过aliyun引入的springframework依赖,那么不会帮我们生成可用的我们定义的参数。可以用param1和param2。 官方的依赖就可以,我们也可以手动修改依赖。也就能实现,自已定义参数名称了。将aliyun依赖换成官方的依赖。
aliyun的springframework依赖(传参不能自定义参数)
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
官方springframework依赖 (传参可以自定义参数)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.17</version>
<relativePath/>
</parent>
三层架构简单回顾
三层架构就是为了符合“高内聚,低耦合”思想,把各个功能模块划分为
- 表示层(UI)、
- 业务逻辑层(BLL)和
- 数据访问层(DAL)
三层架构
各层之间采用接口相互访问,并通过对象模型的实体类(Model)作为数据传递的载体,不同的对象模型的实体类一般对应于数据库的不同表,实体类的属性与数据库表的字段名一致。
三层架构区分层次的目的是为了 “高内聚,低耦合”。开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。