当前位置: 首页 > news >正文

8.16、8.17 JavaWeb(MyBatis P116-P134)

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

MyBatis入门

快速入门

需求:使用MyBatis查询所有用户的数据

1.准备工作(创建springboot工程,数据库表user,实体类User)

2.引入MyBatis的相关依赖,配置MyBatis(数据库连接信息)

3.编写SQL语句(注解/XML)

创建springboot工程,注意勾选MyBatis相关依赖

配置数据库连接信息

新建User类,对象要和数据库表中的各列一致

package com.itheima.pojo;public class User {private Integer id;private String name;private Short age;private Short gender;private String 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;}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 User() {}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", gender=" + gender +", phone='" + phone + '\'' +'}';}
}

编写SQL语句

package com.itheima.mapper;import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;@Mapper //在运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器管理
public interface UserMapper {//查询全部用户信息@Select("select * from user")public List<User> list();}

测试

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 {@Autowiredprivate UserMapper userMapper;@Testpublic void testListUser() {List<User> userList = userMapper.list();userList.stream().forEach(user -> {System.out.println(user);});}}

JDBC介绍

Java DataBase Connectivity,是使用Java语言操作关系型数据库的一套API

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

数据库连接池

数据库连接池是一个容器,负责分配、管理数据库连接

它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏

Lombok

Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化Java开发、提高效率

对于前面创建的User类可以进行简化

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

MyBatis基础操作

环境准备

1.准备数据库表emp

2.创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)

3.appliction.properties中引入数据库连接信息

4.创建对应的实体类Emp

5.准备Mapper接口EmpMapper

快速入门中已经介绍,不再赘述

删除

在EmpMapper接口中写自己需要完成的需求,这里是删除某条记录

package com.itheima.mapper;import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface EmpMapper {//根据id删除数据@Delete("delete from emp where id = #{id}")public void delete(Integer id);//public int delete(Integer id);
}

然后进行测试,在测试启动类中调用delete方法

package com.itheima;import com.itheima.mapper.EmpMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class SpringbootMybatisCrudApplicationTests {@Autowiredprivate EmpMapper empMapper;@Testpublic void testDelete() {//int delete = empMapper.delete(16);//System.out.println(delete);empMapper.delete(16);}}

这里如果delete的返回值是int,则表示这次操作影响的记录数

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

SQL预编译

?是一个占位符

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

例如,登陆的用户名为‘zhangwuji’,密码为‘123456’,输入正确的密码时执行查询操作

select count(*) from emp where username = 'zhangwuji' and password = '123456';

查询结果大于0说明查询到了,可以成功登录。输入错误的密码如

select count(*) from emp where username = 'zhangwuji' and password = '111';

查询结果为0说明数据库查询不到,登陆失败。SQL注入就是可以输入密码 'or '1' = '1

select count(*) from emp where username = 'zhangwuji' and password = '' or '1' = '1';

执行这条SQL语句时,where中的条件永远成立,因此可以登陆成功

使用预编译的SQL语句则不会出现此问题

参数占位符

1. #{...} :执行SQL时会将#{...}替换为?,生成预编译SQL,会自动设置参数值(推荐)

2. ${...} :拼接SQL,直接将参数拼接在SQL语句中,存在SQL注入问题

新增

在EmpMapper接口中新定义一个抽象方法,将Emp对象作为一个参数传进去

//新增员工@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);

在测试启动类使用该方法

@Testpublic void testInsert() {Emp emp = new Emp();emp.setUsername("Tom");emp.setName("汤姆");emp.setImage("1.jpg");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);}

主键返回

可以在新增操作时,返回新增记录的主键值,首先在EmpMapper的insert方法上在添加一个注解

需要返回的主键为‘id’

将id值返回输出

更新

在EmpMapper接口中新定义一个抽象方法,将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);

在测试启动类使用该方法

@Testpublic void testUpdate() {Emp emp = new Emp();emp.setUsername("Tom2");emp.setName("汤姆2");emp.setImage("1.jpg");emp.setGender((short)1);emp.setJob((short)1);emp.setEntrydate(LocalDate.of(2000, 1, 1));emp.setUpdateTime(LocalDateTime.now());emp.setDeptId(1);emp.setId(19);empMapper.update(emp);}

查询

根据id查询

在EmpMapper接口中新定义一个抽象方法,将id作为一个参数传进去

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

在测试启动类使用该方法

@Testpublic void testGetById() {Emp emp = empMapper.getById(19);System.out.println(emp);}

条件查询

在EmpMapper接口中新定义一个抽象方法,将需要用于查询的条件作为参数传进去

//条件查询@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(String name, Short gender, LocalDate begin, LocalDate end);

在测试启动类使用该方法

@Testpublic void testList() {List<Emp> empList = empMapper.list("张", (short)1, LocalDate.of(2010,1,1), LocalDate.of(2020,1,1));System.out.println(empList);}

注意这里进行模糊查找时,使用了${...}而非#{...},这是因为在SQL预编译时#{...}会自动替换为占位符?,而占位符不能出现在'...'中,但是这种方法存在SQL注入问题(前文提到),性能低,不安全,可以使用concat将字符串拼接起来

//条件查询@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);

XML映射文件

前面是通过定义Mapper接口,添加注解完成MyBatis的增删改查,这里通过XML映射文件来实现

规范

1.XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)

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

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

实现

首先注释掉Mapper接口方法上的注解,只保留接口中的抽象方法

public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

在XML映射文件中配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper"><!--resultType:单条记录所封装的类型--><select id="list" resultType="com.itheima.pojo.Emp">select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} andentrydate between #{begin} and #{end} order by update_time desc</select></mapper>

一定要注意需要遵循规范

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

动态SQL

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

如果查询条件并不都需要,例如前面的条件查询我只需要查询姓名中带‘张’的员工信息,不需要性别、入职日期等条件,如果依然采用上述SQL语句则无法查询成功,此时就需要动态SQL

<if>

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

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper"><!--resultType:单条记录所封装的类型--><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>
@Testpublic 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(null,(short)1, null, null);System.out.println(empList);}

<where>:where元素只会在子元素有内容的情况下才插入where子句,并且会自动去除子句开头的and或or

<set>:动态地在行首插入SET关键字,并会删除额外的逗号(用在update语句中)

<foreach>

在XML映射文件中新增一个delete标签

<!--批量删除员工(18,19)信息--><!--collection:遍历的集合item:遍历出来的元素separator:分隔符open:遍历开始前拼接的SQL片段close:遍历结束后拼接的SQL片段--><delete id="deleteByIds">deletefrom empwhere id in <foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach></delete>
//批量删除员工public void deleteByIds(List<Integer> ids);
@Testpublic void testDeleteByIds() {List<Integer> ids = Arrays.asList(18,19);empMapper.deleteByIds(ids);}

<sql><include>

<sql>:定义可重用的SQL片段

<include>:通过属性refid,指定包含的sql片段

<sql id="commonSelect">select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_timefrom emp
</sql><!--resultType:单条记录所封装的类型-->
<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>

从而提高代码的复用性

http://www.dtcms.com/a/335240.html

相关文章:

  • 【网络与爬虫 00】试读
  • lcx、netcat、powercat--安装、使用
  • 【RH134知识点问答题】第 10 章:控制启动过程
  • 深入浅出OpenGL的glDrawArray函数
  • 设计索引的原则有哪些?
  • 数据结构初阶(16)排序算法——归并排序
  • w嵌入式分享合集66
  • 开发一款多商户电商APP要多久?功能拆解与源码技术落地方案
  • vulhub-driftingblues9缓冲区溢出攻击提权
  • 写一个linux脚本,要求实现查找9010端口,如果端口存在则kill,否则不处理,返回对应的提示
  • LE AUDIO----COMMAND AND EVENT
  • ArrayList的扩容源码分析
  • colmap
  • ABB焊接机器人弧焊省气
  • windows扩展(外接)显示器位置调节
  • 狗品种识别数据集:1k+图像,6个类别,yolo标注完整
  • 利用Qwen大模型进行c++11并发库的学习,与时俱进!!!!
  • File 类的用法和 InputStream, OutputStream 的用法
  • C#高级用法:元组
  • pidgen!DecodeProdKey函数分析之iDecodedBytesMax
  • docker安装mongodb及java连接实战
  • 视频理解综述
  • 【异步】js中异步的实现方式 async await /Promise / Generator
  • 码上爬第十一题【协程+wasm】
  • 博弈论07——Lemke-Howson 算法
  • STM32-GPIO实践部分1-跑马灯实验
  • 【Java基础面试题】Java基础概念
  • 按键及消抖
  • C++ 最短路Dijkstra
  • [Python]PTA:for 求奇数分之一序列前N项和