MySQL——JDBC规范

一. JDBC概述

1. 概念

JDBC (Java DataBase Connectivity) java连接数据库技术。

  • JDBC可以实现java语言对数据库表数据的增删改查操作。Java负责后台程序业务逻辑编写的,sql负责数据库增删改查的操作的,我们不能直接使用java去操作sql语言。在这个过程中我们需要一个连接的桥梁或者叫纽带,JDBC就是扮演了这个连接的角色。

  • JDBC技术可以实现java和多种数据库的连接:mysql sqlserver oracle

  • JDBC技术将java连接数据库的方法封装成了jar包的形式,对外提供给开发者使用,我们作为使用者只需要下载并且熟悉使用即可。

2. 分类

在Java中,数据库存取技术可分为如下几类:

  • JDBC直接访问数据库
  • JDO技术(Java Data Object)
  • 第三方O/R工具,如Hibernate, Mybatis 等

JDBC是java访问数据库的基石,JDO, Hibernate等只是更好的封装了JDBC。

3. JDBC的好处

JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统(DBMS)、
通用的SQL数据库存取和操作的公共接口(一组API),
定义了用来访问数据库的标准Java类库,使用这个类库可以以一种标准的方法、方便地访问数据库资源

JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。

JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,
这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。

如果没有JDBC,那么Java程序访问数据库时是这样的:
在这里插入图片描述
有了JDBC之后,Java访问数据库的方式
在这里插入图片描述

  • JDBC是SUN公司提供一套用于数据库操作的接口API,Java程序员只需要面向这套接口编程即可。
  • 不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。

4. JDBC的API

JDBC API是一系列的接口,它统一和规范了应用程序与数据库的连接、执行SQL语句,并到得到返回结果等各类操作。声明在java.sql与javax.sql包中。

JDBC接口(API)包括两个层次:

  • 面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。

  • 面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。

在这里插入图片描述

5. jdbc驱动包下载

jdbc驱动包下载网站

  • 注意事项:jdbc驱动版本需要和mysql数据库版本保持一致。(大版本)
    比如我们的mysql版本是:5.5.58 对应的jdbc驱动版本只要是5.0版本就可以了 如果mysql数据库版本是8.0的对应的jdbc也需要8.0版本

二. JDBC入门

1. JDBC的作用

可以对数据库进行:增删改查

2. JDBC程序的编写步骤

jdbc连接步骤
① 创建java项目,导入下的JDBC驱动包
② 加载JDBC驱动包到程序
③ 创建JDBC连接对象Connection
④ 创建sql的执行对象
⑤ 执行目标sql语句
⑥ 处理执行sql结果返回值
⑦ 关闭连接,释放资源

2.1. 准备工作:引入JDBC驱动程序

JDBC驱动程序:各个数据库厂商根据JDBC的规范制作的 JDBC 实现类的类库

JDBC驱动程序总共有四种类型:

  • 第一类:JDBC-ODBC桥。

  • 第二类:部分本地API部分Java的驱动程序。

  • 第三类:JDBC网络纯Java驱动程序。

  • 第四类:本地协议的纯 Java 驱动程序。

  • 注:第三、四两类都是纯Java的驱动程序,因此,对于Java开发者来说,它们在性能、可移植性、功能等方面都有优势。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.2 加载并注册驱动

  • 加载驱动,把驱动类加载到内存
  • 注册驱动,把驱动类的对象交给DriverManager管理,用于后面创建连接等使用。

在这里插入图片描述
在这里插入图片描述

2.3 获取数据库链接

  • 可以通过 DriverManager 类建立到数据库的连接Connection:
  • DriverManager 试图从已注册的 JDBC 驱动程序集中选择一个适当的驱动程序。
public static Connection getConnection(String url) 

public static Connection getConnection(String url,String user, String password)

public static Connection getConnection(String url,Properties info)
其中Properties info通常至少应该包括 "user""password" 属性

在这里插入图片描述

MySQL的连接URL编写方式:

jdbc:mysql://主机名称:mysql服务端口号/数据库名称?参数=&参数=值

jdbc:mysql://localhost:3306/testdb

jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf8
(如果JDBC程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)
	
jdbc:mysql://localhost:3306/testdb?user=root&password=123456

在这里插入图片描述

2.4 操作或访问数据库

数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。

其实一个数据库连接就是一个Socket连接。

在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:

Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。 

PrepatedStatement:SQL 语句被预编译并存储在此对象中,然后可以使用此对象多次高效地执行该语句。

CallableStatement:用于执行 SQL 存储过程
  • Statement命令对象接口

    通过调用 Connection 对象的 createStatement() 方法创建该对象
    该对象用于执行静态的 SQL 语句,并且返回执行结果
    Statement 接口中定义了下列方法用于执行 SQL 语句:

    int excuteUpdate(sql):执行更新操作INSERT、UPDATE、DELETE,返回受影响的行数
    		
    execute():执行任意语句,返回boolean
    		
    ResultSet excuteQuery(String sql):执行查询操作SELECT,返回结果集
    		
    	ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,
    	ResultSet 接口由数据库厂商实现
    	ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行
    				
    ResultSet 结果集对象接口的常用方法:
    			
    	1.ResultSet 对象生成时会出现一个类似指针的东西指向表头,里面有一个next()方法,
    		调用一次下移一次,也可以返回当前行是否有值(boolean next())。
    
    	2. getXX方法:返回对应列的值,接受类型为XX
    				方式一:getXX(结果集中列的索引)(XX是你想接受的类型)
    				方式二:getXX("列名")
    				方式三:getObject(列的索引/列名)
    
  • PrepatedStatement预编译命令对象接口

    excuteUpdate():执行增删改语句,返回受影响的行数
    excuteQuery():执行查语句,返回结果集
    execute():执行任意sql语句,返回boolean
    setXX(占位符索引,占位符的值):设置对应索引的占位符的值,类型为XX类型
    setObject(占位符索引,占位符的值):设置对应索引的占位符的值,类型为Object类型
    

2.5. 释放资源

Connection、Statement、ResultSet都是应用程序和数据库服务器的连接资源,使用后一定要关闭,可以在finally中关闭

三. JDBC连接的小例子

1. IDEA步骤

创建项目,创建lib目录,赋值jar包进来
在这里插入图片描述
将jar包添加到项目中去
在这里插入图片描述
在这里插入图片描述

package com.pudding.jdbc;

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

public class JDBCTest01 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        /*
         * 使用jdbc技术,增加一个学生数据到学生表
         * INSERT INTO students (sname,age,phone)VALUES("zhangsan",18,"12345678");
         * */

        //1.加载JDBC驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2.创建jdbc连接对象
        String url="jdbc:mysql://localhost:3306/schooldb";//需要操作的目标数据库
        String user="root";//mysql数据库登录账号
        String password="root";//mysql数据库登录密码
        Connection connection= DriverManager.getConnection(url,user,password);

        //3.创建sql的执行对象
        String sql="INSERT INTO students (sname,age,phone) VALUES ('zhangsan', 18 ,'12345678')";
        /*
          PreparedStatement通过连接对象创建
          PreparedStatement执行目标sql的对象,提供了数据库增删改查的方法
          1.executeUpdate执行数据库表的增加 修改 删除操作,返回一个整数值,表示操作数据库表的行数
          2.executeQuery执行数据库表的查询操作,返回值是ResultSet,表示返回的数据结果集合对象
        */
        PreparedStatement statement= connection.prepareStatement(sql);

        //4.执行目标sql
        int row= statement.executeUpdate();

        //5.处理执行sql的返回结果
        System.out.println("数据库表影响的行数:" + row);

        //6.关闭对象释放资源
        statement.close();
        connection.close();
    }
}

在这里插入图片描述

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


/**
 *	此类用于演示JDBC的简单实用步骤
 * @author pudding
 * 
 * 	步骤:
 * 	1.前提:准备mysql的驱动包,加载到项目中
 * 		复制mysql-connector-java-8.0.20.jar到项目的libs目录下,然后右击build path——add to build path
 * 		jar包就到了可引用的类库了
 * 	2.加载驱动:相当于将类加载到我们的内存了
 * 		
 * 		类的加载的时机:
 * 		1.new对象方式
 * 			不足:
 * 				1.属于编译期加载,如果编译期间该类不存在,则直接报编译错误,也就是依赖性太强
 * 				2.导致driver对象创建了两遍,效率低下
 * 			所以一般采用反射的方式加载类
 * 			好处:
 * 				1.属于运行期间的加载,大大降低了类的依赖性
 * 				2.driver对象仅仅创建了1遍,效率较高
 * 
 * 		2.加载子类
 * 		3.调用类中的静态成员
 * 		4.通过反射
 * 
 * 	3.获取连接:相当于把Java应用程序当做客户端连接数据库
 * 	4.执行增删改查操作
 * 	5.关闭连接,释放资源
 *
 */
public class TestJDBC {
	public static void main(String[] args) throws SQLException{
		//1. 加载驱动
		//第一种老方式 不推荐
//		DriverManager.registerDriver(new Driver());
		
		//第二种方式 使用反射方式加载类
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		//2. 获取连接
		//方式一
		Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/girls?serverTimezone=GMT%2B8", "root", "root");
						
		//方式二
//		Properties info = new Properties();
//		try {
//			info.load(new FileInputStream("src\\jdbc.properties"));//此时编写了一个名为properties的txt文档
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		//读出值信息
//		String user = info.getProperty("user");
//		String password = info.getProperty("password");
//		String url = info.getProperty("url");		
//		DriverManager.getConnection(url, user, password);
		
		System.out.println("连接成功");
		
		//3.执行增删改查
		
		String sql = "select id,name,sex,borndate from beauty";
		//获取执行SQL的命令对象
		Statement stmt = con.createStatement();
		//执行SQL语句
		
//		boolean execute = stmt.execute(sql);//执行任何SQL语句
//		int update = stmt.executeUpdate(sql);//执行增删改语句,返回受影响的行数
		ResultSet set = stmt.executeQuery(sql);//执行查询语句,返回一个结果集
		
		
		while(set.next()) {
		
			int id = set.getInt(1);
			String name = set.getString(2);
			String sex = set.getString(3);
			Date date = set.getDate(4);
		
			System.out.println(id+"\t"+name+"\t"+sex+"\t"+date);
		}
		
		//关闭连接
		set.close();
		stmt.close();
		con.close();

	}

}

实现增删改查

public class JDBCTest3 {
    public static void main(String[] args) throws Exception {
        /*
        修改商品信息
        UPDATE goods SET gname='苹果手机',price=8100 WHERE gid=7;
        * */
       Class.forName("com.mysql.jdbc.Driver");
       Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql0103","root","root");
       String sql="UPDATE goods SET gname=?,price=? WHERE gid=?";
       PreparedStatement statement= connection.prepareStatement(sql);
       //占位符替换
       statement.setObject(1,"苹果手机");
       statement.setObject(2,8100);
       statement.setObject(3,7);
       int row= statement.executeUpdate();
        System.out.println("修改影响的行数:"+row);
       statement.close();
       connection.close();
    }
}

public class JDBCTest4 {
    public static void main(String[] args) throws Exception {
        /*
        删除商品
        DELETE FROM goods WHERE gid=5;
        * */
       Class.forName("com.mysql.jdbc.Driver");
       Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql0103","root","root");
       String sql="DELETE FROM goods WHERE gid=?";
       PreparedStatement statement= connection.prepareStatement(sql);
       statement.setObject(1,5);
       int row = statement.executeUpdate();
        System.out.println("删除影响的行数"+row);
        statement.close();
        connection.close();
    }
}

public class JDBCTest5 {
    public static void main(String[] args) throws Exception {
        /*
        查询所有的商品信息:SELECT * FROM goods;
        * */
        //加载JDBC驱动包到程序
        Class.forName("com.mysql.jdbc.Driver");
        //创建JDBC连接对象Connection
        Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql0103","root","root");
        //创建sql的执行对象
        String sql="SELECT * FROM goods";
        PreparedStatement statement= connection.prepareStatement(sql);
        //执行目标sql语句
        /*
        * ResultSet返回的结果集合对象:将数据库表的数据封装到set集合中
        * 1.提供了方法:next()判断set集合中是否有数据,有返回true 没有返回false
        * 2.提供了getXXX方法:获取集合中的数据方法
        *                    根据数据库表的字段类型和名称来获取数据
        * */
        ResultSet resultSet= statement.executeQuery();
        //处理执行sql结果返回值
        System.out.println("获取商品信息如下:");
        while(resultSet.next()){//如果集合中有数据,就执行获取数据的方法
            //获取商品信息:每次循环一次就读取表的一行数据,使用getXXX方法获取行数据中的列字段值
           Object gid= resultSet.getObject("gid");//通过表数据的字段名称获取数据
           Object gname= resultSet.getObject("gname");
           Object price= resultSet.getObject("price");
           Object sortId=resultSet.getObject("sort_id");
            System.out.println(gid+"\t"+gname+"\t"+price+"\t"+sortId);
        }
        //关闭连接,释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}

2. JDBC连接MySQL数据库小实验

题目:
通过JDBC连接MySQL数据库,实现用户的登录和注册两个功能:
(1)在登录功能中,当用户名和密码不匹配时,输出“用户名或密码错误!”,否则输出“登录成功!”;
(2)在注册功能中,注册成功后,输出“新用户注册成功!”。

  1. 在MySQL中创建数据库MyDB,并此数据库中创建表userInfo,表结构如下:

    段名类型
    userNamevarchar(20)
    serPwdvarchar(20)
  2. 采用JDBC方式,连接MyDB数据库

  3. 通过Java编辑器编程(利用纯Java方式)


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

public class TestConnection2 {
	
	public static void main(String[] args) {
		try{
			System.out.println("1-登录");
			System.out.println("2-注册");
			System.out.print("请输入您的选择:");
			Scanner in=new Scanner(System.in);
			int n = in.nextInt();
			
			Class.forName("com.mysql.cj.jdbc.Driver");//这是桥接模式
			Connection con =DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?serverTimezone=GMT%2B8","root","root");
			Statement stmt = con.createStatement();//创建statement对象
			
			if(n==1){
				System.out.println("请输入您的用户名和密码");
				System.out.println("用户名:");
				in=new Scanner(System.in);
				String name = (in.next()).trim();
				
				System.out.print("密码:");
				in=new Scanner(System.in);
				String pwd= (in.next()).trim();
				
				String sql = "select userName,userPwd FROM userinfo where userName = '"+name+"' and userPwd = '"+pwd+"' "; 
				
				ResultSet rs = stmt.executeQuery(sql);
				//rs.last();
				
				//boolean execute = stmt.execute(sql); //执行任何sql语句
				
				if (rs.next()){ 
				     System.out.println("登陆成功");
				}
				if (rs.next() == false) {
					System.out.println("用户名或密码错误!");
				}
				

			}
			else if(n==2){
				System.out.println("请输入您要注册的用户名和密码");
				System.out.println("用户名:");
				in=new Scanner(System.in);
				String name = (in.next()).trim();
				
				System.out.print("密码:");
				in=new Scanner(System.in);
				String pwd= (in.next()).trim();
				
				String sql = "insert into userInfo(userName,userPwd) values('"+ name+"','"+pwd+"')";
				//System.out.println(sql);
	
				stmt.executeUpdate(sql);
				System.out.print("新用户注册成功!");
			}
			else {
				
			}
		}
		catch(ClassNotFoundException e){
			e.printStackTrace();
		}
		catch(SQLException e){
			e.printStackTrace();
		}
				
		System.out.println("success");
	}
}

四. jdbc工具类封装使用

查看前面的增删改查的代码,我们可以发现有很多重复代码,这个时候我们可以考虑将重复代码抽取出来封装成工具类使用,这样可以提高代码的复用性,同时可以提升开发的效果。

1. jdbc工具类代码

在这里插入图片描述
在这里插入图片描述

package com.pudding.util;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

/*jdbc工具类*/
public class JDBCUtil {
    /*设置连接对象的成员参数变量*/
    private static String driver;
    private static String url;
    private static String username;
    private static String password;
    private static Connection connection;

    /*加载jdbc驱动,创建连接对象*/
    static {
        try {
            /*读取外部的配置文件jdbc.properties获取连接参数*/
            Properties properties=new Properties();//创建Properties对象
            properties.load(new FileInputStream("src/jdbc.properties"));//读取配置文件信息
            /*获取配置文件的参数值:根据配置文件的key获取对应的value值*/
            driver=  properties.getProperty("mysql.driver");
            url=properties.getProperty("mysql.url");
            username=properties.getProperty("mysql.username");
            password=properties.getProperty("mysql.password");
            Class.forName(driver);//加载jdbc驱动
            connection= DriverManager.getConnection(url,username,password);//创建连接对象
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*对外提供一个获取连接对象的方法*/
    public static  Connection getConnection(){
        return  connection;
    }

    /*对外提供关闭对象的方法*/
    public static  void close(ResultSet resultSet, Statement statement, Connection connection){
        try {
            if (resultSet!=null){
                resultSet.close();
            }
            if (statement!=null){
                statement.close();
            }
            if (connection!=null){
                connection.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

2. 测试jdbc工具类

在这里插入图片描述

五. DBUTils工具类

1. 概述

Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。
通俗的理解就是:DBUTil是对基础的 JDBC的封装,可以实现jdbc能够实现的所有功能,同时增加了一些新的API,可以大大的提高我们的开发效率。

2. 下载

DBUTil工具类是以jar包的形式提供给开发者使用,我们使用之前需要下载jar包
下载地址:https://commons.apache.org/proper/commons-dbutils/download_dbutils.cgi

3. DBUTils工具类的核心API简介:

  1. DBUTIls类:关闭连接对象

  2. QueryRunner类:执行数据库的增删改查操作,这个类中提供了update()执行增删改操作,提供了query()方法执行查询操作。

  3. ResultSetHandler接口:查询返回的结果集对象。将resultSet对象进行了二次的封装,提供了更加简介的查询结果对象。

    封装的依据:

    #查询返回的不同结果类型:
    #多行多列
    SELECT * FROM emp;
    #多行单列
    SELECT ename FROM emp;
    #单行多列
    SELECT * FROM emp WHERE empno=2;
    #单行单列
    SELECT COUNT(*) FROM emp;
    

    常见返回接口类型如下:

    ArrayHandler:把结果集中的第一行数据转成对象数组。
    
    ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
    
    BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
    
    BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
    
    ColumnListHandler:将结果集中某一列的数据存放到List中。
    
    KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。
    
    MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
    
    MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
    
    ScalarHandler:返回的是具体的一个整数,通常用在聚合查询中
    

4. DBUTil工具类的使用

4.1 准备工作

  1. 创建项目,导入jar包(dbutil和jdbc驱动包)
  2. 创建测试类文件

4.2 DML操作实现(增删改)

需求:使用DBUTIL实现员工表数据的增加功能

package com.pudding.dbutil;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;

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

public class DBUTilTest01 {
    public static void main(String[] args) throws Exception {

        //1.创建sql执行对象:QueryRunner相当于jdbc的sql执行对象PreparedStatement
        QueryRunner queryRunner=new QueryRunner();
        //2.执行目标的sql:增删改使用update方法
        /*
        update方法参数说明:
        * Connection conn 连接对象
        * String sql 目标sql
        * Object... params sql里面携带的参数(可变参数,可以是0-多个参数)
        * */
        //创建连接对象
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/schooldb?useUnicode=true&characterEncoding=utf8","root","root");
        //设置目标sql
        String sql="INSERT INTO emp(ename,job,sal,deptno)VALUES(?,?,?,?)";
        //执行sql:使用可变参数替换占位符
        int row=queryRunner.update(connection,sql,"张三","销售员",5000,12);
        System.out.println("增加数据影响的行数:"+row);
        //关闭对象
        DbUtils.close(connection);
    }
}

在这里插入图片描述
修改员工信息

package com.pudding.dbutil;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;

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

public class DBUTilTest02 {
    public static void main(String[] args) throws Exception{

        Class.forName("com.mysql.jdbc.Driver");
        Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/schooldb?useUnicode=true&characterEncoding=utf8","root","root");
        //创建sql执行对象
        QueryRunner queryRunner=new QueryRunner();
        //执行sql
        String sql="UPDATE emp SET mgr=?,hiredate=?,comm=? WHERE empno=?";
        int row= queryRunner.update(connection,sql,2,"2021-01-03",1500,16);
        System.out.println("修改影响的行数:"+row);
        //关闭对象
        DbUtils.close(connection);
    }
}

在这里插入图片描述
删除员工信息

package com.pudding.dbutil;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;

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

public class DBUTilTest03 {
    public static void main(String[] args) throws Exception{
        /*删除员工信息*/
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/schooldb?useUnicode=true&characterEncoding=utf8","root","root");
        //创建sql执行对象
        QueryRunner queryRunner=new QueryRunner();
        //执行sql
        String sql="DELETE FROM emp WHERE empno=?";
        int row= queryRunner.update(connection,sql,15);
        System.out.println("删除影响的行数:"+row);
        //关闭对象
        DbUtils.close(connection);
    }
}

在这里插入图片描述

4.3 DQL查询操作实现

DBUTil工具类封装了多个ResultSetHandler接口的实现类对象。

我们需要掌握的有下面几个:

  1. BeanHandler (返回单行多列数据):将查询的结果封装到一个javaBean对象中。通过返回的是一个结果对象。每个结果就是数据库表的一行数据。
  2. BeanListHandler:(多行多列数据)将返回的结果封装到javaBean对象中然后在将对象封装到集合中,通常返回的是一个对象的结果集合。也就是对应的是数据库表的多行数据。
  3. ScalarHandler:(单行单列数据)返回的是具体的一个整数,通常用在聚合查询中

知识点补充:javaBean

  • javaBean就是一个java类,类中所有的属性私有化,有set/get方法(java的封装)
  • 一个javaBean类对应数据库表的一张表(实体类Emp<——>数据库表emp)
  • 一个javaBean实例化对象对应表的一行数据(new Emp()<——>数据库表一行数据)
  • JavaBean属性名称对应数据库表的字段名称(类的成员变量名称<——>表字段名称)
  • JavaBean属性的数据类型和数据表的字段类型对应(成员变量的数据类型<——>表字段类型 String<——>varchar)

员工表对应的javaBean类
在这里插入图片描述

public class Emp {
    //私有的属性变量:变量名称必须和数据库表的字段名称一致
    private Integer empno;
    private Integer mgr;
    private Integer deptno;
    private String ename;
    private String job;
    private String hiredate;
    private Double sal;
    private Double comm;
    //无参构造:类中默认会生成的,但是当类中有有参构造的时候无参构造会失效,所以必须写出来
    public Emp() {
    }


    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", mgr=" + mgr +
                ", deptno=" + deptno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", hiredate='" + hiredate + '\'' +
                ", sal=" + sal +
                ", comm=" + comm +
                '}';
    }

    //set/get方法
    public Integer getEmpno() {
        return empno;
    }

    public void setEmpno(Integer empno) {
        this.empno = empno;
    }

    public Integer getMgr() {
        return mgr;
    }

    public void setMgr(Integer mgr) {
        this.mgr = mgr;
    }

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public String getHiredate() {
        return hiredate;
    }

    public void setHiredate(String hiredate) {
        this.hiredate = hiredate;
    }

    public Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

    public Double getComm() {
        return comm;
    }

    public void setComm(Double comm) {
        this.comm = comm;
    }
}

DBUTil测试查询操作一

  • 查询一条员工信息
  • SELECT * FROM emp WHERE empno=3;
public class DBUTilTest04 {
    public static void main(String[] args) throws Exception{
        //创建sql执行对象:QueryRunner
        QueryRunner queryRunner=new QueryRunner();
        //执行查询操作
        /*
        * T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)
        * conn连接对象
        * sql目标sql语句
        * rsh返回结果对象类型 T代表javaBean类型
        * params可变参数
        * */
        //创建连接对象
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/schooldb","root","root");
        //目标sql
        String sql="SELECT * FROM emp WHERE empno=?";
        //创建返回结果对象:单个的javaBean对象BeanHandler  java的多态
        /*注意事项:
           1.javaBean的变量名称必须和数据库表字段一致
           2.javaBean类中必须有无参构造,默认是有一个无参,如果类中有有参构造必须把无参构造写出来
        * */
        ResultSetHandler<Emp> rsh=new BeanHandler<Emp>(Emp.class);
        //执行查询返回结果
        Emp emp= queryRunner.query(connection,sql,rsh,3);
        System.out.println("查询的员工信息是:"+emp);
        DbUtils.close(connection);
    }
}

DBUTil测试查询操作二

  • 查询多条员工信息
  • SELECT * FROM emp WHERE sal BETWEEN 5000 AND 15000;
public class DBUTilTest05 {
    public static void main(String[] args) throws Exception{
        //创建sql执行对象:QueryRunner
        QueryRunner queryRunner=new QueryRunner();
        //创建连接对象
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/schooldb","root","root");
        //创建返回结果对象:BeanListHandler返回多个javaBean对象集合
        ResultSetHandler<List<Emp>> rsh=new BeanListHandler<Emp>(Emp.class);
        //执行查询
        String sql="SELECT * FROM emp WHERE sal BETWEEN ? AND ?";
        //执行查询返回对象的集合
        List<Emp> empList= queryRunner.query(connection,sql,rsh,5000,15000);
        //遍历输出集合数据
        System.out.println("薪资在5000-15000的员工信息:");
        for (Emp emp : empList) {
            System.out.println(emp);
        }
        //关闭对象
        DbUtils.close(connection);

    }
}

DBUTil测试查询操作三

  • 聚合查询
  • SELECT COUNT(*) FROM emp WHERE deptno =12;
public class DBUTilTest06 {
    public static void main(String[] args) throws Exception{
        //创建sql执行对象:QueryRunner
        QueryRunner queryRunner=new QueryRunner();
        //创建连接对象
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/schooldb","root","root");
       //创建返回的结果对象:返回的是一个数值ScalarHandler
        ResultSetHandler<Object> rsh=new ScalarHandler<>();
        //执行查询方法
        String sql="SELECT COUNT(*) FROM emp WHERE deptno =?";
        //执行聚合查询,返回数据
        Object obj= queryRunner.query(connection,sql,rsh,12);
        System.out.println("部门12下面的员工数量是:"+obj);
        //关闭对象
        DbUtils.close(connection);
    }
}

六. 数据库连接池

1. 连接池概述

1.1 为什么要使用连接池技术?

目前为止我们的数据库操作增删改查有可能会造成的一些问题。

  1. 数据库连接是一种关键的有限的昂贵的资源,传统数据库连接每发出一个请求都要创建一个 连接对象,使用完直接关闭不能重复利用;
  2. 关闭资源需要手动完成,一旦忘记会造成内存溢出;
  3. 请求过于频繁的时候,创建连接极其消耗内存;而且一旦高并发访问数据库,有可能会 造成系统崩溃。

1.2 解决问题的方案:

使用连接池,连接池全称是 Database Connection Pool。

使用连接池技术解决问题的原理:(可以参考生活中的共享单车 或者共享充电宝…技术)

  • 数据库连接池负责分配、管理和释放数据库连接,它的核心思想就是连接复用,
  • 通过建立一 个数据库连接池,这个池中有若干个连接对象,当用户想要连接数据库,就要先从连接池中获取连接对象,然后操作数据库。(因为提前进行对象的创建,所以可以提高使用的效率)
  • 一旦连接池中的连接对象被用完了,判断连接对象的个数是否已达上限,如果没有可以再创建新的连接对象,
  • 如果已达上限,用户必须处于等待状态, 等待其他用户释放连接对象,直到连接池中有被释放的连接对象了,这时候等待的用户才能获取连接对象,从而操作数据库。
  • 这样就可以使连接池中的连接得到高效、安全的复用,避免了数据库连接频繁创建、关闭的开销。这项技术明显提高对数据库操作的性能。

2. 第三方连接池

在 Java 中开源的常用的数据库连接池有以下几种 :

一、DBCP

  • DBCP 是一个依赖 Jakarta commons-pool 对象池机制的数据库连接池.DBCP 可以直接的在应用程序中使用,Tomcat 的数据源使用的就是 DBCP。

二、c3p0

  • c3p0 是一个开放源代码的 JDBC 连接池,它在 lib 目录中与 Hibernate 一起发布,包括了实 现 jdbc3 和 jdbc2 扩展规范说明的 Connection 和 Statement 池的 DataSources 对象。

三、Druid

  • 阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一 个 ProxyDriver,一系列内置的 JDBC 组件库,一个 SQL Parser。支持所有 JDBC 兼容的数据 库,包括 Oracle、MySql、Derby、Postgresql、SQL

3. c3p0使用

使用步骤:

  1. 下载c3p0需要的jar包,并添加到到项目中:c3p0-0.9.2.1.jar 和 mchange-commons-java-0.2.3.4.jar
  2. 编写配置文件:拷贝资料里面的c3p0.properties放到项目的src目录下
  3. 测试文件编写

在这里插入图片描述
查询多条员工信息

  • SELECT * FROM emp WHERE sal BETWEEN 5000 AND 15000;
  • 实现思路:DBUTil+c3p0+jdbc

在这里插入图片描述

package com.pudding.test;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.pudding.pojo.Emp;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.util.List;

public class C3p0Test {
    public static void main(String[] args)throws Exception {
        /**
         *  创建sql执行对象:QueryRunner
         *  1.使用无参构造创建的对象,执行增删改查操作的时候需要传入connection对象
         *  2.使用带数据源的有参构造创建对象,执行增删改查操作的时候不需要传入connection对象
         */
        //使用带数据源参数的有参构造创建对象:DataSource管理数据库连接池对象的容器,可以自动回收使用完毕的连接对象
        QueryRunner queryRunner=new QueryRunner(new ComboPooledDataSource());
        //执行查询操作
        String sql="SELECT * FROM emp WHERE sal BETWEEN ? AND ?";
        List<Emp> empList= queryRunner.query(sql,
                new BeanListHandler<Emp>(Emp.class),
                5000,15000);
        //遍历集合
        System.out.println("薪资5000-15000的员工信息是:");
        for (Emp emp : empList) {
            System.out.println(emp);
        }
    }
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值