目录
至此,关于MySQL数据库的内容已经学习完毕了,包括数据库的设计、数据库的操作、数据库的优化,在学习MySQL的时候都是在图形化界面工具DateGrip当中来操作的,通过图形化界面工具直接在查询控制台当中编写SQL语句来完成数据库中数据的增删改查操作。而我们在以后项目开发当中,并不会每一次都基于图形化界面工具来操作数据库当中的数据,而是通过Java程序来完成数据库的操作,而Java程序来操作数据库现在最主流的技术当属MyBatis。
- 在客户端工具中,编写增删改查的SQL语句,发给MySQL数据库管理系统,由数据库管理系统执行SQL语句并返回执行结果。
- 增删改操作:返回受影响行数
- 查询操作:返回结果集(查询的结果)
我们做为后端程序开发人员,通常会使用Java程序来完成对数据库的操作。Java程序操作数据库,现在主流的方式是:Mybatis。
什么是MyBatis?
先来看一下MyBatis官网的解释:
什么是 MyBatis?
- MyBatis是一款用Java语言编写的持久层框架,它使用ORM实现了结果集的封装。
- ORM是Object Relational Mapping对象关系映射,简单说,就是把数据库表中字段和实体类实体类的属性对应起来,让开发者通过操作实体类就可以实现操作数据库表,它封装了JDBC操作的许多细节,使开发者只需要关注SQL语句本身,而无需关心注册驱动、创建连接等复杂过程。
- ORM:Object-Relation-Mapping,也就是对象关系映射,是一种程序设计思想,MyBatis就是ORM的一种实现方式,简单来说就是将数据库中查询出来的数据映射到对应的实体中,底层通过反射机制来自动赋值。
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
-
MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发。
-
MyBatis本是 Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
在上面我们提到了两个词:一个是持久层,另一个是框架。
-
持久层:指的就是Web开发三层架构当中的数据访问层(dao),是用来操作数据库的。
-
数据访问层(dao)也就持久层,就是与数据库打交道的,也就是说MyBatis框架它就是在DAO持久层当中用来操作数据库的。
-
持久层负责将数据保存到数据库的那一层代码。
-
JavaEE的三层架构:表现层(用来做页面展示的)、业务层(用来做逻辑处理的)、持久层(对数据进行持久化的,保存到数据库的)。
-
JDBC它是Sum公司提出的JavaEE13项规范之一,是Sum公司提供的用来操作数据库的一套规范。
-
但是如果直接使用底层的JDBC程序来操作数据库会非常的繁琐,所以现在基本上使用的都是主流的MyBatis框架来简化JDBC的开发。
-
框架:是一个半成品软件,是一套可重用的、通用的、软件基础代码模型。在框架的基础上 进行软件开发更加高效、规范、通用、可拓展。
持久层框架普及:
- Spring Data JPA、Hibernate、MyBatis-Plus
Mybatis课程安排:
-
Mybatis入门:通过一个入门程序,快速感受一下通过Mybatis如何来操作数据库的以及 MyBatis的开发流程。
-
Mybatis基础增删改查:这个也是使用MyBatis操作数据库的基本功,也是我们项目开发当中 使用频次最高的功能。
-
Mybatis动态SQL:MyBatis的高级特性。
基于SpringBoot整合MyBatis的方式来讲解MyBatis,因为在现在的企业开发当中,绝大部分的项目都是基于SpringBoot去构建的。所以我们在项目当中使用MyBatis也是直接使用SpringBoot去整合MyBatis,这也是企业开发当中最为普遍最为主流的一种方式。
接下来,我们就通过一个入门程序,让大家快速感受一下通过Mybatis如何来操作数据库。
一. MyBatis入门
- 快速入门:通过一个入门程序,快速感受一下通过Mybatis如何来操作数据库
- JDBC介绍:MyBatis框架的底层实现 --- JDBC
- 数据库连接池(技术)
- lombok(小工具)
1. 快速入门
导学:掌握MyBatis开发的基本流程
需求:使用Mybatis查询所有用户数据。
MyBatis操作数据库的方式和图形化界面工具操作数据库的方式,底层的逻辑是一样的。
1.1 入门程序分析
以前我们是在图形化客户端工具中编写SQL查询代码,发送给数据库服务器来执行,数据库执行后返回操作结果。
图形化工具会把数据库执行的查询结果,使用表格的形式展现出来:
现在使用Mybatis操作数据库,就是在Java程序当中来编写SQL查询代码,然后再将这条SQL语句发送给数据库服务器来执行,数据库执行后返回结果给Java程序。
Mybatis(Java程序)会把数据库执行的查询结果,使用实体类封装起来(一行记录对应一个实体类对象),也就是说,返回的每一条数据都会封装为一个对象,表中的字段最终会自动地封装到对象的属性当中。
建议让表中字段名与类中属性名保持一致,这样框架就可以完成自动封装。
MyBatis操作数据库其实就是在Java程序当中编写SQL语句,然后把这个SQL语句发送给数据库服务器执行,此时Java程序需要知道要把这个SQL语句发送给哪一台数据库,因此我们就需要配置数据库的连接信息。
数据库连接信息的配置方式和图形化界面工具的配置方式是一样的。
Mybatis操作数据库的步骤:
- 准备工作(创建springboot工程、数据库表user、实体类User) [实体类用来封装用户信息]
- 引入Mybatis的相关依赖,配置Mybatis(配置数据库连接信息)
- 编写SQL语句(注解/XML)
1.2 入门程序实现
1.2.1 准备工作
1.2.1.1 创建springboot工程
创建springboot工程,并导入 mybatis的起步依赖、mysql的驱动包。
Location代表的是我们所创建的这个模块放在哪一个磁盘目录下。
项目工程创建完成后,自动在pom.xml文件中,导入Mybatis依赖和MySQL驱动依赖
打开新创建的SpringBoot项目,删除不需要的文件和文件夹,保持工程的简洁
SpringBoot工程创建好了之后就自带了一份默认的配置文件 --- application.properties
注意:必须保持SpringBoot的版本与MyBatis的版本相对应,否则后面程序运行会报错!
也就是说,SpringBoot的版本是2.xxx,MyBatis的版本也要2.xxx
<dependencies>
<!--mybatis框架的起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!--mysql的驱动包依赖,刚刚发布的最新版本的驱动包-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
<version>8.0.33</version>
</dependency>
<!--上一个版本的驱动包-->
<!--<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>-->
<!--springboot单元测试所需要的依赖(集成了junit)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
1.2.1.2 数据准备
创建用户表user,并创建对应的实体类User。
-
用户表:
-
实体类:用来封装用户信息
-
实体类的属性名与表中的字段名一一对应。
-
在创建出来的springboot工程中,在引导类所在包下,在创建一个包 pojo,在pojo包下创建一个实体类 User,用来封装用户信息。
注意:POJO实体类当中的属性应全部用引用数据类型!
package com.gch.pojo;
/**
* 包pojo专门用来存放实体类
* 实体类User用来封装用户信息
* 实体类当中的属性与表中的字段是一一对应的
*/
public class User {
// 在实体类定义的时候,推荐使用包装类型
private Integer id; // id(主键)
private String name; // 姓名
// tinyint(MySQL) --- short(Java)
private Short age; // 年龄
private Short gender; // 性别
private String phone; // 手机号
//省略GET, SET方法
}
1.2.2 配置Mybatis
在之前使用图形化客户端工具,连接MySQL数据库时,需要配置:
连接数据库的四大参数:
- MySQL驱动类
- 登录名
- 密码
- 数据库连接字符串
配置数据库连接的四项信息:
a. Driver:数据库连接的驱动 指定数据库驱动类的全类名
b. 数据库连接的URL
- localhost之前是协议部分,协议之后的部分指定了当前要连接的是哪一个数据库服务器
- locathost代表的是本机 3306:指的是数据库服务器的端口号
- 在后面再加上一个/ + 数据库的名字,代表我们要连接的是这个数据库服务器当中的哪一个数据库
- 在图形化界面工具当中,为了展示的更加直观,操作的更加方便,将URL当中的主机地址、端口号以及数据库的名字这三个部分又单独的在上面展示出来了, 分别是Host、Port和Database
c. 数据库访问的用户名
- User:用户名
d. 数据库访问的密码
- password:密码
以上就是我们连接数据库时所需要指定的四项信息!
由于MyBatis操作数据库的方式和图形化界面工具操作数据库的方式底层逻辑是一样的,因此在MyBatis操作数据库的时候,我们也是需要配置数据库连接的这四项信息,包括:
- 驱动类的全类名 数据库连接的URL 访问数据库的用户名和密码
这四项信息我们也称之为数据库连接的四要素。
MyBatis操作数据库的方式和图形化界面工具操作数据库的方式,底层的逻辑是一样的。
数据库连接信息的配置方式和图形化界面工具的配置方式是一样的。
基于上述分析,在Mybatis中要连接数据库,同样也需要以上4个参数配置。
在springboot项目中,可以编写application.properties文件,配置数据库连接信息。我们要连接数据库,就需要配置数据库连接的基本信息,包括:driver-class-name、url 、username,password。
在入门程序中,大家可以直接这么配置,后面会介绍什么是驱动。
由于我们现在使用的是SpringBoot整合MyBatis,所以这一部分的信息我们就需要配置在SpringBoot默认的配置文件application.properties当中,而properties配置文件的配置形式是Key = value,等号之前是属性名,等号之后是属性值。
application.properties:
#配置数据库的连接信息 --- 四要素
#驱动类名称
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
- 上述的配置,可以直接复制过去,不要敲错了。 全部都是 spring.datasource.xxxx 开头。
1.2.3 编写SQL语句
在创建出来的springboot工程中,在引导类所在包下,在创建一个包 mapper,在mapper包下创建一个接口 UserMapper ,这是一个持久层接口(Mybatis的持久层接口规范一般都叫 XxxMapper)。
在MyBatis当中定义SQL语句有两种方式,一种方式就是基于注解来定义,另外一种方式就是基于XML来定义。
在入门程序阶段,我们直接基于注解的方式来定义SQL语句。
在Mapper接口当中如何来编写SQL语句?
- 按照MyBatis的规范,我们需要定义一个持久层的接口,并且在接口上加上一个@Mapper注解来标识当前是MyBatis当中的一个持久层的接口,这个接口其实就是三层架构当中的数据访问层也就是dao层的接口,一般称为Mapper接口。
- 然后在Mapper接口当中定义一个方法,上面加上一个注解@Select,来指定当前是一个查询操作,然后在这个注解当中再来指定要执行的SQL语句。
- 最终,我们要想执行这条SQL语句,只需要调用Mapper接口当中的这个list方法就可以,此时,框架就会自动的执行这条SQL语句,并自动的将SQL语句执行的结果封装到方法的返回值当中。
UserMapper:
package com.gch.mapper;
import com.gch.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
基于注解的方式来定义SQL语句
定义持久层的Mapper接口放在单独的包mapper包下,这个包类似于三层架构当中的dao
*/
@Mapper // 代表当前是MyBatis当中的一个Mapper接口
// 在程序运行时,框架会自动的生成该接口的实现类对象(动态代理技术所生成的一个代理对象),并且框架会将该对象交给Spring的IOC容器管理
// 该接口的实现类对象已经成为IOC容器当中的Bean了
public interface UserMapper {
/**
* 查询全部的用户信息
* 其中的每一条记录会封装为一个对象
* @Select注解来指定当前要执行的是一个查询操作,在@Select注解的value属性当中就可以来指定要执行的SQL语句
* @return:把从数据库查询到的每一条记录封装为一个User对象封装到List集合当中
*/
@Select("select * from user")
public List<User> list();
}
@Mapper注解:表示是MyBatis中的Mapper接口
程序运行时:框架会自动生成接口的实现类对象(代理对象),并给交Spring的IOC容器管理
@Select注解:代表的就是select查询,用于书写select查询语句
1.2.4 单元测试
在创建出来的SpringBoot工程中,在src下的test目录下,已经自动帮我们创建好了测试类 ,并且在测试类上已经添加了注解 @SpringBootTest,代表该测试类已经与SpringBoot整合。
该测试类在运行时,会自动通过引导类加载Spring的环境(IOC容器)。我们要测试那个bean对象,就可以直接通过@Autowired注解直接将其注入进行,然后就可以测试了。
测试类代码如下:
package com.gch;
import com.gch.mapper.UserMapper;
import com.gch.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.ArrayList;
import java.util.List;
/**
* 按照标准的Maven项目结构来说,单元测试的代码不应该在main目录下,而应该在test目录下
* 该类是SpringBoot工程创建好了之后自带的一个类,是一个测试类 --- 单元测试
* 说明:由于这个单元测试是SpringBoot整合的单元测试,上面加了一个注解@SpringBootTest,
一旦加了这个注解,其中的单元测试方法在运行的时候它就会
* 自动的加载整个SpringBoot的环境,并且创建Spring的IOC容器,IOC容器创建好了之后
就可以通过依赖注入的形式从IOC容器当中获取到UserMapper这个类型的Bean对象
* 接下来就可以调用这个Bean对象当中的list方法来查询全部用户信息了。
*/
@SpringBootTest // 是springboot整合单元测试的注解
class SpringbootMybatisQuickstartApplicationTests {
// 由于UserMapper接口的实现类对象已经成为IOC容器当中的Bean了
// 所以要想使用这个Bean对象,就可以通过依赖注入的形式将这个Bean对象注入进来
@Autowired
private UserMapper userMapper;
/**
* 查询全部的用户信息
*/
@Test
public void testListUser(){
// 要用IOC容器当中的Bean对象,就可以通过依赖注入的形式将这个Bean对象注入进来
List<User> userList = userMapper.list();
userList.stream().forEach(user ->{
System.out.println(user);
});
}
}
运行结果:
经过上面这三步操作之后,我们就完成了数据的查询操作。
对于上述这三步操作,前两步当中的创建SpringBoot工程,引入MyBatis的相关依赖,配置MyBatis,对于一个项目来说,只需要操作一次就可以了。在学习MyBatis的时候,需要重点关注的就是第三步:在Mapper接口当中如何来编写SQL语句。
这就是入门程序的步骤!
因为我们现在使用的是MyBatis框架,MyBatis框架已经对数据库的操作进行了很好的封装,所以我们只需要编写少量的Java代码就可以完成数据库的操作。
说明:在MyBatis的开发当中,我们只需要去定义这个Mapper接口就可以了,是不需要定义它的 实现类的,因为程序在运行时框架底层会自动生成这个接口的实现类对象。
1.3 配置SQL提示 --- 解决SQL警告与提示
默认在MyBatis中编写SQL语句是不识别的。
默认我们在UserMapper接口上加的@Select注解中编写SQL语句是没有提示的。 如果想让idea给我们提示对应的SQL语句,我们需要在IDEA中配置与MySQL数据库的链接。
默认我们在UserMapper接口上的@Select注解中编写SQL语句是没有提示的。如果想让idea给出提示,可以做如下配置:
配置完成之后,发现SQL语句中的关键字有提示了,但还存在不识别表名(列名)的情况:
产生原因:Idea和数据库没有建立连接,不识别表信息
解决方案:在IDEA中配置MySQL数据库连接
在配置的时候指定连接那个数据库,如上图所示连接的就是mybatis数据库。
然后点击Apply ===> 再点击OK
2. JDBC介绍(了解)
2.1 介绍
导学:到底什么是JDBC以及通过JDBC程序如何来操作数据库,然后再将MyBatis程序与JDBC程 序进行一个对比,来看一下MyBatis到底简化了JDBC的哪些操作
通过Mybatis的快速入门,我们明白了,通过Mybatis可以很方便的进行数据库的访问操作。但是大家要明白,其实Java语言操作数据库呢,只能通过一种方式:使用sun公司提供的JDBC规范。
Mybatis框架,就是对原始的JDBC程序的封装,从而来简化开发,提高性能。
那到底什么是JDBC呢,接下来,我们就来介绍一下。
JDBC: ( Java DataBase Connectivity ),就是使用Java语言操作关系型数据库的一套API。
- JDBC就是sun公司提供的使用Java语言来操作关系型数据库的一套API。
- 换句话说,就是现在我们Java程序要想去操作MySQL,Oracle,SQL Server这些关系型数据库,就得通过Sun公司提供的JDBC的这套API来操作。
- 我们知道关系型数据库的产品有很多,而不同的数据库产品底层实现也是有非常大的差异的,底层的实现方式不同,也就意味着操作的方式也不一样,那Sun公司提供的操作关系型数据库的这套API --- JDBC,它又是如何来操作所有的关系型数据库的?
- 是因为Sun公司提供的JDBC仅仅是一套规范,一套接口而已,它并没有提供具体的实现,那谁来提供具体的实现呢?
- 是由各个数据库厂商提供的,因为一个数据库它的底层实现细节,它的操作方式各个厂商是最清楚的,所以是由各个厂商来提供JDBC的实现,比如MySQL的厂商要提供MySQL数据库的JDBC实现,Oracle的厂商要提供Oracle数据库的JDBC实现,SQL Server的厂商要提供SQL Server数据库的JDBC的实现,而我们最终在编写Java程序的时候,我们直接使用面向接口编程,使用JDBC当中所提供的接口来操作就可以,最终其实就是通过我们所引入进来的各个数据库厂商提供的JDBC的实现来操作对应的数据库。
- 而各个厂商提供的JDBC规范的实现,又有一个非常高大上的名字,叫数据库的驱动,就比如我们刚才入门程序当中所引入进来的MySQL的驱动,这个就是MySQL厂商提供的JDBC的实现。
简答介绍了一下JDBC,小结一下JDBC:
本质:
sun公司官方定义的一套操作所有关系型数据库的规范,即接口。
各个数据库厂商去实现这套接口,提供数据库驱动jar包。
我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
- JDBC它的本质就是Sun公司提供的一套操作所有关系型数据库的规范,而规范指的就是接口。
- Sun公司并不提供JDBC的实现,JDBC的实现是由各个数据库厂商去提供的,我们也叫数据库驱动的jar包。
- 而我们在Java程序当中使用JDBC,我们将会采用面向接口的方式进行编程,我们将会使用JDBC当中所提供的一系列的接口来操作,而真正执行的代码是驱动jar包当中所提供的实现类。
2.2 代码
下面我们看看原始的JDBC程序是如何操作数据库的。操作步骤如下:
-
注册驱动
-
获取连接对象
-
执行SQL语句,返回执行结果
-
处理执行结果
-
释放资源
- 在pom.xml文件中已引入MySQL驱动依赖,我们直接编写JDBC代码即可
JDBC具体代码实现:
/**
* 使用原始的JDBC程序来操作数据库
* @throws Exception
*/
@Test
public void testJdbc() throws Exception {
// 1. 注册驱动:其实就是告诉JDBC我们要使用的是哪一个驱动类
Class.forName("com.mysql.cj.jdbc.Driver");
/**
* 2. 获取连接对象
* 我们要操作数据库就需要通过程序和数据库建立连接,所以第二步需要获取到一个连接对象connection
* 在获取连接对象时,我们需要指定数据库连接的url,username,password
*/
String url = "jdbc:mysql://localhost:3306/mybatis";
String username = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url, username, password);
// 3. 获取执行SQL的对象Statement,执行SQL,返回结果
String sql = "select * from user";
Statement statement = connection.createStatement();
// 由于是一个查询操作,所以在执行完毕之后,它会给我们返回这样一个结果集resultSet
// 这个resultSet叫结果集对象,里面就封装了查询返回回来的结果
ResultSet resultSet = statement.executeQuery(sql);
/**
* 4. 封装结果数据
* 解析返回回来的resultSet结果集对象
* resultSet结果集对象在解析的时候需要一个字段一个字段的解析
*/
List<User> userList = new ArrayList<>();
while (resultSet.next()){
// 有多少个字段,我们就需要解析多少次
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
short age = resultSet.getShort("age");
short gender = resultSet.getShort("gender");
String phone = resultSet.getString("phone");
// 解析完成后,手动将这个结果封装为一个用户对象
User user = new User(id,name,age,gender,phone);
// 将该对象添加到List集合当中
userList.add(user);
}
//5. 释放资源
statement.close();
connection.close();
// 遍历集合
for (User user : userList) {
System.out.println(user);
}
}
package com.gch;
import com.gch.mapper.UserMapper;
import com.gch.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* 按照标准的Maven项目结构来说,单元测试的代码不应该在main目录下,而应该在test目录下
* 该类是SpringBoot工程创建好了之后自带的一个类,是一个测试类 --- 单元测试
* 说明:由于这个单元测试是SpringBoot整合的单元测试,上面加了一个注解@SpringBootTest,一旦加了这个注解,其中的单元测试方法在运行的时候它就会
* 自动的加载整个SpringBoot的环境,并且创建Spring的IOC容器,IOC容器创建好了之后就可以通过依赖注入的形式从IOC容器当中获取到UserMapper这个类型的Bean对象
* 接下来就可以调用这个Bean对象当中的list方法来查询全部用户信息了。
*/
@SpringBootTest // 是springboot整合单元测试的注解
class SpringbootMybatisQuickstartApplicationTests {
// 由于UserMapper接口的实现类对象已经成为IOC容器当中的Bean了
// 所以要想使用这个Bean对象,就可以通过依赖注入的形式将这个Bean对象注入进来
@Autowired
private UserMapper userMapper;
/**
* 使用原始的JDBC程序来操作数据库
* @throws Exception
*/
@Test
public void testJdbc() throws Exception {
// 1. 注册驱动:其实就是告诉JDBC我们要使用的是哪一个驱动类
Class.forName("com.mysql.cj.jdbc.Driver");
/**
* 2. 获取连接对象
* 我们要操作数据库就需要通过程序和数据库建立连接,所以第二步需要获取到一个连接对象connection
* 在获取连接对象时,我们需要指定数据库连接的url,username,password
*/
String url = "jdbc:mysql://localhost:3306/mybatis";
String username = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url, username, password);
// 3. 获取执行SQL的对象Statement,执行SQL,返回结果
String sql = "select * from user";
Statement statement = connection.createStatement();
// 由于是一个查询操作,所以在执行完毕之后,它会给我们返回这样一个结果集resultSet
// 这个resultSet叫结果集对象,里面就封装了查询返回回来的结果
ResultSet resultSet = statement.executeQuery(sql);
/**
* 4. 封装结果数据
* 解析返回回来的resultSet结果集对象
* resultSet结果集对象在解析的时候需要一个字段一个字段的解析
*/
List<User> userList = new ArrayList<>();
while (resultSet.next()){
// 有多少个字段,我们就需要解析多少次
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
short age = resultSet.getShort("age");
short gender = resultSet.getShort("gender");
String phone = resultSet.getString("phone");
// 解析完成后,手动将这个结果封装为一个用户对象
User user = new User(id,name,age,gender,phone);
// 将该对象添加到List集合当中
userList.add(user);
}
//5. 释放资源
statement.close();
connection.close();
// 遍历集合
for (User user : userList) {
System.out.println(user);
}
}
}
DriverManager(类):数据库驱动管理类。
作用:
注册驱动
创建java代码和数据库之间的连接,即获取Connection对象
Connection(接口):建立数据库连接的对象
作用:用于建立java程序和数据库之间的连接
Statement(接口): 数据库操作对象(执行SQL语句的对象)。
作用:用于向数据库发送sql语句
ResultSet(接口):结果集对象(一张虚拟表)
作用:sql查询语句的执行结果会封装在ResultSet中
- 通过上述代码,我们看到直接基于JDBC程序来操作数据库,代码实现非常繁琐,所以在项目开发中,我们很少使用。
- 在项目开发中,通常会使用Mybatis这类的高级技术来操作数据库,从而简化数据库操作、提高开发效率。
2.3 问题分析
原始的JDBC程序,存在以下几点问题:
数据库链接的四要素(驱动、链接、用户名、密码)全部硬编码在java代码中
查询结果的解析及封装非常繁琐,造成代码臃肿 [因为需要一个字段一个字段去解析]
每一次查询数据库都需要获取连接,操作完毕后释放连接,频繁的去获取连接、释放连接会造成资源浪费, 性能降低
在获取连接的时候,要指定数据库连接的URL、username和password,这部分的信息在我们项目开发当中是比较容易变动的,特别是下面的URL、username和password,我们在项目开发时,在开发阶段,我们将会连接开发数据库;在测试阶段,将会连接测试数据库;在生成阶段,将会连接生产数据库。那此时,URL、username和password都有可能会发生变动,在原始的JDBC程序当中,我们是将其写死在了Java代码当中,这个我们叫硬编码。
硬编码的弊端:一旦这一块儿的内容发生变化了,由于这是Java代码,代码就需要重新编译、打 包之后才能运行,比较繁琐。
2.4 技术对比
分析了JDBC的缺点之后,我们再来看一下在mybatis中,是如何解决这些问题的:
-
数据库连接四要素(驱动、链接、用户名、密码),都配置在springboot默认的配置文件 application.properties当中,以后我们要修改这一块的信息,就不用再去操作Java代码了,直接操作配置文件就可以了
-
查询结果的解析及封装,由mybatis自动完成映射封装,我们无需关注
-
在MyBatis中使用了数据库连接池技术,从而避免了频繁的创建连接、销毁连接而带来的资源浪费。
- 在MyBatis当中,我们在SpringBoot默认的配置文件applicaton.properties当中配置数据库连接信息的时候,所有的配置项它的前缀都是spring.datasource,翻译过来叫数据源,当我们按照这种方式来配置数据库连接信息之后,SpringBoot底层就会自动的采用数据库连接池技术来同意管理和分配这些连接,而这个连接指的就是connection对象
- 有了连接池之后,每一次在执行SQL语句的时候,我们只需要从连接池当中获取一个连接,然后来执行这条SQL语句,这条SQL语句执行完毕之后,再将这个连接归还给连接池,这样就可以做到连接的复用,而不是每一次都来创建一个新的连接,从而就避免了频繁的获取连接和释放连接而造成的资源浪费。
- 使用SpringBoot+Mybatis的方式操作数据库,能够提升开发效率、降低资源浪费
我们使用SpringBoot整合MyBatis框架进行数据库操作的时候,我们主要关注两点:
而对于Mybatis来说,我们在开发持久层程序操作数据库时,需要重点关注以下两个方面:
1. application.properties当中关于MyBatis的相关配置
2. Mapper接口以及所定义的SQL语句(编写SQL语句)
3. 数据库连接池
在前面我们谈到在使用SpringBoot整合MyBatis框架操作数据库的时候,使用了数据库连接池技术,避免频繁的创建连接、销毁连接而带来的资源浪费。
下面我们就具体的了解下数据库连接池。
导学:什么是数据库连接池?它的作用是什么?以及我们如何来切换不同的连接池产品?
- 数据库线程池类似于线程池,它也是一个容器,而这个容器当中存储的是一个一个的数据库连接对象connection。
没有使用数据库连接池:
- 客户端执行SQL语句:要先创建一个新的连接对象,然后执行SQL语句,SQL语句执行后又需要关闭连接对象从而释放资源,每次执行SQL时都需要创建连接、销毁链接,这种频繁的重复创建销毁的过程是比较耗费计算机的性能。
数据库连接池是个容器,负责分配、管理数据库连接(Connection)
程序在启动时,会在数据库连接池(容器)中,初始化 / 创建一定数量的Connection对象
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
客户端在执行SQL时,先从连接池中获取一个Connection对象,然后在执行SQL语句,SQL语句执行完之后,释放Connection时就会把Connection对象归还给连接池(Connection对象可以复用),这样就可以做到连接的复用,而不是每一次都来创建一个新的连接
释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
当各个客户端在执行SQL语句的时候,它会从连接池当中来获取相关的连接,SQL语句执行完毕之后,再将这个连接归还给连接池,如果说有个别的客户端获取到Connection对象了,但是Connection对象一直处于空闲状态,并没有去访问数据库去操作数据库当中的数据(处于空闲),此时数据库连接池就去会监测这个连接的空闲时间,如果数据库连接池发现Connection对象的空闲时间 > 连接池中预设的最大空闲时间,此时数据库连接池就会自动释放掉这个连接对象,这样就可以避免某一些连接没有及时地得到释放而造成数据库连接池当中的连接越用越少。
连接越来越少之后,可能就会出现一个问题:再过来一个客户端去获取连接,发现连接池当中已经没有可用的连接了,那此时,就相当于把这个客户端遗漏了,没有给它分配到连接。
数据库连接池的好处 / 优势:
资源重用(资源指的就是数据库的连接 --- connection)
提升系统响应速度(因为创建连接是一个比较耗时而且比较耗费资源的操作,而我们现在连接重用了之后,就可以提升系统的响应速度)
避免数据库连接遗漏
3.2 产品
我们该怎么样来实现这样一个数据库连接池呢?
要怎么样实现数据库连接池呢?
Sun公司的官方给我们提供了一个标准的数据库连接池的接口 --- DataSource,所有的数据库连接池都需要实现这个标准的接口 --- DataSource,并且要去实现其中一个比较核心的功能方法 --- getConnection()
官方(sun)提供了数据库连接池标准(javax.sql.DataSource接口)
-
功能:获取连接
public Connection getConnection() throws SQLException;
-
第三方组织必须按照DataSource接口实现
数据库连接池其实并不需要我们去实现,目前市面上有非常多的优秀的连接池技术 / 产品。
常见的数据库连接池:
-
C3P0
-
DBCP
-
Druid [德鲁伊]
-
Hikari [追光者] (springboot当中默认自带的连接池)
现在使用更多的是:Hikari、Druid (性能更优越)
- Hikari(追光者) [SpringBoot默认的连接池]
-
Druid(德鲁伊)
-
Druid连接池是阿里巴巴开源的数据库连接池项目
-
功能强大,性能优秀,是Java语言最好的数据库连接池之一
-
如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要完成以下两步操作即可:
1. 在pom.xml文件中引入依赖
<dependency>
<!-- Druid连接池的起步依赖 -->
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
2. 在application.properties中引入数据库连接配置 / 配置数据库的连接信息
方式1:[在datasource之后再来加一层druid,代表我们选择使用的是druid连接池]
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.druid.username=root
spring.datasource.druid.password=123456
方式2:[原始的配置方式,我们自己就是用的这种配置方式]
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.username=root
spring.datasource.password=123456
测试:
数据库连接池小结:
4. lombok
4.1 介绍
Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化Java开发、提高效率。
Lombok是一个实用的Java类库,可以通过简单的注解来简化和消除一些必须有但显得很臃肿的Java代码,简化实体类的定义,提高开发效率。
通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。
注解 | 作用 |
---|---|
@Getter/@Setter | 为所有的属性提供get/set方法 |
@ToString | 会给类自动生成易阅读的 toString 方法 |
@EqualsAndHashCode | 根据类所拥有的非静态字段自动重写 equals 方法和 hashCode 方法 |
@Data | 提供了更综合的生成代码功能(@Getter + @Setter + @ToString + @EqualsAndHashCode) |
@NoArgsConstructor | 为实体类生成无参的构造器方法 |
@AllArgsConstructor | 为实体类生成除了static修饰的字段之外带有各参数的构造器方法。 |
4.2 使用
第1步:在pom.xml文件中引入依赖
<!--lombok-->
<!-- 在springboot的父工程中,已经集成了lombok并指定了版本号
(已经将lombok的依赖版本统一进行了管理),故当前引入依赖时不需要指定version -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
第2步:在实体类上添加注解
package com.gch.pojo;
import lombok.*;
/**
* 包pojo专门用来存放实体类
* 实体类User用来封装用户信息
* 实体类当中的属性与表中的字段是一一对应的
*/
//@Getter
//@Setter
//@ToString
//@EqualsAndHashCode
@Data
@NoArgsConstructor // 无参构造
@AllArgsConstructor // 全参构造
public class User {
// 在实体类定义的时候,推荐使用包装类型
private Integer id; // id(主键)
private String name; // 姓名
// tinyint(MySQL) --- short(Java)
private Short age; // 年龄
private Short gender; // 性别
private String phone; // 手机号
}
- 在实体类上添加了@Data注解,那么这个类在编译时期,就会生成getter/setter、equals、hashcode、toString等方法。
- lombok的原理:就是在程序编译的时候,根据上面提供的注解来决定为这个类生成什么样的方法。
查看类的字节码文件:
说明:@Data注解中不包含全参构造方法,通常在实体类上,还会添加上:全参构造、无参构造
import lombok.Data;
@Data //getter方法、setter方法、toString方法、hashCode方法、equals方法
@NoArgsConstructor //无参构造
@AllArgsConstructor//全参构造
public class User {
private Integer id;
private String name;
private Short age;
private Short gender;
private String phone;
}
Lombok的注意事项:
-
Lombok会在编译时,会自动生成对应的java代码
-
在使用lombok时,还需要安装一个lombok的插件(新版本的IDEA中自带)