学JavaWeb第六天——JDBC & Mybatis

一、JDBC

1.1 JDBC入门程序------执行DML语句

  1. class.forName(XX类):就是将指定类加载到内存当中。------告诉jvm,我们使用的是哪一个数据库的驱动
  2. 执行SQL语句后返回的整数是数据库中影响的记录数。
  3. DML的insert、update、delete都是用executeUpdate来完成的。

代码示例:

1)先准备一个Maven项目,并引入依赖。

依赖:

html 复制代码
<dependencies>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>
 
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.9.3</version>
        <scope>test</scope>
    </dependency>
 
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.30</version>
    </dependency>
</dependencies>

2)准备一个数据库web01

3)编写JDBC程序,操作数据库。

java 复制代码
package com.itheima;

import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;


public class JdbcTest {

    @Test
    public void DMLtest() throws ClassNotFoundException, SQLException {

        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2.
        String url="jdbc:mysql://localhost:3306/web01";
        String username="root";
        String password="1234";
        Connection connection = DriverManager.getConnection(url, username, password);

        //3.
        Statement statement = connection.createStatement();

        //4
        int i = statement.executeUpdate("update user set age=25 where id=1");

        //5.
        statement.close();
        connection.close();

    }
}

输出结果:在数据库中的年龄被修改为25.

1.2 JDBC执行DQL语句

代码示例:

提示词:

sql 复制代码
你是一名java开发工程师,帮我基于JDBC程序来操作数据库,执行如下SQL语句:select id,username,password,name,age from user  where username = 'daqiao' and password = '123456';
并将查询的每一行记录,都封装到实体类User中,然后将User对象的数据输出到控制台中。
User 实体类属性如下:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id; //ID
    private String username; //用户名
    private String password; //密码
    private String name; //姓名
    private Integer age; //年龄
}

用ai写的,采用了预编译SQL

java 复制代码
 @Test
    public void JdbcTest2() {
            // 1. 数据库配置信息 (请根据实际情况修改数据库名、账号和密码)
            String url = "jdbc:mysql://localhost:3306/web01";
            String dbUser = "root";
            String dbPassword = "1234";

            // 2. 定义SQL语句 (使用 ? 作为占位符,这是最佳实践)
            String sql = "select id, username, password, name, age from user where username = ? and password = ?";

            // 用于存储封装后的User对象列表
            List<User> userList = new ArrayList<>();

            // 3. 使用 try-with-resources 自动关闭资源 (Connection, Statement, ResultSet)
            try (Connection conn = DriverManager.getConnection(url, dbUser, dbPassword);
                 PreparedStatement pstmt = conn.prepareStatement(sql)) {

                // 4. 设置参数,对应 SQL 中的 ?
                pstmt.setString(1, "daqiao");
                pstmt.setString(2, "123456");

                // 5. 执行查询
                try (ResultSet rs = pstmt.executeQuery()) {
                    // 6. 遍历结果集
                    while (rs.next()) {
                        // 创建 User 对象
                        User user = new User();

                        // 7. 将结果集中的列封装到对象属性中
                        user.setId(rs.getInt("id"));
                        user.setUsername(rs.getString("username"));
                        user.setPassword(rs.getString("password"));
                        user.setName(rs.getString("name"));
                        user.setAge(rs.getInt("age"));

                        // 添加到列表
                        userList.add(user);
                    }
                }

            } catch (SQLException e) {
                e.printStackTrace();
            }

            // 8. 将 User 对象的数据输出到控制台
            System.out.println("查询结果如下:");
            for (User user : userList) {
                // 这里的 toString() 方法由 Lombok 的 @Data 注解自动生成
                System.out.println(user);
            }
        }

输出结果:

1.3 预编译SQL

为什么静态SQL会出现SQL注入攻击?

一个登录页面,本来只有输入正确的用户名和密码才能成功登录,现在只需输入如下,就能成功。

**这就是SQL注入攻击,因为这样的静态SQL从前端拿来的username和password都会被直接拼接到SQL语句上,如果password的输入不正规,造成如下****其他 or '1'='1'**的恒等式,那就无论输入的username和password是什么,都会成功登录。

而预编译SQL就不会由SQL注入危机。

因为 预编译SQL 会把username 和 password 后面的两个 问好?当成整体,不会散开,所以就构不成****其他 or '1'='1' 的局面。password只是password。

预编译SQL 两大优势:

Why?性能更高???????

  1. MySQL接收到Java的 SQL语句之后,会先执行前三个,并把编译的SQL语句放到缓存中,当之后再接收到相同的SQL语句之后,就不用执行前三步了,直接在缓存中找相同语句,执行SQL。
  2. 预编译有?,SQL语句一样,只需换掉?的内容就行。性能更高。
  3. 而静态SQL是每次username和password都不一样,所以SQL语句也不一样,所以每次都要执行前三步,性能低。

有一个可以运行的jar包,如何运行?

--------在该jar包的文件路径下输入cmd,之后命令行输入 java -jar jar包的名字,回车,jar包运行。此时命令行就相当于控制台,会显示运行jar包的输出信息,比如日志信息等。

下图就是控制台输出的日志信息:

二、 MyBatis

2.1 什么是MyBatis

------底层是JDBC,封装了JDBC,使用起来更加简洁。

2.2 MyBatis 入门程序

代码示例:

1)创建springboot模块,并引入mybatis相关依赖

不用引入web的相关依赖,因为这次不涉及前端,主要目标是在java开发工具中使用数据库

2)准备数据库表user和实体类User

3)配置Mybatis,在applications.properties中写mybatis的连接数据库的url、root、密码、驱动包的信息。

4)编写Mybatis程序,编写持久层接口,写SQL语句。(重点)

根据findall的返回值类型:mybatis会把findall方法查询的每一条数据都封装在User对象中,所以数据库的每个字段名要和User类的各个变量名一致。多个User对象会自动存储在List这个集合当中

接口上面的**@Mapper****注解是mybatis给的,功能:应用程序在运行时,会自动地为该接口创建一个实现类对象(代理对象),并且会自动将该实现类对象存入IOC容器中,变成bean对象。**

此时,主程序main代码就写完了,真正的执行放在了测试test部分,就像以前写的测试类。

test需要在IOC容器中捞出UserMapper的对象,并执行它的方法。所有的IOC容器中的bean对象都是在需要的时候用DI注解@Autowired将相应类型的类对象捞出,得到类的对象,并执行对象的方法。

5)编写测试类、测试方法

测试类上面的注解 @SpringBootTest 是使用springboot框架的单元测试注解,当测试类中的测试方法运行时,会启动springboot项目,同时,IOC也随之启动。

**解释:**因为之前学Java时测试方法都是创建main主程序中的类的对象,进而调用它们的方法,所以不用启动项目,但是现在不创建对象了,而是利用IOC容器,只有项目启动,IOC才会启动,所以springboot的测试类运行时,就会启动整个springboot项目。

输出成果:

springboot的标志:IOC容器、DI注解,@springbootTest

2.3 辅助配置

2.4 JDBC &MyBatis 对比

2.5 数据库连接池

springboot默认用Hikari追光者。我们现在跑的连接数据库,执行SQL语句的代码都是用的Hikari连接池。

我们现在改用Druid连接池,该如何做?

输出结果:

所有的 数据库连接池 都是实现DataSource这个接口的实现类,我们不用编写这些实现类,第三方组织已经为我们写好了,直接用就可以,比如Hikari、Druid等。

2.6 基于MyBatis的增删改查操作

2.6.1 删除操作

#{id}在执行的时候会被替换为?,变为占位符,所以是预编译SQL和参数共同传递给数据库,数据库执行SQL语句,如图所示。

Delete也可以有返回值,是执行SQL语句后。数据库被影响的记录个数:如下所示:

#{ }和${ }的区别

现在都用#{ },因为是预编译SQL,更安全,如果用 ${ }就是拼接字符串,不安全,如图所示:

2.6.2 添加操作

2.6.3 修改操作

当要传递的sql语句的#{ }参数有很多时,就要把参数封装到一个对象中,方法传递的参数是对象,sql语句会自动解析 对象的属性值。

当传递的参数不多,只有两三个时,就不用传递对象了,直接传递这两三个参数即可。

2.6.4 查询操作

但是,这些形参在编译后的字节码文件中是没有形参名称的,只有类型,所以SQL语句就找不到对应参数名称的参数值,就引入了@Param注解。

我们现在写的项目就是基于springboot框架,所以不用加@param注解。为什么呢?

因为基于springboot框架都有一个父工程parent-------插件maven-compile-------parameter是true,就说明在编译后会保留参数名称,这样就不用写注解@Param了。

如下图是没有用springboot骨架时的形参,此时就没有保留参数名称,所以运行会报错。

而如下图是使用了@Param注解之后,字节码文件会保留参数名称,运行就不会报错。

2.6.5 代码

UserMapper接口:

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

import com.itheima.POJO.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface UserMapper {

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

    //删除 某个id 的用户
    @Delete("delete from user where id = #{id}")
    public void deleteByID(Integer id);

    //添加用户
    @Insert("insert into user(username,password,name,age) values (#{username},#{password},#{name},#{age})")
    public void InsertUser(User user);

    //修改用户
    @Update("update user set username=#{username},password=#{password},name=#{name},age=#{age} where id=#{id}")
    public void updateuser(User user);

    //查询用户
    @Select("select * from user where username=#{username} and password=#{password}")
    public User selectByusernameANDpassword( String username, String password);
}

接口上面的**@Mapper****注解是mybatis给的,功能:应用程序在运行时,会自动地为该接口创建一个实现类对象(代理对象),并且会自动将该实现类对象存入IOC容器中,变成bean对象。**

复制代码
SpringbootMybatisQuickstar02ApplicationTests类:
java 复制代码
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
class SpringbootMybatisQuickstar02ApplicationTests {

    @Autowired
    private UserMapper userMapper;  //找到容器里相应的对象并赋值给userMapper

    //测试查询用户
    @Test
    public void testFindAll(){
        List<User> users = userMapper.findAll();
        users.forEach(user-> System.out.println(user));
    }


    //测试删除用户
    @Test
    public void testDeleByID(){
        userMapper.deleteByID(2);
    }


    //测试添加用户
    @Test
    public void testInsert(){
        User user=new User(null,"gaoyuanyuan","12345689","高圆圆",25);
        userMapper.InsertUser(user);
    }

    //测试修改用户
    @Test
    public void testUpdate(){
        User user=new User(7,"suwuming","12345000","苏无名",29);
        userMapper.updateuser(user);
    }

    //测试查询用户
    @Test
    public void testSelect(){
        User user = userMapper.selectByusernameANDpassword("suwuming", "12345000");
        System.out.println(user);
    }
}

2.7 XML映射配置

现在都用注解@select、@insert等来写SQL语句,以前不用注解,而用XML配置文件。2.7 就来介绍如何用XM配置文件来写SQL语句。

这三步一个都不能少,因为通过这三个才能找到对应XML映射文件的SQL语句。

简单SQL语句用注解,复杂的增删改查用XML映射文件。

代码:

UserMapper.xml文件:

java 复制代码
<?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.itheima.Mapper.UserMapper">
    <select id="findAll" resultType="com.itheima.POJO.User">
        select username,password,name,age,id from user
    </select>
</mapper>

此时就i可以把原来@select的注解删掉了。

运行依然是成功的。

2.7.1 辅助配置

如果不同包的话也想成功运行,就要进行以下辅助配置:

代码:

另一个辅助配置:下载MybatisX插件

实现UserMapper接口方法与对应XML文件的SQL语句的直接跳转。很方便。。。。

**本节主要讲的是:**如何通过java语言来完成对MySQL数据库中数据的增删改查。通过JDBC,现在都改为使用Mybatis了。上一节完成的项目是在持久层(数据访问层)通过读取文件的方式来获取数据,这次通过MyBatis来获取MySQL数据库中的数据。

相关推荐
青岛少儿编程-王老师2 小时前
CCF编程能力等级认证GESP—C++8级—20251227
java·开发语言·c++
Damon小智2 小时前
NiFi实现数据存储到数据库
数据库·mysql·docker·postgresql·nifi
计算机毕设指导62 小时前
基于微信小程序的个性化漫画阅读推荐系统【源码文末联系】
java·python·微信小程序·小程序·tomcat·maven·intellij-idea
Love Song残响2 小时前
高效自动化清理临时文件方案
java·开发语言·spring
技术小泽2 小时前
java转go语言入门基础篇(二)
java·golang
资深web全栈开发2 小时前
Zanzibar vs MySQL Permission System - 实证性能对比研究
数据库·mysql·权限设计·zanzibar
我不会写代码njdjnssj2 小时前
基于SpringBoot+SSM的外卖平台Day1-6
java·spring boot·后端
崎岖Qiu2 小时前
【设计模式笔记26】:深入浅出「观察者模式」
java·笔记·观察者模式·设计模式