后端Web实战-Java代码操作数据库

目录

1.JDBC

1.1概述

1.2快速入门

[1.3 API详解](#1.3 API详解)

[1.3.1 DriverManager](#1.3.1 DriverManager)

[1.3.1.1 注册驱动](#1.3.1.1 注册驱动)

[1.3.1.2 获取链接](#1.3.1.2 获取链接)

[1.3.2 Connection & Statement](#1.3.2 Connection & Statement)

[1.3.3 ResultSet](#1.3.3 ResultSet)

[1.3.4 PreparedStatement](#1.3.4 PreparedStatement)

2.Mybtis基础

[2.1 介绍](#2.1 介绍)

[2.2 快速入门](#2.2 快速入门)

[2.2.1 准备工作](#2.2.1 准备工作)

[2.2.2 编写SQL语句](#2.2.2 编写SQL语句)

[2.2.3 单元测试](#2.2.3 单元测试)

[2.3 辅助配置](#2.3 辅助配置)

[2.3.1 配置SQL提示](#2.3.1 配置SQL提示)

[2.3.2 配置Mybatis的日志输出](#2.3.2 配置Mybatis的日志输出)

[2.4 JDBC VS Mybatis](#2.4 JDBC VS Mybatis)

[2.5 数据库连接池](#2.5 数据库连接池)

[2.5.1 介绍数据库连接池](#2.5.1 介绍数据库连接池)

[2.5.2 如何实现数据库连接?](#2.5.2 如何实现数据库连接?)

[2.6 Mybatis的XML配置文件](#2.6 Mybatis的XML配置文件)

[2.6.1 XML配置文件规范](#2.6.1 XML配置文件规范)

[2.6.3 MybatisX的使用](#2.6.3 MybatisX的使用)

3.部门列表查询

[3.1 功能实现](#3.1 功能实现)

[3.1.1 需求](#3.1.1 需求)

[3.1.2 实现](#3.1.2 实现)

[3.2 数据封装](#3.2 数据封装)


1.JDBC

1.1概述

我们做为后端程序开发人员,通常会使用Java程序来完成对数据库的操作。Java程序操作数据库的技术呢,有很多啊。

  • JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。 【是操作数据库最为基础、底层的技术】

那现在在企业项目开发中呢,一般都会使用基于JDBC的封装的高级框架,比如:Mybatis、MybatisPlus、Hibernate、SpringDataJPA。

我们会学习目前最为主流的就是Mybatis,其次是MybatisPlus。

JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。

本质:

  • sun公司官方定义的一套操作所有关系型数据库的规范,即接口。

  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包。

  • 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

1.2快速入门

java 复制代码
public class JDBCTest {

    @Test
    public void testUpdate() throws Exception {
        //1.准备工作
        //1.1 注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");//固定步骤
        //1.2 获取数据库连接对象Connection
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java147_db02", "root", "456789");
        //1.3 获取SQL语句执行对象Statement
        Statement statement = connection.createStatement();

        //2.执行SQL语句
        //需求:修改用户表id为1的密码,修改为12345678
        int i = statement.executeUpdate("update user set password = '12345678' where id = 1;");
        System.out.println("i == " + i);

        //3.释放资源
        statement.close();
        connection.close();
    }
}

1.3 API详解

1.3.1 DriverManager

作用:

  • 注册驱动

  • 获取数据库链接 Connection

1.3.1.1 注册驱动

上述的代码中我们是通过class.forName("com.mysql.cj.jdbc.Driver")来注册的,看似和DriverManager没什么联系。其实不然,这段代码只是将Driver这个类加载到JVM中。而在Driver这个类中定义了静态代码块,内容如下:

Driver 这个类被加载时,就会自动执行静态代码块中的代码,然后就完成了注册驱动的操作。

备注:

而其实啊,class.forName("com.mysql.cj.jdbc.Driver") 这句代码呢,是可以省略的,省略了,也可以正常的完成驱动的注册。 原因是因为在MySQL的驱动jar包中,在 META-INF/services 目录中提供了一个文件 java.sql.Driver ,在这个文件中编写了一行内容,就是驱动类的全类名 :

当在程序需要用到这个类时,java会自动加载这个类,这个类一加载 就会自动执行静态代码块中的内容,就完成了注册驱动的操作 ,而java中的这个机制称之为 SPI

SPI机制:Service Provider Interface,JDK内置的一种服务提供发现机制,可以轻松的扩展你的程序(切换实现),实现接口与实现类之间的解耦。

1.3.1.2 获取链接

1.3.2 Connection & Statement

  • Connection的作用:获取执行SQL的对象

    • 执行普通SQL对象的Statement:connection.createStatement();

    • 执行预编译SQL对象PreparedStatement:connection.prepareStatement(); 【后面单独讲解】

  • Statement的作用:执行SQL

    • 执行DDL(数据库定义语句,一般不用)、DML(增删改)语句:executeUpdate(sql); 如果是执行DML语句完毕,返回值int代表 DML 语句影响的行数。

    • 执行SQL(查询)语句:executeQuery(sql); 返回值为ResultSet,里面封装了查询结果。

1.3.3 ResultSet

java 复制代码
@Test
    public void testSelect() throws Exception {
        //1.准备工作
        //1.1 注册驱动
        //Class.forName("com.mysql.cj.jdbc.Driver");//固定步骤
        //省略注册驱动也可以运行成功,
        //1.2 获取数据库连接对象Connection
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java147_db02", "root", "456789");
        //1.3 获取SQL语句执行对象Statement
        Statement statement = connection.createStatement();

        //2.执行SQL语句
        //需求:根据用户名和密码查询用户信息,模拟用户登录
        ResultSet resultSet = statement.executeQuery("select * from user where username = 'xiaoqiao' and password = '123456'");
        //判断是否有值
        while(resultSet.next()) {
            //输出结果--解析Resulet
            //int id = resultSet.getInt(1); //下标从1开始
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            String password = resultSet.getString("password");
            String name = resultSet.getString("name");
            int age = resultSet.getInt("age");
            User user = new User(id,username,password,name,age);
            System.out.println(user);
        }

        //3.释放资源
        statement.close();
        connection.close();
    }

在上述的单元测试中,我们在SQL语句中,将用户名和密码的值都写死了,而这两个值应该是动态的,是将来页面传递到服务端的。那么,我们可以基于前面所讲的JUnit中的参数化测试进行单元测试,代码改造如下:

java 复制代码
 @ParameterizedTest //参数化测试
    //@ValueSource(strings = {"xiaoqiao","123456"}) //代表一个参数分两次测试
    //所以@ValueSource只适合对一个参数进行测试的
    @CsvSource(value = {"xiaoqiao, 123456", "zhangsan, 123456"})
    public void testSelect(String uname,String pwd) throws Exception {
        //1.准备工作
        //1.1 注册驱动
        //Class.forName("com.mysql.cj.jdbc.Driver");//固定步骤
        //省略注册驱动也可以运行成功,
        //1.2 获取数据库连接对象Connection
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java147_db02", "root", "456789");
        //1.3 获取SQL语句执行对象Statement
        Statement statement = connection.createStatement();

        //2.执行SQL语句
        //需求:根据用户名和密码查询用户信息,模拟用户登录
        ResultSet resultSet = statement.executeQuery("select * from user where username = '"+uname+"' and password = '"+pwd+"'");
        //判断是否有值
        while(resultSet.next()) {
            //输出结果--解析Resulet
            //int id = resultSet.getInt(1); //下标从1开始
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            String password = resultSet.getString("password");
            String name = resultSet.getString("name");
            int age = resultSet.getInt("age");
            User user = new User(id,username,password,name,age);
            System.out.println(user);
        }

        //3.释放资源
        statement.close();
        connection.close();
    }

如果在测试时需要用一个参数就用@ValueSource(strings = {"xiaoqiao","123456"}) //代表一个参数分两次测试,如果需要用到一组参数就用 @CsvSource(value = {"xiaoqiao, 123456", "zhangsan, 123456"})进行注解。

1.3.4 PreparedStatement

  • 作用:预编译SQL语句并执行,可以防止SQL注入问题。

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

java 复制代码
@ParameterizedTest //参数化测试
    //@ValueSource(strings = {"xiaoqiao","123456"}) //代表一个参数分两次测试
    //所以@ValueSource只适合对一个参数进行测试的
    @CsvSource(value = {"xiaoqiao, 123456", "zhangsan, ' or '1' = '1"})
    public void testSelect(String uname,String pwd) throws Exception {
        //1.准备工作
        //1.1 注册驱动
        //Class.forName("com.mysql.cj.jdbc.Driver");//固定步骤
        //省略注册驱动也可以运行成功,
        //1.2 获取数据库连接对象Connection
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java147_db02", "root", "456789");
        //1.3 获取SQL语句执行对象Statement -- ?代表占位符
        PreparedStatement ps = connection.prepareStatement("select * from user where username = ? and password = ?");

        //1.4设置参数值
        ps.setString(1,uname);
        ps.setString(2,pwd);
        //2.执行SQL语句
        //需求:根据用户名和密码查询用户信息,模拟用户登录
        ResultSet resultSet = ps.executeQuery();
        //判断是否有值
        while(resultSet.next()) {
            //输出结果--解析Resulet
            //int id = resultSet.getInt(1); //下标从1开始
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            String password = resultSet.getString("password");
            String name = resultSet.getString("name");
            int age = resultSet.getInt("age");
            User user = new User(id,username,password,name,age);
            System.out.println(user);
        }

        //3.释放资源
        ps.close();
        connection.close();
    }

在预编译SQL语句中,当我们执行的时候,会把整个' or '1'='1作为一个完整的参数,赋值给第2个问号(' or '1'='1进行了转义,只当做字符串使用)

那么此时再查询时,就查询不到对应的数据了,登录失败。

注意:在以后的项目开发中,我们使用的基本全部都是预编译SQL语句。

预编译SQL的优势:

  • 安全(防止SQL注入)

  • 性能更高

PreparedStatement性能更高的主要原因与其预编译机制和数据库的执行优化有关:

1.SQL预编译与重用

PreparedStatement 会在创建时将 SQL 语句发送给数据库进行预编译(解析、优化、生成执行计划),后续执行时只需传入参数即可。

Statement 每次执行都需要重新发送完整 SQL、重新编译,这会产生额外的网络传输和数据库解析开销。

对于多次执行相同结构(仅参数不同)的 SQL(如批量插入、更新),PreparedStatement 的预编译结果可以重复使用,大幅减少重复工作。

2.数据库执行计划缓存

数据库通常会缓存预编译生成的执行计划,当再次执行相同 SQL 结构时,可直接复用缓存的计划,避免重复优化和计算,进一步提升效率。

3.参数高效处理

PreparedStatement 通过 setXxx() 方法设置参数,数据库会高效处理参数绑定,避免了字符串拼接 SQL 带来的额外解析成本(例如 Statement 中用 + 拼接参数的字符串操作)。

4.批量操作优化
PreparedStatement 支持 addBatch()executeBatch() 进行批量操作,数据库可以对批量命令进行合并处理,减少网络交互次数和事务提交开销,这在大量数据操作时优势明显。

2.Mybtis基础

2.1 介绍

什么是MyBatis?

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

  • MyBatis本是 Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

  • 官网:https://mybatis.org/mybatis-3/zh/index.html

在上面我们提到了两个词:一个是持久层,另一个是框架。

  • 持久层:指的是就是数据访问层(dao),是用来操作数据库的。

框架:是一个半成品软件,是一套可重用的、通用的、软件基础代码模型。在框架的基础上进行软件开发更加高效、规范、通用、可拓展。

2.2 快速入门

2.2.1 准备工作

项目工程创建完成后,自动在pom.xml文件中,导入Mybatis依赖和MySQL驱动依赖

XML 复制代码
<dependencies>
    <!-- Mybatis的起步依赖 -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>
	
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- lombok驱动 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
	
    <!-- 单元测试 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2.2.2 编写SQL语句

在创建出来的springboot工程中,在引导类所在包下,再创建一个包mapper。在,mapper包下创建一个接口UserMapper,这是一个持久层接口(Mybatis的持久层接口规范一般都叫XxxMapper)

UserMapper的内容如下:

java 复制代码
import com.itheima.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper //作用:程序启动时,会自动生成该接口的的代理对象,交由IOC容器管理
public interface UserMapper {

    //查询所有用户数据
    @Select("select * from user")
    public List<User> list();
}

@Mapper注解:表示是mybatis中的Mapper接口,在程序运行时,框架会自动生成接口的实现类对象(代理对象),并交给Spring的IOC容器管理

@Select注解:代表的就是select查询,用于书写select查询语句

2.2.3 单元测试

在创建出来的SpringBoot工程中,在src下的test目录下,我们创建测试类UserMapperTest,并且在测试类上已经添加了注解@SpringBootTest,代表该测试类已经与SpringBoot整合。

该测试类在运行时,会自动通过引导类加载Spring的环境(IOC容器(控制反转,对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转))。我们要测试上面的bean对象,就可以直接通过@Autowired注解直接将其注入进行,然后就可以测试了。

java 复制代码
import com.itheima.entity.User;
import com.itheima.mappeer.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

@SpringBootTest //作用:会加载Spring环境(IOC容器)
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testList() {
        List<User> list = userMapper.list();
        for (User user : list) {
            System.out.println(user);
        }
    }
}

运行结果:

md-end-block 复制代码
<span style="background-color:#f8f8f8">User(id=1, username=daqiao, password=1234567890, name=大乔, age=22)
User(id=2, username=xiaoqiao, password=123456, name=小乔, age=18)
User(id=3, username=diaochan, password=123456, name=貂蝉, age=24)
User(id=4, username=lvbu, password=123456, name=吕布, age=28)
User(id=5, username=zhaoyun, password=12345678, name=赵云, age=27)</span>

注意:测试类所在包,需要与引导类所在包相同。

如果测试类UserMapperTest类不在com.itheima这个包下,而是被移动到了com.itbaima,此时我们需要在UserMapperTest类里加上(class = SpringbootMybatisQuickstartApplication.class)

java 复制代码
@SpringBootTest(classes = SpringbootMybatisQuickstartApplication.class) 
//作用:会加载Spring环境(IOC容器)
//@SpringBootTest //作用:会加载Spring环境(IOC容器)
//注意:测试类所在包必须与启动类所在包或子包一致
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testList() {
        List<User> list = userMapper.list();
        for (User user : list) {
            System.out.println(user);
        }
    }
}

2.3 辅助配置

2.3.1 配置SQL提示

默认我们在UserMapper接口上的 @Select 注解中编写SQL语句是没有提示的。如果想让idea给出提示,可以做如下配置:

配置完成之后,发现SQL语句中的关键字有提示了,但还存在不识别表名(列名)的情况:

产生原因:Idea和数据库没有建立连接,不识别表信息

解决方案:在Idea中配置MySQL数据库连接

注意:该配置的目的,仅仅是为了在编写SQL语句时,有语法提示(写错了会报错),不会影响运行,即使不配置也是可以的。

2.3.2 配置Mybatis的日志输出

默认情况下,在Mybatis中,SQL语句执行时,我们并看不到SQL语句的执行日志。 加入如下配置,即可查看日志:

打开上述开关之后,再次运行单元测试,就可以看到控制台输出的SQL语句是什么样子的。

2.4 JDBC VS Mybatis

JDBC程序的缺点:

  • url、username、password 等相关参数全部硬编码在java代码中。

  • 查询结果的解析、封装比较繁琐。

  • 每一次操作数据库之前,先获取连接,操作完毕之后,关闭连接。 频繁的获取连接、释放连接造成资源浪费。

分析了JDBC的缺点之后,我们再来看一下在mybatis中,是如何解决这些问题的:

  1. 数据库连接四要素(驱动、链接、用户名、密码),都配置在springboot默认的配置文件 application.properties中

  2. 查询结果的解析及封装,由mybatis自动完成映射封装,我们无需关注

  3. 在mybatis中使用了数据库连接池技术,从而避免了频繁的创建连接、销毁连接而带来的资源浪费。

使用SpringBoot+Mybatis的方式操作数据库,能够提升开发效率、降低资源浪费

而对于Mybatis来说,我们在开发持久层程序操作数据库时,需要重点关注以下两个方面:

1.application.properties

java 复制代码
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/web01
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=1234

2.Mapper接口(编写SQL语句)

java 复制代码
@Mapper
public interface UserMapper {
    @Select("select * from user")
    public List<User> list();
}

2.5 数据库连接池

前面我们说过mybatis中,使用了数据库连接池技术,避免频繁的创建连接、销毁连接而带来的资源浪费

2.5.1 介绍数据库连接池

没有使用数据库连接池:

  • 客户端执行SQL语句:要先创建一个新的连接对象,然后执行SQL语句,SQL语句执行后有需要关闭连接对象来从而释放资源,每次执行SQL时都需要创建连接、销毁连接,这种频繁的重复创建和销毁的过程是比较耗费计算机的性能的。

使用数据库连接池,数据库连接池是一个容器,负责分配,管理数据库连接(Connection)

  • 程序在启动时,会在数据库连接池(容器)中创建一定数量的Connection对象允许应用程序重复使用一个现有的数据库连接,而不是重新创建一个
  • 客户端在执行SQL时,先从连接池中获取一个Connection对象,然后在执行SQL语句,SQL语句执行完之后,释放Connection时就会把Connection对象归还给连接池(Connection对象可以重复使用)

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

最大空闲时间核心作用是:规定一个连接在连接池中保持空闲状态的最长时间。当某个连接的空闲时间超过这个阈值时,连接池会自动将其关闭并从池中移除,释放相关资源。

  • 客户端获取到Connection对象了,但是Connection对象并没有去访问数据库(处于空闲),数据库连接池发现Connection对象的空闲时间 > 连接池中预设的最大空闲时间,此时数据库连接池就会自动释放掉这个连接对象

数据库连接池的好处:

  1. 资源重用

  2. 提升系统响应速度

  3. 避免数据库连接遗漏

2.5.2 如何实现数据库连接?

  • 官方(sun)提供了数据库连接池标准(javax.sql.DataSource接口)

功能:获取连接

java 复制代码
public Connection getConnection() throw SQLException;

常见的数据库连接池:C3P0、DBCP、Druid、Hikari(springboot默认)

现在更多使用的是Druid和Hikari(性能更加优越)

1). Hikari(追光者) [默认的连接池]

2). Druid(德鲁伊)

  • Druid连接池是阿里巴巴开源的数据库连接池项目

  • 功能强大,性能优秀,是Java语言最好的数据库连接池之一

如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要完成一下两步操作即可:

1.在pom.xml文件中引入依赖

XML 复制代码
<dependency>
    <!-- Druid连接池依赖 -->
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.19</version>
</dependency>

2.在application.properties中引入数据库连接配置

XML 复制代码
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
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=1234

2.6 Mybatis的XML配置文件

Mybatis的开发有两种方式:

1.注解

2.XML

2.6.1 XML配置文件规范

使用Mybatis的注解方式主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中。

在Mybatis中使用XML映射文件方式开发,需要符合一定的规范:

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

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

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

注意:

  • 在resources下创建文件夹要用 / 来分级创建,用点并没有分级效果。
  • 名称一致指的是全限定名一致,含包名和类名的全称
  • resultType如果有返回值就要用实体类的全称(指的是查询返回的单条记录所封装的类型,如User类),如果无返回值就不需要写

2.6.3 MybatisX的使用

可以通过MybatisX快速定位

3.部门列表查询

3.1 功能实现

3.1.1 需求

查询数据库表中的所有部门数据,展示在页面上

3.1.2 实现

1.准备数据库表dept及实体类Dept

sql 复制代码
-- 部门管理
create table dept(
    id int unsigned primary key auto_increment comment '主键ID',
    name varchar(10) not null unique comment '部门名称',
    create_time datetime  comment '创建时间',
    update_time datetime  comment '修改时间'
) comment '部门表';

INSERT INTO `dept` VALUES (1,'学工部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
						(2,'教研部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
						(3,'咨询部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
						(4,'就业部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
						(5,'人事部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
						(6,'行政部','2023-09-27 14:00:00','2023-09-27 14:00:00'),
						(7,'综合部','2023-09-25 14:44:19','2023-09-25 14:44:19');
java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
    private Integer id;
    private String name;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

2.在项目中引入Mybatis的起步依赖,mysql的驱动包

XML 复制代码
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

3.在项目的application.properties 中引入Mybatis的配置信息 (数据库连接、日志输出)

XML 复制代码
#数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/web01
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root@1234

#mybatis 日志
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

4.定义mapper包,并且定义DeptMapper接口,并声明接口方法。

java 复制代码
import com.itheima.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;

@Mapper
public interface DeptMapper {

    @Select("select * from dept")
    public List<Dept> list();

}

5.改造之前编写的dao、service的代码,在service实现中注入mapper接口

  • dao层的代码不需要了(备份之后,可以删除)

  • service层的代码,需要注入Mapper接口,调用mapper接口方法查询数据库中的数据

java 复制代码
package com.itheima.service.impl;

import com.itheima.entity.Dept;
import com.itheima.mapper.DeptMapper;
import com.itheima.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 业务逻辑处理层
 */

@Service
public class DeptServiceImpl implements DeptService {

    @Autowired //从IOC容器中,自动寻找bean对象,为该变量赋值--依赖注入DI的实现
    private DeptMapper deptMapper;
    public List<Dept> list(){
        //1.调用mapper的方法,获取列表数据并返回
        return deptMapper.list();

    }
}

6.启动服务,打开apifox进行测试

经过测试,我们发现,创建时间 createTime,修改时间 updateTime 属性并未成功封装。 接下来,我们就需要来处理数据封装问题。

3.2 数据封装

我们看到查询返回的结果中大部分字段是有值的,但是createTime,updateTime这两个字段是没有值的,而数据库中是有对应的字段值的,这是为什么呢?

原因:

  • 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
  • 如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。

解决方案:

  1. 起别名

  2. 结果映射

  3. 开启驼峰命名

java 复制代码
package com.itheima.mapper;

import com.itheima.entity.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface DeptMapper {
    /**
     * 查询所有部门信息
     *
     * @return
     */

    //数据封装方式一:手动结果映射
//    @Results({
//            @Result(column = "create_time", property = "createtime"),
//            @Result(column = "update_time", property = "updatetime")
//    })

    //数据封装方式二:起别名
    //@Select("select id, name, create_time createTime, update_time updateTime from dept")

    //数据封装方式三:全局配置,开启驼峰命名规则映射
    @Select("select * from dept")
    public List<Dept> list();
}

3.开启驼峰命名(推荐):如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射

驼峰命名规则: abc_xyz => abcXyz

  • 表中字段名:abc_xyz

  • 类中属性名:abcXyz

java 复制代码
# 在application.properties中添加:
mybatis.configuration.map-underscore-to-camel-case=true

要使用驼峰命名前提是 实体类的属性 与 数据库表中的字段名严格遵守驼峰命名。