1.JDBC编程概念
在实际项目中,我们对于数据库的操作大部分是通过代码来完成的,各种数据库在开发的时候,都会提供一组编程接口API。所以不同公司使用不同的数据库软件,那么程序员学习成本是非常大的,因为要学习不同数据库对应的编程风格和相关语法。所以在java层面就进行了统一,这就是JDBC。各大数据库厂商在自身原生的API接口的基础上进行封装,形成数据库驱动包,在由各个数据库的数据库驱动包集合形成JDBC。
JDBC,即Java Database Connectivity,java数据库连接。是一种用于执行SQL语句的Java API,它是
Java中的数据库连接规范。这个API由 java.sql.*,javax.sql.*包中的一些类和接口组成,它为Java
开发人员操作数据库提供了一个标准的API,可以为多种关系数据库提供统一访问。
1.1 JDBC的工作原理
JDBC 为多种关系数据库提供了统一访问方式,作为特定厂商数据库访问API的一种高级抽象,它主要包
含一些通用的接口类。
JDBC访问数据库层次结构:
1.2 JDBC优势
- Java语言访问数据库操作完全面向抽象接口编程
- 开发数据库应用不用限定在特定数据库厂商的API
- 程序的可移植性大大增强
2.JDBC使用
2.1JDBC驱动包的下载
首先是安装驱动包,驱动包可以从MySQL官网获取,但是oracle官网贼难用;或者可以去github下载,再者可以去maven中央仓库下载(这个maven就类似计算机系列软件程序的应用商店)
这里我们使用maven去下载
- 打开网站https://mvnrepository.com/
- 搜索mysql的相关软件
- 点击第一个或者第二个(mysql-connector-java)都可以
- 然后选择对应的版本,注意这里的大版本号一定要和数据库服务器版本匹配,比如我的mysql的数据库服务器用的是5版本,所以我的驱动包也必须用5版本
- 进入下载页面
- 我们下载的文件后缀是.jar,这个后缀可以理解为是多个.class文件合在一起的压缩包
2.2驱动包的安装、导入
- 下载好驱动包(一个.jar文件)后,首先我们我们在idea创建一个新的项目
- 在项目下面我们创建一个目录
- 然后将我们下载下来的.jar文件复制粘贴到该目录下
- 将目录标记为库,标记为库后,idea就可以识别.jar文件了。从而就可以调用里面的类来写代码了。
- 导入成功后我们就可以开始正常编程了,我们在src文件下创建类JDBCIsert
2.3 IDEA内JDBC的使用
在新建好类,以及main方法后,我们开始编程。JDBC需要通过已下步骤来完成开发
2.3.1 创建并初始化一个数据源
- 创建并初始化MysqlDataSource
所谓数据源就是数据从哪里来,也就是描述数据库服务器在哪里,我们通过DataSource这个接口来描述。
但是DataSource本身是接口,是一个抽象类,不能直接new,所以实际上我们是new他的子类MysqlDataSource对象,来实现DataSource这个接口。
DataSource dataSource = new MysqlDataSource();//这里实际是向上转型,子类实现父类接口
但是这样还不够,还需要向下转型一次,转回来,因为我们需要使用setUrl、setUser、setPassword方法,这个方法是子类MysqlDataSource独有的,父类并没有,所以进行向下转型。
- 设置Url
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/JDBC?characterEncoding=utf8&useSSL=false);
所以上述两行代码实际上也可以写成以下代码
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/JDBC?characterEncoding=utf8&useSSL=false);
URL是唯一资源定位符,是一个计算机网络中的常见术语,用于标记网络资源的位置。
我们这里输入"jdbc:mysql://127.0.0.1:3306/JDBC?characterEncoding=utf8&useSSL=false"
首先jdbc
是固定的,mysql
是我们使用的数据库,127.0.0.1:3306
是IP地址,mysql数据库是一个“客户端服务器”结构,客户端和服务器端通过网络通信,网络上确定主机位置就是通过IP地址来确定,而127.0.0.1表示环回地址,表示本地Ip因为我们测试的mysql的服务器端和客户端在同一台设备上(我们自己的主机)。3306是端口号,用于区别不同的应用程序,数据库服务器的默认端口号是3306。base1
是数据库名字,也就是我们用SQL语句写时create database 数据库名
里面的数据库名字。characterEncoding=utf8
表示字符集使用utf8,useSSL=false
中SSL是一个加密协议,这里表示不加密。
- 设置用户名和密码
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("120198087zbh");
用户名统一写成默认值root,不要写其他值;密码对应的是我们在装mysql时写入的密码。
2.3.2 建立连接
Connection connection = dataSource.getConnection();
但是这里是会报错的,这是一个受查异常,我们直接给他抛出,注意要抛出,还要导入这个异常的包。
然后我们用Conenction接口接收。注意Conection接收时我们一定使用java.sql这里包里面的Conection否则编译不了,千万不要使用mysql包里面的。
到这里的代码就可以先执行一下,判断是否有错误。
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.SQLException;public class JDBCInsert {public static void main(String[] args) throws SQLException {//JDBC需要通过以下步骤来完成开发//1.创建并初始化一个数据源
// MysqlDataSource mysqlDataSource = new MysqlDataSource();
// mysqlDataSource.setUrl();DataSource dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/base1?characterEncoding=utf8&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("120198087zbh");//2.建立连接Connection connection = dataSource.getConnection();}
}
2.3.3构造sql语句
在dos环境下我们打开我们的mysql,构建数据库,创建表。
Enter password: ************
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.27-log MySQL Community Server (GPL)Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database base1 character set utf8mb4;
Query OK, 1 row affected (0.00 sec)
mysql> use base1;
Database changed
mysql> create table student(student_id int primary key auto_increment,student_name varchar(20));
Query OK, 0 rows affected (0.02 sec)
假如我现在要在java里去新增数据,那么在IDEA里面写下如下代码
//3.构造SQL语句
String sql = "insert into student values(1,'张三')";//创建一个sql语句
PreparedStatement statement = connection.prepareStatement(sql);//使用PreparedStatement接口进行提前预编译我们的sql
让客户端进行预编译,服务器做的工作就简单一些,压力会小一些。PreparedStatement中Prepared可以理解为提前准备的,Statement语句
2.3.4执行sql语句
在构造好sql语句后(预编译)我们要将其发送给服务器端,并执行该语句
int ret = statement.executeUpdate();//executeUpdate的返回值为int
System.out.println("ret = "+ ret);
insert、updata、delete操作都使用executeUpate方法,其返回值为int,表示影响了几行,实际上就是我们在dos环境下(如下图)这个里面的0 rows affected 里面的0就是这个返回值。
而select 操作使用的是executeQuery方法
在执行完这一句之后就我们可以去MySQL验证一下,是不是插入了数据
mysql> select * from student;
+------------+--------------+
| student_id | student_name |
+------------+--------------+
| 1 | 张三 |
+------------+--------------+
1 row in set (0.01 sec)
发现确实是插入了的。
2.3.5 释放资源
- 数据库的客户端和服务器之间进行通信的时候,是要消耗一定资源(包括cpu,内存,硬盘,带宽等)的。当客户端数量够大的时候,一定不能让客户端随意的占用消耗,也就是不用的时候要感觉释放。
- 语句(statement)和链接(connection)的释放是有一定顺序的,谁先创建谁后释放。
statement.close();
connection.close();
2.3.6 细节补充
在本例子中我们插入数据是通过nsert into student values(1,'张三')
这样写死的硬编码去完成的,但是实际项目中,这个输入肯定是需要用户在控制台输入才对。
所以代码可以这样去改写
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;public class JDBCInsert {public static void main(String[] args) throws SQLException {Scanner scanner = new Scanner(System.in);//JDBC需要通过以下步骤来完成开发//1.创建并初始化一个数据源
// MysqlDataSource mysqlDataSource = new MysqlDataSource();
// mysqlDataSource.setUrl();DataSource dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/base1?characterEncoding=utf8&useSSL=false");//设置url((MysqlDataSource)dataSource).setUser("root");//设置用户名((MysqlDataSource)dataSource).setPassword("120198087zbh");//设置密码//2.建立连接Connection connection = dataSource.getConnection();//异常抛出//3.控制台输入System.out.println("请输入学号:");int student_id = scanner.nextInt();System.out.println("请输入姓名:");String student_name = scanner.next();//4.构造SQL语句String sql = "insert into student values(" + student_id+ ",'" + student_name + "')";//创建一个sql语句PreparedStatement statement = connection.prepareStatement(sql);//使用PreparedStatement接口进行提前预编译我们的sql//5.执行SQL语句int ret = statement.executeUpdate();//executeUpdate的返回值为intSystem.out.println("ret = "+ ret);//6.释放资源statement.close();connection.close();}
}
但是这个代码还是比较丑陋的。
有更好的写法,可以借助PreparedStaterment的拼装功能来实现。
String sql = "insert into student values(?,?)";//用?(占位符)来先取代两个参数的位置
PreparedStatement statement = connection.prepareStatement(sql);//使用PreparedStatement接口进行提前预编译我们的sql
statement.setInt(1,student_id);//将第一个占位符所表示的整型参数替换为student_id
statement.setString(2,student_name);//将第二个占位符所表示的字符串参数替换为student_name
那么我们的完整的代码可以就如下:
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;
public class JDBCInsert {public static void main(String[] args) throws SQLException {Scanner scanner = new Scanner(System.in);//JDBC需要通过以下步骤来完成开发//1.创建并初始化一个数据源
// MysqlDataSource mysqlDataSource = new MysqlDataSource();
// mysqlDataSource.setUrl();DataSource dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/base1?characterEncoding=utf8&useSSL=false");//设置url((MysqlDataSource)dataSource).setUser("root");//设置用户名((MysqlDataSource)dataSource).setPassword("120198087zbh");//设置密码//2.建立连接Connection connection = dataSource.getConnection();//异常抛出//3.控制台输入System.out.println("请输入学号:");int student_id = scanner.nextInt();System.out.println("请输入姓名:");String student_name = scanner.next();//4.构造SQL语句
// String sql = "insert into student values(" + student_id + ",'" + student_name + "')" ;//创建一个sql语句String sql = "insert into student values(?,?)";//用?(占位符)来先取代两个参数的位置PreparedStatement statement = connection.prepareStatement(sql);//使用PreparedStatement接口进行提前预编译我们的sqlstatement.setInt(1,student_id);//将第一个占位符所表示的整型参数替换为student_idstatement.setString(2,student_name);//将第二个占位符所表示的字符串参数替换为student_name//5.执行SQL语句int ret = statement.executeUpdate();//executeUpdate的返回值为intSystem.out.println("ret = "+ ret);System.out.println(statement);//如果我们发现出错,我们可以将statement打印出来,观察一下是不是我们的SQL语句写错了;//6.释放资源statement.close();connection.close();}
}
同时如果在项目开发中出错,我们可以通过打印statement看到我的SQL语句有么有出错。
执行结果
当前我们的JDBC是使用DataSourse 这样的方式来进行编写。
还有一种写法DriveManager,通过反射的方式加载驱动包中的类,进一步进行后续操作。
但是还是推荐DataSourse,因为反射的代码可读性是非常差的,编译器难以对代码的正确性进行检查。此外,DataSource内置了数据库连接池,可以复用连接,提高连接服务器的效率。
计算机中池的本质是一种预申请机制,利用空间换时间。
2.4 IDEA实现MySQL查询操作
示例
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;public class JDBCSelect {public static void main(String[] args) throws SQLException {Scanner scanner = new Scanner(System.in);//1.创建并初始化数据源DataSource dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/base1?characterEncoding=utf8&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("120198087zbh");//2.建立连接Connection connection = dataSource.getConnection();//3.构造SQLSystem.out.println("请输入查询语句");String sql = scanner.nextLine();
// String sql = "select * from student";//4.预执行PreparedStatement statement = connection.prepareStatement(sql);//5.执行SQL语句ResultSet resultSet = statement.executeQuery();//resultSet就是select里面创建的临时表//6.遍历结果集合while(resultSet.next()){//这个效果和迭代器类似//把resultSet想象成一个表格,同时有一个光标指向表格的最上面//每一次调用next,光标都会往下走一行//当光标指向某一行的时候就可以通过getXXX等方法来获取当前行对应的列里面的数据。//当这个表都遍历完了,next就会返回false;int id = resultSet.getInt("student_id");//getXXX方法必须类型匹配//getXXX方法的参数可以是列名,也可以是下标String name = resultSet.getString("student_name");System.out.println("id = " + id +", name - " + name );}//7.释放资源resultSet.close();statement.close();connection.close();}
}
结果