MyBatis中文网
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>3.1.4version>
<relativePath/>
parent>
<groupId>com.examplegroupId>
<artifactId>demoMybatisartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>demoMybatisname>
<description>demoMybatisdescription>
<properties>
<java.version>17java.version>
properties>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>3.0.2version>
dependency>
<dependency>
<groupId>com.mysqlgroupId>
<artifactId>mysql-connector-jartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starter-testartifactId>
<version>3.0.2version>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
CREATE DATABASE mybatis;
USE mybatis;
CREATE TABLE USER(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT 'ID',
NAME VARCHAR(100) COMMENT '姓名',
age TINYINT UNSIGNED COMMENT '年龄',
gender TINYINT UNSIGNED COMMENT '性别, 1:男, 2:女',
phone VARCHAR(11) COMMENT '手机号'
) COMMENT '用户表';
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'白眉鹰王',55,'1','18800000000');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'金毛狮王',45,'1','18800000001');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'青翼蝠王',38,'1','18800000002');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'紫衫龙王',42,'2','18800000003');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'光明左使',37,'1','18800000004');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'光明右使',48,'1','18800000005');
实体类 User 中的属性与数据库表格中的字段是一一对应的
在实体类属性定义的时候使用相关数据类型的包装类型
再创建有参无参构造、getter/setter 方法以及 toString 方法
package com.example.pojo;
public class User {
/*
实体类 User 中的属性与数据库表格中的字段是一一对应的
在实体类属性定义的时候使用相关数据类型的包装类型
*/
private Integer id;
private String name;
private Short age;
private Short gender;
//生成getter和setter方法和toString方法以及有参无参构造
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
public User() {
}
public User(Integer id, String name, Short age, Short gender) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
}
}
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456
数据库的名字为 mybatis,数据库的密码为 123456
要依据具体情况修改
package com.example.mapper;
import com.example.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper //在运行时,会自动生成该接口的实现类对象(代理对象),并将该对象交给IOC容器管理
public interface UserMapper {
//查询全部用户信息
//全部用户信息使用list集合
@Select("select * from user")
public List<User> list();
}
package com.example;
import com.example.mapper.UserMapper;
import com.example.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;
/**
* 这是SpringBoot工程自带的一个测试类
*/
@SpringBootTest//SpringBoot整合单元测试的注解
class DemoMybatisApplicationTests {
/*
写一个测试方法来进行测试
查询所有用户的信息
来调用UserMapper接口中的list方法
UserMapper是一个接口,不能直接new接口
但是,在Usermapper接口上加了Mapper注解,会自动生成代理对象
*/
//所以直接声明一个UserMapper的对象,再加上注解进行依赖注入
@Autowired
private UserMapper userMapper;
@Test
public void testListUser(){
//直接调用方法进行查询
List<User> userList = userMapper.list();
//进行遍历输出
userList.stream().forEach(user ->{
System.out.println(user);
});
}
}
JDBC,全称Java DataBase Connectivity(java数据库连接),是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问。它是由一组用java语言编写的类和接口组成,是sun公司制定的一套接口(interface),接口都有调用者和实现者。JDBC为程序开发人员提供了一组用于实现对数据库访问的JDBCAPI,并支持SQL语言,是sun开发的一套数据库访问编程接口,是一种SQL级的API。
JDBC的作用在于降低了程序的耦合度,提高了程序的扩展力。它通过驱动程序管理类(DriverManager)这个JDBC的管理类,作用于用户和驱动程序之间,提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
利用JDBC可以将JAVA代码连接到多种数据库,如oracle、DB2、SQLServer、MYSQL等,从而实现对数据库中的数据操作的目的。同时,JDBC具有很好的跨平台特性,使用JDBC编写的数据库应用程序可以在任何支持java的平台上运行,而不必在不同的平台上编写不同的应用程序。
Java、MySQL、JDBC、MyBatis和MyBatis Plus之间的关系、联系和区别如下:
总结起来,Java是编程语言,MySQL是数据库管理系统,JDBC是Java和MySQL之间的连接桥梁,而MyBatis和MyBatis Plus是在JDBC基础上进一步封装和简化的持久层框架。
JDBC 的代码使用就不需要详细掌握了
数据库连接池是计算机技术中的一种特殊池,用于存储和复用数据库连接。我们可以将其类比为现实生活中的游泳池。
在日常生活中,如果我们想要游泳,通常需要去游泳池。游泳池为我们提供了方便的游泳场所,并节省了我们每一次都必须挖掘一个新的泳池的费用和时间。池中的水可以被不同的人共享,高效地利用了水资源。
类似地,当我们需要与数据库进行交互时,我们通常需要创建数据库连接。创建数据库连接需要消耗计算资源和时间,而且如果每个请求都创建新的数据库连接,系统性能会大大降低。这时,数据库连接池就发挥作用了。
数据库连接池就像一个有多个泳道的游泳池。每个泳道都像一个数据库连接,而泳道中的水就像数据库连接的资源。这些资源被多个用户共享,而不是每个用户都创建新的资源。这样,我们就可以更高效地利用系统资源,提高系统性能。
具体来说,当我们需要与数据库交互时,我们从数据库连接池中获取一个可用的数据库连接,就像从泳道中借一个游泳圈一样。用完后,我们把这个连接放回连接池中,就像把游泳圈还回泳道一样。如果连接池中没有可用的连接,那么将会自动创建新的连接。就像如果所有的游泳圈都被借走了,那么游泳池管理员会再放入一些新的游泳圈。
同时,数据库连接池还可以对连接进行管理和监控。比如当一个连接被使用时,连接池可以记录这个连接的创建时间、最近一次使用时间等信息,并在需要时自动关闭那些长时间未被使用的连接,释放系统资源。就像游泳池管理员会根据泳道的占用情况来关闭那些没有人使用的泳道,节省水资源。
因此,数据库连接池通过复用数据库连接、管理和监控连接等作用,提高了系统性能和资源利用率。
在数据库连接池中,如果所有的连接都被占满了,有以下几种解决办法:
- 等待:如果所有的连接都在被高频率地使用,但是并没有空闲连接,那么你可以选择等待,直到有连接空出来。
- 创建新的连接池:如果你需要更多的连接,你可以创建新的连接池。
- 优化连接使用:在连接池中,如果连接被占满了,也可以通过优化连接使用来进行解决。比如可以对连接进行分类,对不同类型的连接进行管理和复用,以更高效地利用系统资源。
因此,当游泳池中的泳道被占满了时,我们可以选择等待、提高泳姿或者寻找其他泳池。而在数据库连接池中,我们可以选择等待、创建新的连接池或者优化连接使用。
不同的编程语言和数据库系统有不同的默认连接池。以下是一些常见的默认连接池:
需要注意的是,默认连接池可能因不同的版本和配置而有所不同,如果需要使用自定义的连接池,则需要在配置中进行相应的设置和指定。
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
这个时候,在原先的实体类中,注释掉 setter、getter、toString、构造方法
使用 Data 注解即可
运行结果依旧正确:
-- 部门管理
create table dept(
id int unsigned primary key auto_increment comment '主键ID',
name varchar(10) not null unique comment '部门名称',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '部门表';
insert into dept (id, name, create_time, update_time) values(1,'学工部',now(),now()),(2,'教研部',now(),now()),(3,'咨询部',now(),now()), (4,'就业部',now(),now()),(5,'人事部',now(),now());
-- 员工管理
create table emp (
id int unsigned primary key auto_increment comment 'ID',
username varchar(20) not null unique comment '用户名',
password varchar(32) default '123456' comment '密码',
name varchar(10) not null comment '姓名',
gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
image varchar(300) comment '图像',
job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
entrydate date comment '入职时间',
dept_id int unsigned comment '部门ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '员工表';
INSERT INTO emp
(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2010-01-01',2,now(),now()),
(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());
在这里,@Delete后面写的是“delete from emp where id = #{id}”;而不是“delete from emp where id = 7 ”
因为,如果是后者,就会静态的只能删除 i 为 7 的数据,前者可以 在方法参数中设置传入的参数的值,在 sq 语中,#{id}来接收传进来的 i 值
如果将这里的 void 变为 int,最后测试的时候返回的是这个 sq 语影响的行数
@Test
public void testDeleteById(){
empMapper.deleteById(17);
}
@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);
这里同样将 SQ 语设置为动态的,只不过在方法的形参列表中传递的不是一个个的参数,而是实体类 Emp 的对象 emp,在调用方法的时候,设置并传入 emp 的相应的参数
@Test
public void testInsert(){
//构造员工对象
Emp emp =new Emp();
emp.setUsername("zhang");
emp.setName("张章");
emp.setImage("1.png");
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);
}
如果直接输出获取主键,会发现返回的是 Null 而无法获得主键
只需要在@insert注解上面加上 options 注即可,这里第一个属性表示主键是 id 字段,第二个属性表示要获取主键
@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);
@Test
public void testUpdate(){
//构造员工对象
Emp emp =new Emp();
emp.setId(1);
emp.setUsername("haenggg");
emp.setName("张g11111章");
emp.setImage("121.png");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
//执行更新员工信息操作
empMapper.update(emp);
}
@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);
将 mapper 接口的注解注释掉,只保留方法
EmpMapper.xml 如下:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.EmpMapper">
<select id="list" resultType="com.example.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>
随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。
如果将 test 中的查询条件只设置 name,其他为 null,则无法查询到结果,因为此时是静态的,接口中设置了几个查询条件 test 中就要查询几个条件
这时候可以在 xml 配置文件中编写如下 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">
<mapper namespace="com.example.mapper.EmpMapper">
<select id="list" resultType="com.example.pojo.Emp">
select *
from emp
where
<if test="name!=null">
name like concat('%',#{name},'%')
</if>
<if test="gender!=null">
and name like concat('#{gender}')
</if>
<if test="begin!=null and end!=null">
and entrydate between #{begin} and #{end}
</if>
order by update_time desc
</select>
</mapper>
设置动态 sql
即可查询所有姓名中带有”张“的信息
同理,如果这时候查询条件只有两个也可以
但是,如果这样查询就会报错,因为如果第一个条件为 null,sql 语句就会开头出现 and 而语法错误
这个时候可以使用标签
在之前的更新的时候,有些字段需要更新,有些字段不需要更新,所以写代码的时候只需要写需要进行更新的字段就行了,但是,如果不需要更新的字段不写,就会默认更新为 null
如果要使用动态 SQL,则只需要写想要更新的字段,其他字段不会改变而不会变成 null
使用 xml 配置文件
在接口文件中编写一个 update 方法
会发现报错为没有 xml 映射文件的 sql 代码,这时候鼠标放在红线上,点击即可在 xml 文件中创建(因为安装了 MybatisX 插件)
将更新 SQL语句更写为如下:
对于这里的标签,如果只更改 username,那么后面的都不会成立,那么,会多一个逗号
会语法错误,使用 set 标签可解决这个问题
即可动态更新
此时如果只想将 id 为 1 的 name 改为 qqqqq
<mapper namespace="com.example.mapper.EmpMapper">
<!--批量删除员工 (1,2,3)-->
<!--
collection: 遍历的集合
item: 遍历出来的元素
separator: 分隔符
open: 遍历开始前拼接的SQL片段
close: 遍历结束后拼接的SQL片段
-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>