黑马程序员——mysql——day04——JDBC&数据库连接池

目录:

  1. 第一章JDBC
    1. JDBC的概念
      1. 目标
      2. 讲解
        1. JDBC的由来
        2. JDBC的好处
      3. 小结
    2. JDBC核心API的介绍
      1. 目标
      2. 讲解
        1. JDBC会用到的包
        2. JDBC四个核心对象
        3. JDBC访问数据库的步骤
      3. 小结
    3. JDBC注册驱动
      1. 目标
      2. 讲解
        1. 准备工作
        2. 导入驱动Jar包
        3. 注册驱动
      3. 小结
    4. 获取连接
      1. 讲解
        1. API介绍
        2. 参数说明
        3. 注意事项
        4. 使用步骤
        5. 案例代码
        6. 案例效果
      2. 小结
    5. JDBC实现对单表数据增、删、改
      1. 目标
      2. 讲解
        1. JDBC实现对单表数据增、删、改
        2. API介绍
        3. 使用步骤
        4. 案例代码
    6. JDBC实现对单表数据查询
      1. 目标
      2. 讲解
        1. ResultSet的原理
        2. ResultSet获取数据的API
        3. 使用JDBC查询数据库中的数据的步骤
        4. 案例代码
      3. 小结
    7. 根据别名查询处理结果集扩展
    8. JDBC实现登录案例
      1. 目标
      2. 讲解
        1. 案例分析
        2. 实现步骤
      3. 小结
    9. PreparedSatement预编译对象
      1. 目标
      2. 讲解
        1. SQL注入问题
        2. sql注入原因演示_模拟登陆:
      3. 小结
        1. 问题根本原因:
        2. 问题的解决方案:
    10. PreparedStatement解决SQL注入方案
      1. 目标
      2. 讲解
      3. 小结:
    11. PreparedStatement的应用(掌握)
      1. 目标
      2. 讲解
    12. 执行DQL封装成集合的操作
    13. JDBC事务
      1. 目标
      2. 讲解
        1. 准备数据
        2. JDBC操作事务
        3. API介绍
        4. 使用步骤
        5. 案例代码
      3. 小结
    14. 三层开发业务的案例分析(掌握)
  2. 第二章连接池
    1. 连接池介绍
      1. 目标
      2. 讲解
        1. 没有连接池的现状
        2. 连接池解决现状问题的原理
        3. 连接池好处
        4. 常用连接池的介绍
      3. 小结
    2. Druid连接池
      1. 目标
      2. 讲解
        1. DRUID简介
        2. Druid常用的配置参数
        3. Druid连接池基本使用
        4. 使用步骤
        5. 案例代码
        6. 案例效果
  3. 第三章JDBC练习
    1. 需求
    2. 环境搭建
    3. 查询所有数据
    4. 添加
    5. 修改
    6. 删除

第一章 JDBC

1.JDBC的概念
目标
  1. 能够掌握JDBC的概念

  2. 能够理解JDBC的作用

讲解

客户端操作MySQL数据库的方式

  1. 使用第三方客户端来访问MySQL:SQLyog、Navicat

  2. 使用MySQL自带的命令行方式

  3. 通过Java来访问MySQL数据库,今天要学习的内容

    如何通过Java代码去操作数据库呢?

    Java中给我们提供专门的一套技术,可以通过其中的某些类和接口操作任何的数据库,这个技术就是今天要学习的JDBC。

    什么是JDBC:Sun公司为了简化、统一对数据库的操作,定义了一套java操作数据库的接口的规范,称之为JDBC。JDBC的全称为:java database connection (java和 数据库的连接 ) 就是使用java代码来操作数据库。 JDBC的作用:Java通过JDBC就可以操作数据库

JDBC的由来

java程序依赖于jdk,jdk和数据库是2个不同的应用程序,那他们是怎么进行访问的呢?

要想搞清楚这个问题,我们必须了解下电脑是如何和其他硬件设备交互的。假设我们电脑安装完系统之后是一个无驱动的操作系统。那么当我们电脑想播放声音,即安装音响,必须得安装声卡驱动。同时电脑想和u盘硬件进行交互,也必须在电脑上安装对应的驱动。如果驱动安装失败,很显然他们是不能正常的交互的。这个安装驱动的其实就是为了定义他们两个相互交互的规则。只有统一了规则,才能交互。

具体的解释如下图所示:

同理:java程序想和数据库进行交互,也必须得安装数据库驱动,这样才能交互。但是,我们数据库有多种,这样就会导致不同的数据库具备不同的数据库驱动。

从而会导致在开发中作为程序员由于安装不同的数据库驱动而浪费很多时间,同时和数据库交互的java代码也得重新书写,这样都会导致效率很低。所以说,sun公司就会制定一套规则,这套规则就是用来java程序连接数据库的,然后各大数据库厂商只需要实现这个规则即可。这个规则就是jdbc技术,即接口。

换句话就是说,就是数据库厂商使用sun公司提供的接口,然后作为java程序员实现接口中的方法即可。接口中的方法体由具体的数据库厂商来实现。

JDBC的好处
  1. 我们只需要会调用JDBC接口中的方法即可,使用简单

  2. JDBC有关的类和接口:都在java.sql 和 javax.sql(扩展包) 包下

  3. 方法体由具体的数据库厂商来完成的

  4. 使用同一套Java代码,进行少量的修改就可以访问其他JDBC支持的数据库

小结
  1. 说出JDBC的概念?Java数据库连接(Java操作数据库的标准规范)

  2. 说出JDBC的作用?Java通过JDBC就可以操作数据库

2、JDBC核心API的介绍
目标

能够理解JDBC四个核心对象

讲解
JDBC会用到的包
  1. java.sql:JDBC访问数据库的基础包,在JavaSE中的包。如:java.sql.Connection

  2. javax.sql: JDBC访问数据库的扩展包

  3. 数据库的驱动,各大数据库厂商来实现。如:MySQL的驱动:com.mysql.jdbc.Driver

JDBC四个核心对象

这几个类都是在java.sql包中

  1. DriverManager(类): 数据库驱动管理类。这个类的作用:1)注册驱动; 2)创建java代码和数据库之间的连接,即获取Connection接口;

  2. Connection(接口): 是一个接口, 建立数据库连接的一个接口。作用:建立数据库和java代码之间的连接。表示与数据库创建的连接

  3. Statement(接口)、PreparedStatement(接口) (解决安全隐患问题,比如sql注入的问题): 数据库操作,向数据库发送sql语句。执行SQL语句的对象

  4. ResultSet: 结果集或一张虚拟表。 Statement 发送sql语句,得到的结果 封装在 ResultSet 中。

JDBC访问数据库的步骤
  1. 由DriverManager注册驱动程序

  2. 创建和数据库的连接对象Connection

  3. 由客户端发送SQL语句给服务器执行,SQL语句封装成Statement对象

  4. 查询到的结果集封装成ResultSet对象

  5. 在客户端可以从ResultSet中取出数据,处理结果集

  6. 释放资源,关闭连接对象

小结

JDBC四个核心对象?

  1. DriverManager(类): 用于注册驱动和获取连接

  2. Connection(接口): 表示与数据库创建的连接

  3. Statement(接口): 执行SQL语句的对象

  4. ResultSet(接口): 结果集或一张虚拟表

3、JDBC注册驱动

Connection表示Java程序与数据库之间的连接,只有拿到Connection才能操作数据库。

JDBC获取连接步骤

1.导入mysql驱动Jar包 2.注册驱动 3.获取连接

目标

能够导入mysql驱动Jar包

能够通过JDBC注册数据库驱动

讲解
准备工作

1、确定启动mysql数据库。

此电脑-------》右键管理-------》选择服务

找到MySQL服务,查看MySQL服务是否已经启动了,如果启动是灰色,说明已经启动了。

2、创建数据库和创建user表,并添加信息,sql语句如下。

打开可视化工具,将如下sql语句添加到可视化工具中,并执行以下sql语句即可。

-- 创建数据库
create database day04_db;

-- 切换数据库
use day04_db;

-- 用户表
create table user (
  id int primary key auto_increment,
  username varchar(30) unique not null,
  password varchar(30)
);

insert into user(username, password) values('zhangsan','123');
insert into user(username, password) values('lisi','123');
insert into user(username, password) values('wangwu','123');

select * from user;

 执行结果:

导入驱动Jar包

1、新建项目day04,在项目day04上新建lib文件夹

 

2、将mysql驱动的jar包导入到lib文件夹下

3、在导入的mysql的jar包上右键,选择Add as Library...

注册驱动

我们Java程序需要通过数据库驱动才能连接到数据库,因此需要注册驱动。 MySQL的驱动的入口类是:com.mysql.jdbc.Driver

API介绍

java.sql.DriverManager类用于注册驱动。提供如下方法注册驱动

static void registerDriver(Driver driver) 
向 DriverManager 注册给定驱动程序。 

说明:

1.执行完上述语句之后,DriverManager就可以管理mysql驱动了。

2.当前的DriverManager.registerDriver(Driver driver);方法的参数是Driver,这是jdbc的一个接口,所以我们需要给定实现该接口的实现类。如果我们连接的是mysql数据库,那么需要导入mysql数据库提供的包,也就是com.mysql.jdbc.Driver; 下的Driver类。如果我们连接的是oracle数据库,那么需要导入oracle数据库提供的包。

使用步骤

1.DriverManager.registerDriver(驱动对象); 传入对应参数即可

案例代码

public class Demo01 {
	public static void main(String[] args) throws Exception {
		// 注册驱动
		DriverManager.registerDriver(new com.mysql.jdbc.Driver());
	}
}

 说明:这里的new Driver()的类Driver就是来自mysql数据库。

通过查询com.mysql.jdbc.Driver源码,我们发现Driver类“主动”将自己进行注册

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    static {
        try {
            // 自己自动注册
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
    public Driver() throws SQLException {
    }
}

注意:使用DriverManager.registerDriver(new com.mysql.jdbc.Driver());,存在以下方面不足

  • 驱动被注册两次

使用Class.forName("com.mysql.jdbc.Driver");加载驱动,这样驱动只会注册一次

public class Demo01 {
	public static void main(String[] args) throws Exception {
	/*
            1)注册驱动使用的类是驱动管理类:DriverManager,使用该类中的静态方法:
              static void registerDriver(Driver driver) 向 DriverManager 注册给定驱动程序。
                真正注册驱动代码:  DriverManager.registerDriver(new Driver());
            2) static void registerDriver(Driver driver) 方法参数Driver是驱动接口,java.sql.Driver表示每个驱动程序类必须实现的接口。
                    对于该参数我们都是创建该接口java.sql.Driver实现类对象,实现类由各大数据库厂商来提供,并且必须实现该驱动接口java.sql.Driver
            3) 真正注册驱动代码:  DriverManager.registerDriver(new Driver());
                    注意:这里new Driver()创建的是mysql厂商定义的实现类
                    //com.mysql.jdbc.Driver  属于mysql厂商的实现类
                    //java.sql.Driver  属于sun公司定义的驱动接口
                    public class com.mysql.jdbc.Driver implements java.sql.Driver {
                        public Driver() throws SQLException {
                        }

                        static {
                            try {
                                DriverManager.registerDriver(new Driver());
                            } catch (SQLException var1) {
                                throw new RuntimeException("Can't register driver!");
                            }
                        }
                }
            4)为什么我们不使用代码: DriverManager.registerDriver(new Driver()); 注册呢,我们为什么这里使用代码:
                  Class.forName("com.mysql.jdbc.Driver");的原因?

                原因:因为DriverManager.registerDriver(new Driver());注册了两次,而Class.forName("com.mysql.jdbc.Driver");只是注册了一次

                 Class.forName("com.mysql.jdbc.Driver"); 就是将com.mysql.jdbc.Driver类加载到内存中,加载该类,就会执行该类的静态代码块:

                    public class com.mysql.jdbc.Driver implements java.sql.Driver {
                        //静态代码块,当前类一加载内存就执行
                        static {
                            try {
                                //注册驱动的真正代码
                                DriverManager.registerDriver(new Driver());
                            } catch (SQLException var1) {
                                throw new RuntimeException("Can't register driver!");
                            }
                        }
                }

                总结: Class.forName("com.mysql.jdbc.Driver");注册一次驱动原因,类com.mysql.jdbc.Driver加载内存中执行静态代码块
                然后注册驱动了


             5)为什么 我们自己书写该代码DriverManager.registerDriver(new Driver()); 注册两次?
                因为首先在执行代码:new com.mysql.jdbc.Driver() ,先将类com.mysql.jdbc.Driver加载到内存中执行静态代码块,注册一次驱动,然后
                这里又注册一次

              6)从jdbc4开始,我们第一步注册驱动不用我们程序员书写了,,底层在使用到com.mysql.jdbc.Driver类就注册了


         */
		Class.forName("com.mysql.jdbc.Driver"); // 后期可以将"com.mysql.jdbc.Driver"字符串写在文件中.
	}
}

演示:Class.forName("包名.类名");会走这个类的静态代码块  

通常开发我们使用Class.forName() 加载驱动。Class.forName("com.mysql.jdbc.Driver");会走Driver类的静态代码块。在静态代码块中注册一次驱动。

总结:注册MySQL驱动使用Class.forName("com.mysql.jdbc.Driver");

小结

1.导入mysql驱动Jar包

2.通过JDBC注册数据库驱动?

Class.forName("com.mysql.jdbc.Driver");

 3.从jdk4.0开始,对于我们java开发工程师,第一步不用书写了,底层帮助我们使用com.mysql.jdbc.Driver类先注册驱动了.驱动必须注册,只是不用我们书写代码注册了。

4、获取连接

能够通过JDBC获取数据库连接

讲解
API介绍

java.sql.DriverManager类中有如下方法获取数据库连接

static Connection getConnection(String url, String user, String password) 
连接到给定数据库 URL ,并返回连接。 
参数说明
  1. String url:连接数据库的URL,用于说明连接数据库的位置

  2. String user:数据库的账号

  3. String password:数据库的密码

连接数据库的URL地址格式:协议名:子协议://服务器名或IP地址:端口号/数据库名?参数=参数值

MySQL写法:jdbc:mysql://localhost:3306/day04_db 如果是本地服务器,端口号是默认的3306,则可以简写:jdbc:mysql:///day04_db

注意事项
  • 如果数据出现乱码需要加上参数: ?useUnicode=true&characterEncoding=utf8,表示让数据库以UTF8编码来处理数据。 如: jdbc:mysql://localhost:3306/day04_db?useUnicode=true&characterEncoding=utf8
使用步骤

1.DriverManager.getConnection(url, user, password); 传入对应参数即可

案例代码
public class Demo01 {
	public static void main(String[] args) throws Exception {
		Class.forName("com.mysql.jdbc.Driver");
         /*
            1)使用DriverManager类中的静态方法获取和数据库的连接:
                static Connection getConnection(String url, String user, String password)
                    参数:
                        url:表示建立和数据库服务器连接的地址,书写格式几乎是固定的。
                            jdbc:mysql://连接mysql服务器的ip地址:mysql服务器的端口号/连接的数据库名
                            补充:如果连接的数据库软件在本地,那么url可以简写为:jdbc:mysql:///连接的数据库名
                        user:连接mysql服务器的用户名,这里暂时书写root
                        password:接mysql服务器的密码
                    返回值:Connection,属于java.sql 包下的一个接口,表示连接接口,和数据库的连接。

         */
		// 连接到MySQL
		// url: 连接数据库的URL
		// user: 数据库的账号
		// password: 数据库的密码
		Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day04_db", "root", "1234");
		System.out.println(conn);
	}
}
案例效果

1.连接成功

2.连接失败

小结

JDBC获取数据库连接使用哪个API?

DriverManager.getConnection(数据库url, 账号, 密码)

 通过JDBC连接mysql的URL写法?

jdbc:mysql://服务器ip地址:3306/数据库

如果连接mysql服务器在本地,那么url可以简写:  

jdbc:mysql:///数据库
5、JDBC实现对单表数据增、删、改
目标

通过JDBC实现对单表数据增、删、改、查

讲解
JDBC实现对单表数据增、删、改

我们要对数据库进行增、删、改、查,需要使用Statement对象来执行SQL语句。

API介绍

获取Statement对象

java.sql.Connection接口中有如下方法获取到Statement对象

Statement createStatement() 
创建一个 Statement 对象来将 SQL 语句发送到数据库

Statement的API介绍

int executeUpdate(String sql)
根据执行的DML(INSERT、UPDATE、DELETE)语句,返回受影响的行数
ResultSet executeQuery(String sql)
根据查询语句返回结果集,只能执行SELECT语句

注意:在MySQL中,只要不是查询就是修改。 executeUpdate:用于执行增删改 executeQuery:用于执行查询

使用步骤
  1. 注册驱动

  2. 获取连接

  3. 获取Statement对象

  4. 使用Statement对象执行SQL语句

  5. 释放资源

案例代码
public class Demo03 {
	public static void main(String[] args) throws Exception {
		Class.forName("com.mysql.jdbc.Driver");

		Connection conn = DriverManager.getConnection("jdbc:mysql:///day04_db", "root", "1234");
		System.out.println(conn);

        /*
            1)获取发送sql语句对象使用Connection连接接口对象调用Connection接口的方法:
                 Statement createStatement() 创建一个 Statement 对象来将 SQL 语句发送到数据库。
                 PreparedStatement prepareStatement(String sql) 创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。
             2)Statement和PreparedStatement都可以用来向数据库发送sql语句,Statement是PreparedStatement的父接口。

             3)PreparedStatement 是安全的,Statement不安全的。并且Statement效率低,PreparedStatement效率高

             4)Connection还可以手动控制mysql事务:
                开启事务  void setAutoCommit(boolean autoCommit) 将此连接的自动提交模式设置为给定状态。
                            autoCommit - 为 true 表示启用自动提交模式;为 false 表示禁用自动提交模式

               1. conn.setAutoCommit(false);

                一切正常提交事务  void commit()

               2. conn.commit()

                出现异常,回滚事务  void rollback()

               3. conn.rollback()

         */
		// 从连接中拿到一个Statement对象
		Statement stmt = conn.createStatement();

        /*
            Statement向数据库发送sql语句,使用Statement中的不同的方法可以向数据库发送不同的sql语句:
                1)DQL查询语句:  ResultSet executeQuery(String sql) 执行给定的 SQL 语句,该语句返回单个 ResultSet 对象。
                                                参数:sql - 要发送给数据库的 SQL 语句,通常为静态 SQL SELECT 语句
                                                 返回值:ResultSet用来存放查询的结果,表示结果集
                2)DML增删改和DDL语句(创建表和数据库)使用的方法:
                     int executeUpdate(String sql)
                            执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句(DML),
                            或者不返回任何内容的 SQL 语句(如 SQL DDL 语句)。
                          返回值:
                                    1) 对于 SQL 数据操作语言 (DML) 语句,返回行记录数,影响的行数
                                    2) 对于什么都不返回的 SQL 语句,返回 0 ,执行DDL返回的是0 了解

         */
		// 1.插入记录
		String sql = "insert into user values(null, 'zhaoliu', 'abc')";
		int i = stmt.executeUpdate(sql);
		System.out.println("影响的行数:" + i);

		// 2.修改记录
		sql = "update user set username='tianqi' where username='zhaoliu'";
		i = stmt.executeUpdate(sql);
		System.out.println("影响的行数:" + i);

		// 3.删除记录
		sql = "delete from user where id=4";
		i = stmt.executeUpdate(sql);
		System.out.println("影响的行数:" + i);
		
		// 释放资源
		stmt.close();
		conn.close();
	}
}

6、JDBC实现对单表数据查询
目标

能够掌握JDBC实现对单表数据查询

讲解

ResultSet用于保存执行查询SQL语句的结果。 我们不能一次性取出所有的数据,需要一行一行的取出。

ResultSet的原理
  1. ResultSet内部有一个指针,刚开始记录开始位置

  2. 调用next方法, ResultSet内部指针会移动到下一行数据

  3. 我们可以通过ResultSet得到一行数据 getXxx得到某列数据

ResultSet获取数据的API

其实ResultSet获取数据的API是有规律的get后面加数据类型。我们统称getXXX()

 例如:

对于上图中的一行数据,我要获取username为zhangsan这列的值,有如下2种写法:

  1. rs.getString(“username”); 通过列名获取该列的值。

  2. rs.getString(2); 通过username列所在的第二个位置获取该列的值。

使用JDBC查询数据库中的数据的步骤
  1. 注册驱动

  2. 获取连接

  3. 获取到Statement

  4. 使用Statement执行SQL

  5. ResultSet处理结果

  6. 关闭资源

 案例代码
public class Demo04 {
	public static void main(String[] args) throws Exception {
		Class.forName("com.mysql.jdbc.Driver");
		
		Connection conn = DriverManager.getConnection("jdbc:mysql:///day04_db", "root", "1234");
		Statement stmt = conn.createStatement();
		
		String sql = "select * from user";
		ResultSet rs = stmt.executeQuery(sql);
		
		// 内部有一个指针,只能取指针指向的那条记录
        while(rs.next()){// 指针移动一行,有数据才返回true
				int id = rs.getInt("id");
				String name = rs.getString(2);
				String pwd= rs.getString(3);
				System.out.println(id+"+++"+name+"++++"+pwd);
			}
		
		// 关闭资源
		rs.close();
		stmt.close();
		conn.close();
	}
}
小结

其实我们使用JDBC操作数据库的步骤都是固定的。不同的地方是在编写SQL语句

  1. 注册驱动

  2. 获取连接

  3. 获取到Statement

  4. 使用Statement执行SQL

  5. ResultSet处理结果

  6. 关闭资源

ResultSet如何获取数据?

  1. 调用next方法, ResultSet内部指针会移动到下一行数据

  2. 我们可以通过ResultSet得到一行数据 getXxx得到某列数据

 

7、根据别名查询处理结果集扩展
package com.itheima.sh.a_jdbc_01;

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

public class JDBC03Test {
    public static void main(String[] args) throws Exception {
        /*
            需求:查询数据表user2所有数据输出到控制台
         */
        //2.获取连接
        String url = "jdbc:mysql://localhost:3306/day03_heima138";//连接mysql服务器地址
        String username = "root";//连接mysql服务器用户名
        String password = "1234";//连接mysql服务器密码,这里输入你的密码
        Connection conn = DriverManager.getConnection(url, username, password);

        //3.定义sql
        String sql = "select id,username,password pwd from user2";

        //4.获取发送sql语句对象
        Statement st = conn.createStatement();

        //5.发送sql语句
        /*
            1.ResultSet 表示结果集,用来存放查询的结果,因为查询有可能是多行数据,所以使用集合存储
         */
        ResultSet rs = st.executeQuery(sql);

        //6.处理结果
        while(rs.next()){
            //获取数据
            int id = rs.getInt("id");
            String userName = rs.getString("username");
            /*
                对应处理结果集ResultSet中的getXxx(xxx 变量名):
                    1)根据第几列来获取字段值:例如password属于第三列,那么这里获取password值是:rs.getString(3);
                    2)根据字段名或者别名来获取字段值:如果sql语句某个字段有别名,那么只能书写别名,不能书写字段
                        sql语句:select id,username,password pwd from user2
                        获取密码值:rs.getString("pwd");
             */
            String pwd = rs.getString("pwd");

            //输出
            System.out.println(id+"---"+userName+"---"+pwd);
        }

        //7.释放资源
        rs.close();
        st.close();
        conn.close();
    }
}

8、JDBC实现登录案例
目标

模拟用户输入账号和密码登录网站

  1. 输入正确的账号,密码,显示登录成功

  2. 输入错误的账号,密码,显示登录失败

讲解
案例分析
  1. 使用数据库保存用户的账号和密码

  2. 使用SQL根据用户的账号和密码去数据库查询数据

  3. 如果查询到数据,说明登录成功

  4. 如果查询不到数据,说明登录失败

实现步骤
-- 创建数据库
create database day04_db;

-- 切换数据库
use day04_db;

-- 用户表
create table user (
  id int primary key auto_increment,
  username varchar(30) unique not null,
  password varchar(30)
);

insert into user(username, password) values('zhangsan','123');
insert into user(username, password) values('lisi','123');
insert into user(username, password) values('wangwu','123');

select * from user;

1.使用SQL根据用户的账号和密码去数据库查询数据.  

package com.itheima.sh.a_jdbc_01;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

public class JDBCTest04 {
    public static void main(String[] args) throws Exception {
        /*
            练习:模拟登录,如果登录成功,提示登录成功,登录失败,提示失败
         */
        //1.创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        //2.提示输入用户名和密码
        System.out.println("-------请输入用户名:-------");
        //获取用户名
        String inputUsername = sc.nextLine();

        System.out.println("-------请输入密码:-------");
        //获取密码
        String inputPassword = sc.nextLine();
        //3.获取数据
        //4.注册驱动
        //5.获取和数据库连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day03_heima139", "root", "1234");
        //6.获取发送sql语句的对象
        Statement st = conn.createStatement();
        //7.发送sql语句
        /*
            错误的完整的sql语句:select * from user3 where username=zhangsanand password=123
            正确的完整的sql语句:select * from user3 where username='zhangsan' and password='123'
         */
        ResultSet rs = st.executeQuery("select * from user3 where username='" + inputUsername + "' and password='" + inputPassword+"'");
        //8.处理结果集
        //用户名唯一,查询的是一条数据,所以这里使用if即可
        if(rs.next()){
            //rs.next() :如果当前指针指向的行有数据则返回true
            //获取用户名
            String username = rs.getString("username");
            //输出
            System.out.println("恭喜您,亲,登录成功,欢迎光临我的小店,你的用户名是"+username);
        }else{
            System.out.println("用户名或者密码错误");
        }
        //9.释放资源
        rs.close();
        st.close();
        conn.close();
    }
}
小结

登录案例步骤

  1. 使用数据库保存用户的账号和密码

  2. 让用户输入账号和密码

  3. 使用SQL根据用户的账号和密码去数据库查询数据

  4. 如果查询到数据,说明登录成功

  5. 如果查询不到数据,说明登录失败

9、PreparedSatement预编译对象
目标

能够理解什么是SQL注入

能够理解PreparedSatement的执行原理

讲解
SQL注入问题

sql注入:由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL 关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。

简单来说就是:用户在页面提交数据的时候人为的添加一些特殊字符,使得sql语句的结构发生了变化,最终可以在没有用户名或者密码的情况下进行登录。

案例:模拟登陆。

sql注入原因演示_模拟登陆:

sql注入代码演示:

需求: 根据用户名和密码 查询用户信息(只知道用户名,不知道密码)。

恶意注入方式:在sql语句中添加 -- 是mysql的注释。

用户名username输入 zhangsan' 空格--空格 ,密码password 随意。

select * from user where username ='zhangsan' -- ' and password ='kajajha''' ;

对上述sql语句进行说明:

-- ' and password ='kajajha''' ; -- 表示注释的意思,这样就会将密码都给注释掉了,就相当于只根据用户名zhangsan来查询了。

注意:以上的 zhangsan' 空格--空格 中的用户名zhangsan是数据库存在的。

package com.itheima.sh.a_jdbc_01;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

public class JDBCTest05 {
    public static void main(String[] args) throws Exception {
        /*
            sql注入问题:在对于sql语句使用变量的部分输入一些特殊的符号导致输入的数据不正确也可以完成查询数据
         */
        //1.创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        //2.提示输入用户名和密码
        System.out.println("-------请输入用户名:-------");
        //获取用户名
        String inputUsername = sc.nextLine();

        System.out.println("-------请输入密码:-------");
        //获取密码
        String inputPassword = sc.nextLine();
        //3.获取数据
        //4.注册驱动
        //5.获取和数据库连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day03_heima139", "root", "1234");
        //6.获取发送sql语句的对象
        Statement st = conn.createStatement();
        //7.发送sql语句
        /*
            sql注入:
            正确的完整的sql语句:select * from user3 where username='zhangsan' -- ' and password='i182928'
            说明:上述sql语句在用户输入一些特殊符号(单引号 空格 --等)导致 -- 后面额内容被注释了,结果是之后执行sql:select * from user3 where username='zhangsan'
            其实就是根据用户名查询数据了,即使输入密码,由于被注释了也不会根据密码查询了
         */
        ResultSet rs = st.executeQuery("select * from user3 where username='" + inputUsername + "' and password='" + inputPassword+"'");
        //8.处理结果集
        //用户名唯一,查询的是一条数据,所以这里使用if即可
        if(rs.next()){
            //rs.next() :如果当前指针指向的行有数据则返回true
            //获取用户名
            String username = rs.getString("username");
            //输出
            System.out.println("恭喜您,亲,登录成功,欢迎光临我的小店,你的用户名是"+username);
        }else{
            System.out.println("用户名或者密码错误");
        }
        //9.释放资源
        rs.close();
        st.close();
        conn.close();
    }
}
小结
问题根本原因:

之所以有sql注入的问题,无非是在参数中设置了一些特殊字符,使sql语句在拼接这些参数的时候因为特殊字符的原因改变了sql语句原来的规则。

问题的解决方案:

使用PreparedStatement 解决SQL注入问题,运行在SQL中参数以 ? 占位符的方式表示。

10、PreparedStatement解决SQL注入方案
目标

掌握PreparedStatement是如何解决SQL注入问题的

讲解

1.获取PreparedStatement对象

PreparedStatement是Statement的子接口,可以防止sql注入问题。可以通过Connection接口中的prepareStatement(sql)方法获得PreparedStatement的对象。

方法如下所示:

 PreparedStatement	prepareStatement(String sql)  创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。

注意:sql提前创建好的。sql语句中需要参数。使用?进行占位。

举例:

select *from user where username='zhangsan' and password = '123456';

使用?进行占位

select *from user where username=? and password = ?;

String sql=”select *from user where username=? and password = ?”;

步骤一:PreparedStatement pstmt = conn.prepareStatement(sql); -----需要你事先传递sql。如果sql需要参数,使用?进行占位。

步骤二:设置参数(执行sql之前):pstmt.setXXX(int index, 要放入的值) -----根据不同类型的数据进行方法的选择。第一个参数index表示的是?出现的位置。从1开始计数,有几个问号,就需要传递几个参数。

方法的参数说明:

第一个参数:int index ;表示的是问号出现的位置。 问号是从1开始计数

第二个参数:给问号的位置传入的值。

步骤三、执行,不需要在传递sql了。

pstmt.executeQuery();---执行select

pstmt.executeUpdate();---执行insert,delete,update

小结:

1.使用预编译接口PreparedStatement 好处:

1.解决sql注入问题
2.提供效率,对sql语句只会预编译一次

2.使用编译接口PreparedStatement步骤:

1)使用连接对象调用方法获取预编译接口对象:PreparedStatement  pstmt =  conn.prepareStatement(sql); 
2)给sql语句占位符赋值:pstmt.setXxx(第几个占位符,实际值)
3)运行sql语句:
    	 pstmt.executeQuery();---执行select
   		 pstmt.executeUpdate();---执行insert,delete,update

11、PreparedStatement的 应用(掌握)
目标

能够掌握PreparedSatement实现查询和添加数据

讲解

1、需求: 根据用户名和密码查询用户信息。

代码如下所示:

说明:导包必须都得使用java.sql包下的。

package com.itheima.sh.a_jdbc_01;

import java.sql.*;
import java.util.Scanner;

public class JDBCTest06 {
    public static void main(String[] args) throws Exception {
        /*
            使用PreparedStatement接口解决sql注入问题
                1.使用Connection接口对象调用方法,获取PreparedStatement预编译接口
                    PreparedStatement prepareStatement(String sql)
                2.使用预编译接口  PreparedStatement的对象调用PreparedStatement接口中的方法给sql语句中的占位符赋值
                    setXxx(第几个占位符,实际值)
                3.使用预编译接口  PreparedStatement对象调用PreparedStatement接口中的方法执行sql
                     ResultSet executeQuery()  执行DQL(查询语句)
                      int executeUpdate()    执行DML(增删改语句)
         */
        //1.创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        //2.提示输入用户名和密码
        System.out.println("-------请输入用户名:-------");
        //获取用户名
        String inputUsername = sc.nextLine();

        System.out.println("-------请输入密码:-------");
        //获取密码
        String inputPassword = sc.nextLine();
        //3.获取数据
        //4.注册驱动
        //5.获取和数据库连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day03_heima139", "root", "1234");
        //6.使用Connection接口对象调用方法,获取PreparedStatement预编译接口
        // PreparedStatement prepareStatement(String sql)
        String sql = "select * from user3 where username=? and password=?";
        PreparedStatement pst = conn.prepareStatement(sql);

        //2.使用预编译接口  PreparedStatement的对象调用PreparedStatement接口中的方法给sql语句中的占位符赋值
        //setXxx(第几个占位符,实际值)
        //第一个参数1表示上述sql语句中的第一个占位符(?)位置
        //inputUsername :表示给第一个占位符赋的实际值
        // zhangsan\'\ \-\-
        pst.setString(1,inputUsername);

        //第一个参数2表示上述sql语句中的第二个占位符(?)位置
        //inputPassword :表示给第二个占位符赋的实际值
        pst.setString(2,inputPassword);

        /*
             3.使用预编译接口  PreparedStatement对象调用PreparedStatement接口中的方法执行sql
                     ResultSet executeQuery()  执行DQL(查询语句)
         */
        ResultSet rs = pst.executeQuery();

        //8.处理结果集
        //用户名唯一,查询的是一条数据,所以这里使用if即可
        if(rs.next()){
            //rs.next() :如果当前指针指向的行有数据则返回true
            //获取用户名
            String username = rs.getString("username");
            //输出
            System.out.println("恭喜您,亲,登录成功,欢迎光临我的小店,你的用户名是"+username);
        }else{
            System.out.println("用户名或者密码错误");
        }
        //9.释放资源
        rs.close();
        pst.close();
        conn.close();
    }
}

小结:

上述如何解决sql注入的问题呢?

在方法setXxx()内部解决的。例如上述 st.setString(1,inputUsername); ,将输入的用户名 "zhangsan' -- "传入给setString方法体中,在该方法体中使用转义符号 / ,将特殊符号给转义了,转义之后再发送给mysql服务器,那么特殊符号例如--就不是注释的意思就是普通字符,mysql会认为用户名的值是:zhangsan' --

2、 需求:使用预编译对象执行删除操作

package com.itheima.sh.a_jdbc_01;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class JDBCTest07 {
    public static void main(String[] args) throws Exception {
        /*
            需求:使用预编译对象执行删除操作
         */
        //1.注册驱动
        //2.获取连接
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day03_heima139", "root", "1234");
        //3.获取发送sql语句的预编译对象
        PreparedStatement pst = conn.prepareStatement("delete from user3 where id=?");
        //4.发送sql语句
        //给占位符赋值
        pst.setInt(1, 4);//第一个参数1表示上述sql语句的占位符位置是第一个,第二个参数4表示给id的实际值
        int i = pst.executeUpdate();
        //5.处理结果集
        System.out.println("i = " + i);
        //6.释放资源
        pst.close();
        conn.close();

    }
}
12、执行DQL封装成集合的操作

需求:将user中的数据查询封装到实体类User对象中,然后将User对象放到list集合中,最后遍历list集合

在实际开发中我们使用三层架构进行开发,层与层之间会将传递的参数封装成实体对象,那么接下来我们来看一下dao(数据处理层)层是如何将查询出的结果封装成user对象的:

说明:封装到User类的对象中是因为我们要把查询的结果进行显示和其他的处理。

举例:

用户想在浏览器查询自己的个人信息,那么我们需要到数据库查询出来,然后把个人的全部信息封装到User类的对象中。然后在将User类的对象传递给前台,最后经过相关技术显示到页面浏览器中,达到显示个人信息的效果。

其实我们生活中到淘宝网站购买商品,查看某个商品信息也是这样做的,将数据库中有关商品信息都先全部封装到Product类的对象中。最后显示到页面中。

按照如下操作,书写代码:

新建一个User类,具体属性如下所示:

 

在DAO层使用JDBC将查询的数据封装到User类的对象中的代码,如下所示:

@Test
	public void show() {
		// 初始化值
		Connection conn = null;
		ResultSet rs = null;
		PreparedStatement pst = null;
		try {
			conn = JDBCUtils.getConnection();
			String sql = "select * from user";
			// 获取发送sql的对象
			pst = conn.prepareStatement(sql);
			// 执行sql
			rs = pst.executeQuery();
			//定义集合将遍历结果集封装到List集合中
			List<User> list=new ArrayList<User>();
			// 处理结果
			while (rs.next()) {
				//由于数据库中有多行,所以需要多个User类的对象
				User u = new User();
				u.setId(rs.getInt("id"));
				u.setName(rs.getString("name"));
				u.setCity(rs.getString("city"));
				// 将对象添加到集合中
				list.add(u);
			}
			System.out.println(list.size());//3
		} catch (Exception e) {
			e.printStackTrace();
			
		} finally {
			JDBCUtils.release(rs, pst, conn);// 不要关闭连接,每次使用完之后,把连接还给连接池
		}
	}

说明:

上述将从数据库中查询的数据封装到User类的对象中,相对来说比较复杂。我们这里用户属性相对比较少,如果属性多的话会更加复杂。所以,我们完全可以使用更为简单的方式来对数据进行封装到User类的对象中。可以使用后面学习的mybatis进行封装。

13、JDBC事务
目标

能够掌握JDBC操作事务

讲解

之前我们是使用MySQL的命令来操作事务。接下来我们使用JDBC来操作银行转账的事务。

准备数据
# 创建一个表:账户表.
create database day05_db;
# 使用数据库
use day05_db;
# 创建账号表
create table account(
	id int primary key auto_increment,
	name varchar(20),
	money double
);
# 初始化数据
insert into account values (null,'a',1000);
insert into account values (null,'b',1000);
 JDBC操作事务

API介绍

Connection接口中与事务有关的方法

void setAutoCommit(boolean autoCommit) throws SQLException;
false:开启事务, true:关闭事务
void commit() throws SQLException;
提交事务
void rollback() throws SQLException;
回滚事务

说明:

  • 注意:在jdbc事务操作中,事务的控制都是通过Connection对象完成的,当一个完整的业务操作前,我们首先使用conn.setAutoCommit(false)来开启事务。默认情况下是true的,表示关闭事务,那么一条sql语句就是一个事务,默认提交事务。如果设置为false,那么表示开启事务,所有的sql语句就会都在一个事务中。
  • 当业务操作完成之后,如果整个操作没有问题,我们需要使用conn.commit()来提交事务。当然了,如果出现了异常,我们需要使用conn.rollback()撤销所有的操作,所以出现异常,需要进行事务的回滚。
使用步骤
  1. 注册驱动

  2. 获取连接

  3. 开启事务

  4. 获取到Statement

  5. 使用Statement执行SQL

  6. 提交或回滚事务

  7. 关闭资源

案例代码

如下是使用jdbc操作事务的转账案例代码。

需求:a转给b 100元。

分析:

a用户 money=money-100

b用户 money=money+100

package com.itheima.sh.a_jdbc_01;

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

public class JDBCTest08 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pst1 = null;
        PreparedStatement pst2 = null;
        //生成try-catch-finally代码块快捷键:ctrl+alt+T,不要选中释放资源的代码
        try {
        /*
            需求:使用jdbc控制mysql事务。
            使用Connection接口中的方法:
                1.开启手动控制事务:void setAutoCommit(false)
                2.一切正常,提交事务:void commit()
                3.出现异常,回滚事务: void rollback()
         */
            //使用事务完成a给b转账100元
            //a-100
            //b+100
            //1.注册驱动
//        DriverManager.registerDriver(new Driver());
            //2.获取数据库连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day03_heima139", "root", "1234");
            //开启手动控制事务 == 1.开启手动控制事务:void setAutoCommit(false)
            conn.setAutoCommit(false);
            //3.获取发送sql语句的预编译对象
            // a-100
            pst1 = conn.prepareStatement("update account set money=money-100 where name=?");

            // b+100
            pst2 = conn.prepareStatement("update account set money=money+100 where name=?");
            //4.发送sql语句
            //给占位符赋值
            pst1.setString(1, "a");
            pst2.setString(1, "b");

            //5.发送sql语句
            pst1.executeUpdate();

            //模拟异常

//            int i = 1 / 0;

            pst2.executeUpdate();

            //2.一切正常,提交事务:void commit()
            conn.commit();

        } catch (Exception throwables) {
            throwables.printStackTrace();
            try {
                //3.出现异常,回滚事务: void rollback()
                if (conn != null) {
                    conn.rollback();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

        } finally {
            //5.处理结果
            //6.释放资源
            try {
                if (pst2 != null) {//防止空指针异常
                    pst2.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }

            try {
                if (pst1 != null) {//防止空指针异常
                    pst1.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if (conn != null) {//防止空指针异常
                    conn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }


    }
}
小结

JDBC中与事务相关的API?Connection接口中setAutoCommit,commit,rollback

JDBC操作事务的步骤?

  1. 注册驱动

  2. 获取连接

  3. 获取到Statement

  4. 开启事务

  5. 使用Statement执行SQL

  6. 提交或回滚事务

  7. 关闭资源

14、三层开发业务的案例分析(掌握)

1、开发中,常使用分层思想

  • 不同的层次结构分配不同的解决过程,各个层次间组成严密的封闭系统
  • 不同层级结构彼此平等
  • 分层的目的是:
    • a:解耦,就是降低代码之间的依赖关系。
    • b:可维护性,哪一层出现问题,直接维护哪一层。
    • c:可扩展性,哪一层需要添加代码,直接添加即可。
    • d:可重用性,一个方法可以被其它层重复调用。

2、不同层次,使用不同的包表示

  • com.itheima.web web层 公司域名倒写。和前端页面直接交互。
  • com.itheima.service service层。也叫做业务层。专门用来处理业务的,比如事务。
  • com.itheima.dao dao层。数据处理层。操作数据库的代码都书写在这一层。直接和数据库交互。
  • com.itheima.domain/bean/pojo javabean 存放实体类。临时存放数据
  • com.itheima.utils 存放工具类。

具体的三层开发如下图所示:

第二章 连接池

1、连接池介绍
目标

能够理解连接池的原理和好处

讲解
没有连接池的现状

首先我们通过画图的形式来分析一下我们目前所学的jdbc程序的结构。

说明:以前使用的jdbc的缺点:

  1. 操作数据库都需要创建连接,操作完成还需要关闭连接
  2. 创建连接和关闭连接需要可能比执行sql需要的时间都长
  3. 一个网站需要高频繁的访问数据库,如果短时间频繁的访问数据库服务器,就容易造成服务器的宕机,即死机。
连接池解决现状问题的原理

注意:

通过画图分析得出:当前的jdbc程序每次访问数据库都需要创建一个新的连接,访问完毕之后,还需要释放资源。那么在这样的一个过程中,连接的创建和销毁所消耗的资源是远远大于我们发送sql并执行的时间的。基于这样的情况,我们发现我们的jdbc程序将大量的资源浪费在了连接的创建和销毁上。

举例:就像在上海坐地铁,就一站2分钟的路程,往往在买地铁票的过程需要等待至少10分钟以上的时间。这样是不合理的。所以我们 需要对这样的结构进行优化。

思考上面的结构,大部分的时间浪费在了创建和销毁上。那么我们能不能实现将这些连接回收和利用呢?这样我们就不需要不停的创建和销毁了。只需要创建一次,放在指定的地方。当我们使用的时候,直接从里面拿就行了。用完放回原来的地方。不去销毁,当我再次使用的时候,去拿就行了。而这样的解决方案就是我们需要的。

优化后的结构如下:

说明:首先创建一定数量的连接,然后放到指定的地方。当我们需要获取连接的时候,直接从指定的地方获取。用完了,我们再将连接放回去。这样就能将我们连接的回收利用。并且不用花费大量时间在创建和销毁连接上。

解决方案如下图所示:

连接池好处

连接池中保存了一些数据库连接,这些连接是可以重复使用的。节省数据库的资源消耗。

常用连接池的介绍

javax.sql.DataSource表示数据库连接池,DataSource本身只是Sun公司提供的一个接口,没有具体的实现,它的实现由连接池的数据库厂商去实现。我们只需要学习这个工具如何使用即可。

该接口如下:

public interface DataSource {
	Connection getConnection();
}

常用的连接池实现组件有以下这些:

  1. 阿里巴巴-德鲁伊Druid连接池:Druid是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和SQL解析器组成。该项目主要是为了扩展JDBC的一些限制,可以让程序员实现一些特殊的需求。

  2. C3P0是一个开源的JDBC连接池,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0有自动回收空闲连接功能。

  3. DBCP(DataBase Connection Pool)数据库连接池,是Apache上的一个Java连接池项目。dbcp没有自动回收空闲连接的功能。

小结

连接池的好处?

  1. 连接池内部会保存好一些连接,这些连接可以反复使用,提高连接的使用率,降低数据库资源消耗

连接池的原理?

  1. 创建连接池时,连接池内部就会创建一些连接
  2. 当需要使用连接时,就直接从连接池里面取出连接
  3. 当连接使用完毕时,重新放回连接池
2、Druid连接池
目标

能够掌握Druid连接池的使用

讲解
DRUID简介

Druid是阿里巴巴开发的号称为监控而生的数据库连接池(可以监控访问数据库的性能),Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。如:一年一度的双十一活动,每年春运的抢火车票。

DRUID连接池使用的jar包:druid-1.0.9.jar

Druid常用的配置参数
url数据库连接字符串jdbc:mysql://localhost:3306/数据库名
username数据库的用户名
password数据库的密码
driverClassName驱动类名。根据url自动识别,这一项可配可不配,如果不配置druid会根据url自动识别数据库的类型,然后选择相应的数据库驱动名
initialSize初始化时建立的物理连接的个数。初始化发生在显式调用init方法,或者第一次获取连接对象时
maxActive连接池中最大连接数
maxWait获取连接时最长等待时间,单位是毫秒。
Druid连接池基本使用

API介绍

核心类:DruidDataSourceFactory

获取数据源的方法:使用 com.alibaba.druid.pool.DruidDataSourceFactory 类中的静态方法:

public static javax.sql.DataSource createDataSource(Properties properties)
创建一个连接池,连接池的参数使用properties中的数据

配置信息在properties属性对象中。

我们可以看到Druid连接池在创建的时候需要一个Properties对象来设置参数,所以我们使用properties文件来保存对应的参数。

Druid连接池的配置文件名称随便,放到src目录或者项目根目录下面加载 druid.properties文件内容:

# 数据库连接参数
url=jdbc:mysql://localhost:3306/day05_db
username=root
password=123
driverClassName=com.mysql.jdbc.Driver
使用步骤

1.导入核心包druid-1.0.9.jar

2.在项目下创建一个properties文件,文件名随意,设置对应参数

3.加载properties文件的内容到Properties对象中

4.创建DRUID连接池,使用配置文件中的参数

5.从DRUID连接池中取出连接

6.执行SQL语句

7.关闭资源

案例代码

1.属性文件:在项目下新建一个druid配置文件,命名为:druid.properties

# 数据库连接参数
url=jdbc:mysql://localhost:3306/day05_db
username=root
password=123
driverClassName=com.mysql.jdbc.Driver

2.java代码  

public class Demo03 {
    public static void main(String[] args) throws Exception {
      //加载properties文件的内容到Properties对象中
        Properties info = new Properties();
        //加载项目下的属性文件 相对项目根目录
//        FileInputStream fis = new FileInputStream("druid.properties");
        //相对src目录
        InputStream fis = Test01.class.getClassLoader().getResourceAsStream("druid.properties");
        //从输入流中加载属性
        info.load(fis);
        System.out.println(info);
        //创建DRUID连接池,使用配置文件中的参数
        DataSource dataSource = DruidDataSourceFactory.createDataSource(info);
        //从DRUID连接池中取出连接
        //Connection conn = dataSource.getConnection();
        //System.out.println("conn = " + conn);
// 需求: 根据用户名和密码 查询用户信息
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            // 获得连接
            conn = dataSource.getConnection();
            // 获得发送sql的对象
            String sql = "select * from emp where name=? and city=?";
            pstmt = conn.prepareStatement(sql);
            // 如果有问号,需要 设置参数,注意:下标从1开始
            pstmt.setString(1, "刘备");
            pstmt.setString(2, "北京");
            // 执行sql 获得结果
            rs = pstmt.executeQuery();
            // 处理结果
            if (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String city = rs.getString("city");

                System.out.println(id + ":::" + name + "===" + city);
            } else {
                System.out.println("没有查到对应的用户信息!");
            }
        } catch (Exception e) {
        } finally {
//            JDBCUtils.release(conn, pstmt, rs);
        }
    }
}
案例效果

第三章 JDBC练习

1.需求

完成商品品牌数据的增删改查操作。

查询:查询所有数据

添加:添加品牌

修改:根据 id修改

删除:根据 id删除

2.环境搭建

准备环境:1.创建项目 2.导入druid 和mysql驱动包 3.在src下面创建连接数据库的配置文件

数据库表 tb_brand

实体类 Brand

测试用例

3.查询所有数据

1.获取Connection

2.定义SQL:select *** from tb_brand;

3.获取 PreparedStatement对象

4.设置参数:不需要

5.执行SQL

6.处理结果:List<Brand>

7.释放资源

 @Test
    public void query() throws Exception{
        Properties p = new Properties();
        p.load(new FileInputStream("src\\druid.properties"));
        DataSource ds = DruidDataSourceFactory.createDataSource(p);
        //获取Connection
        Connection conn = ds.getConnection();
        //定义SQL:select * from tb_brand;
        String sql = "select * from tb_brand";
        //获取 PreparedStatement对象
        PreparedStatement pst = conn.prepareStatement(sql);
        //设置参数:不需要
        //执行SQL
        ResultSet rs = pst.executeQuery();
        //处理结果:List<Brand>
        ArrayList<Brand> list = new ArrayList<>();
        while (rs.next()){
            int id = rs.getInt("id");
            String brandName = rs.getString("brand_name");
            String companyName = rs.getString("company_name");
            int ordered = rs.getInt("ordered");
            String description = rs.getString("description");
            int status = rs.getInt("status");
            Brand brand = new Brand();
            brand.setId(id);
            brand.setBrandName(brandName);
            brand.setCompanyName(companyName);
            brand.setOrdered(ordered);
            brand.setDescription(description);
            brand.setStatus(status);
            list.add(brand);
        }
        System.out.println("list = " + list);
        //释放资源
        rs.close();
        pst.close();
        conn.close();
    }
4.添加
@Test
    public void add() throws Exception{
        Properties p = new Properties();
        p.load(new FileInputStream("src\\druid.properties"));
        DataSource ds = DruidDataSourceFactory.createDataSource(p);
        //获取Connection
        Connection conn = ds.getConnection();
        String sql = "insert into tb_brand values(null,?,?,?,?,?)";
        //获取 PreparedStatement对象
        PreparedStatement pst = conn.prepareStatement(sql);
        pst.setString(1,"苹果");
        pst.setString(2,"apple");
        pst.setInt(3,1);
        pst.setString(4,"贵");
        pst.setInt(5,0);
        int count = pst.executeUpdate();
        System.out.println("count = " + count);
        //释放资源
        pst.close();
        conn.close();
    }
5.修改
 @Test
    public void update() throws Exception{
        Properties p = new Properties();
        p.load(new FileInputStream("src\\druid.properties"));
        DataSource ds = DruidDataSourceFactory.createDataSource(p);
        //获取Connection
        Connection conn = ds.getConnection();
        String sql = "update tb_brand set brand_name  = ?,company_name= ?,ordered= ?,description = ?,status= ? where id = ?";
        //获取 PreparedStatement对象
        PreparedStatement pst = conn.prepareStatement(sql);
        pst.setString(1,"OPPO");
        pst.setString(2,"OPPO");
        pst.setInt(3,1);
        pst.setString(4,"贵");
        pst.setInt(5,0);
        pst.setInt(6,3);
        int count = pst.executeUpdate();
        System.out.println("count = " + count);
        //释放资源
        pst.close();
        conn.close();
    }
6.删除
 @Test
    public void delete() throws Exception{
        Properties p = new Properties();
        p.load(new FileInputStream("src\\druid.properties"));
        DataSource ds = DruidDataSourceFactory.createDataSource(p);
        //获取Connection
        Connection conn = ds.getConnection();
        String sql = "delete from tb_brand where id = ?";
        //获取 PreparedStatement对象
        PreparedStatement pst = conn.prepareStatement(sql);
        pst.setInt(1,4);
        int count = pst.executeUpdate();
        System.out.println("count = " + count);
        //释放资源
        pst.close();
        conn.close();
    }

  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿瞒有我良计15

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值