目录
1. 各种数据库如MySQL、Oracle、SQLServer等,在开始时会提供一组编程接口(API),
API即application programming interface,即代码层次上的提供的功能,API往往是通过函数或类的形式来提供的。
2. 不同的数据库系统的API是不同的JDBC就是统一Java与数据库连接的一套规范的API:

3.Java程序员如果想要进行数据库开发,就需要在项目中导入对应数据库的驱动包,才能编写代码。
4. 驱动包是数据库厂商提供的,此处以MySQL为例,获取方式有:
(1)从MySQL官网获取(现为Oracle官网的一个子网);
(2)github;
(3)maven中央仓库;
注:中央仓库可以理解为一个服务器,托管了各种软件程序包,maven就类似于应用商店,通过应用商店就可以访问到应用程序包并进行下载;

- import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
-
- import javax.sql.DataSource;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.SQLException;
-
- public class JDBCInsert {
- public static void main(String[] args) throws SQLException {
- // 1. 创建并初始化一个数据源;
- DataSource dataSource = new MysqlDataSource();
- // 把dataSource对象转为MysqlDataSource类型
- // setUrl是MysqlDataSource类的方法要调用需先将对象转为MysqlDataSource类型
- ((MysqlDataSource)dataSource).setUrl
- ("jdbc:mysql://127.0.0.1:3306/JDBCProgram?characterEncoding=utf8&useSSL=false");
- ((MysqlDataSource)dataSource).setUser("root");
- ((MysqlDataSource)dataSource).setPassword("xxxxx");
-
- // 2. 和数据库服务器建立连接;
- Connection connection = dataSource.getConnection();
-
- // 3. 构造 SQL 语句
- String sql = "insert into student values(1, 'Mike')";
- // 使用PreparedStatement对sql语句进行预编译
- PreparedStatement statement = connection.prepareStatement(sql);
-
- // 4. 执行 SQL 语句
- int ret = statement.executeUpdate();
- System.out.println("ret = "+ ret);
-
- // 5. 释放必要的资源
- statement.close();
- connection.close();
- }
- }
运行代码,在idea控制台有:

并在MySQL中查看Student表结果:
- mysql> select* from student;
- +------+------+
- | id | name |
- +------+------+
- | 1 | Mike |
- +------+------+
- 1 row in set (0.00 sec)
编写JDBC代码需要以下五个步骤:
(1)数据源即数据的源头,此处数据来源于数据库,即此处要描述数据库服务器在哪里;
数据库中使用DataSourse接口进行描述;
(2)在创建并初始化一个数据源,也可以无需向上转型+向下转型,直接使用MysqlDataSource:
MysqlDataSource dataSource = new MysqlDataSource();
只是在向上转型+向下转型的写法比较流行,二者均可使用;
(3)URL即唯一资源定位符,用于描述网络上某个资源所在的位置,此处设置为:
- ((MysqlDataSource)dataSource).setUrl
- ("jdbc:mysql://127.0.0.1:3306/JDBCProgram?characterEncoding=utf8&useSSL=false");
① jdbc是固定的,mysql为连接的哪一个库;
② 127.0.0.1为本地回环地址,表示本主机;
③ 3306为数据库服务器默认端口号,标记某一主机上的进程;
④ JDBCProgram为数据库名(自行创建);
⑤ characterEncoding=utf8&useSSL=false分别表示字符集为utf8和不加密,SSL是一个加密协议;
(3)除设置URL之外,还需设置User和Passward才能访问数据库服务器,用户名默认为root,密码为安装数据库时的密码;
(4)经过第一步后,只是描述了数据库的位置与用户名、密码等,还没有进行连接;
(1)使用getConnection方法与数据库服务器建立连接,并用Connection类型的变量来接受返回值,注意选择第一个jdbc的Connection:

(2)如果getConnection方法正常运行则连接建立成功,如果连接建立失败会直接抛异常;
基于以下数据库与数据表:
- mysql> use jdbcprogram
- Database changed
- mysql> show tables;
- +-----------------------+
- | Tables_in_jdbcprogram |
- +-----------------------+
- | student |
- +-----------------------+
- 1 row in set (0.00 sec)
-
- mysql> desc student;
- +-------+-------------+------+-----+---------+-------+
- | Field | Type | Null | Key | Default | Extra |
- +-------+-------------+------+-----+---------+-------+
- | id | int(11) | YES | | NULL | |
- | name | varchar(20) | YES | | NULL | |
- +-------+-------------+------+-----+---------+-------+
- 2 rows in set (0.00 sec)
(1)构造的SQL语句与在MySQL中构造的规定相同;
(2)如果请求是个SQL字符串,服务器是可以处理的。服务器就需要对SQL进行解析。
客户端数目庞大时会导致服务器压力很大,故而在客户端使用PreparedStatement对SQL语句进行预编译,就可以减轻服务器的压力;
(1)注意SQL语句的insert、delete和update操作都是使用executeUpdate方法进行执行的,返回值是int类型数据,表示影响的行数;
(2)select操作使用的是executeQuery方法;
(1)数据库的客户端与服务器进行通信时,会消耗一定的系统资源,如CPU、内存、硬盘、带宽等等。为了防止服务器同时处理多个客户端造成系统资源受限,当客户端不使用服务器时,就对资源进行释放;
(2)语句与连接均需要释放,需要先释放语句再释放连接。
释放的顺序与创建的顺序是相反的。
(3)除Datsource之外,还有一种DriverManager的写法,这种写法是通过反射的方式加载驱动包中的类,进一步进行后续操作的。
但并不建议使用这种写法,反射属于java开发的特殊手段,其代码可读性非常差,编译期难以对代码的正确性进行检查,容易产生运行时异常,建议不到万不得已不要使用反射;
并且DataSource内置了数据库连接池,可以复用连接,提高连接服务器的效率;
对于上文的JDBC代码,要插入的数据是硬编码,但是让用户编码是不现实的,故而需要将数据通过其他方式供用户输入。
- 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);
- // 1. 创建并初始化一个数据源;
- DataSource dataSource = new MysqlDataSource();
- ((MysqlDataSource)dataSource).setUrl
- ("jdbc:mysql://127.0.0.1:3306/JDBCProgram?characterEncoding=utf8&useSSL=false");
- ((MysqlDataSource)dataSource).setUser("root");
- ((MysqlDataSource)dataSource).setPassword("xxxxx");
-
- // 2. 和数据库服务器建立连接;
- Connection connection = dataSource.getConnection();
-
- // 3. 从控制台读取用户输入的内容
- System.out.println("请输入学生姓名:");
- String name = scanner.next();
- System.out.println("请输入学生学号:");
- int id = scanner.nextInt();
-
- // 4. 构造 SQL 语句
- String sql = "insert into student values(" + id + ", '"+name + "')";
- // 预编译
- PreparedStatement statement = connection.prepareStatement(sql);
-
- // 5. 执行 SQL 语句
- int ret = statement.executeUpdate();
- System.out.println("ret = "+ ret);
-
- // 6. 释放必要的资源
- statement.close();
- connection.close();
- }
- }
运行代码,在控制台输入一下信息:

在mysql中查看Student表:
- mysql> select* from student;
- +------+------+
- | id | name |
- +------+------+
- | 1 | Mike |
- | 2 | Mary |
- +------+------+
- 2 rows in set (0.00 sec)
在上例代码中,构造的SQL语句为:
String sql = "insert into student values(" + id + ", '"+name + "')";
如果用户输入的name形如:王五');select* from ***,导致看似一条SQL语句变为多个语句,就会出现SQL注入问题,如果再携带drop database之类的语句,可能会对系统造成更大的伤害。
针对以上问题,可以借助PreparedStatement的拼装功能实现:
- 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);
- // 1. 创建并初始化一个数据源;
- DataSource dataSource = new MysqlDataSource();
- // 把dataSource对象转为MysqlDataSource类型
- // setUrl是MysqlDataSource类的方法要调用需先将对象转为MysqlDataSource类型
- ((MysqlDataSource)dataSource).setUrl
- ("jdbc:mysql://127.0.0.1:3306/JDBCProgram?characterEncoding=utf8&useSSL=false");
- ((MysqlDataSource)dataSource).setUser("root");
- ((MysqlDataSource)dataSource).setPassword("xxxxx");
-
- // 2. 和数据库服务器建立连接;
- Connection connection = dataSource.getConnection();
-
- // 3. 从控制台读取用户输入的内容
- System.out.println("请输入学生姓名:");
- String name = scanner.next();
- System.out.println("请输入学生学号:");
- int id = scanner.nextInt();
-
- // 4. 构造 SQL 语句
- String sql = "insert into student values(?, ?)";
- // 使用PreparedStatement对sql语句进行预编译
- PreparedStatement statement = connection.prepareStatement(sql);
- statement.setInt(1, id);
- statement.setString(2, name);
- // 打印statement需在拼接数据之后
- System.out.println(statement);
- // 5. 执行 SQL 语句
- int ret = statement.executeUpdate();
- System.out.println("ret = "+ ret);
-
- // 6. 释放必要的资源
- statement.close();
- connection.close();
- }
- }
输入学生姓名与学号后,控制台输出结果如下:

在mysql中查看Student表:
- mysql> select* from student;
- +------+------+
- | id | name |
- +------+------+
- | 1 | Mike |
- | 2 | Mary |
- | 3 | John |
- +------+------+
- 3 rows in set (0.00 sec)
注:(1)构造的SQL语句中的2个?是两个占位符,statement.setInt与statement.setString方法就可以把占位符替换为指定的值,
- statement.setInt(1, id);
- statement.setString(2, name);
分别表示将第一个占位符替换为id的值,第二个占位符替换为name的值,当用户输入给id和name赋值后,就会通过该方法自动替换;
(2)可以使用打印statement的方法查看具体拼接情况,需将该语句置于拼接数据之后;
假如代码执行出错了也可以把statement打印出来查看具体语法是否出错;
- 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;
-
- public class JDBCSelect {
- public static void main(String[] args) throws SQLException {
- // 1. 创建并初始化数据源
- DataSource dataSource = new MysqlDataSource();
- ((MysqlDataSource)dataSource).setUrl
- ("jdbc:mysql://127.0.0.1:3306/JDBCProgram?characterEncoding=utf8&useSSL=false");
- ((MysqlDataSource)dataSource).setUser("root");
- ((MysqlDataSource)dataSource).setPassword("97805");
- // 2. 建立连接
- Connection connection = dataSource.getConnection();
- // 3. 构造SQL语句
- String sql = "select* from Student";
- PreparedStatement statement = connection.prepareStatement(sql);
- // 4. 执行SQL语句
- ResultSet resultSet = statement.executeQuery();
- // 5. 遍历结果集合
- while(resultSet.next()){
- int id = resultSet.getInt("id");
- String name = resultSet.getString("name");
- System.out.println("id = " + id +", name = " + name);
- }
- // 6. 释放资源
- resultSet.close();
- statement.close();
- connection.close();
- }
- }
控制台输出结果为:

注:(1)执行SQL的语句为:
ResultSet resultSet = statement.executeQuery();
对比SQL实现Insert的executeUpdate方法返回的是一个int类型数据,实现Select的executeQuery方法返回的是一个ResultSet类型对象。
该对象可以视为是一张表,初始时光标指向表首行,可以使用getXXX方法获取当前光标指向的行的数据。每调用一次next,就使光标下移一行,当光标遍历完整张表,再调用next时,就会返回false;
(2)getXXX方法用于取出这一行指定列的值,使用的方法要与列的类型匹配;
参数可以是第几列的下标,也可以是列名,更推荐使用列名;
- while(resultSet.next()){
- int id = resultSet.getInt("id");
- String name = resultSet.getString("name");
- System.out.println("id = " + id +", name = " + name);
- }
(3)实现Select的程序在释放资源时,相较于Insert,需要多释放一个resultSet,可以将查询结果的临时表视为一个resultSet;