什么是JDBC

Java 数据库连接 (JDBC) API 是 Java 编程语言与各种数据库 SQL 数据库和其他表格数据源(如电子表格或平面文件)之间独立于数据库的连接之间的行业标准。JDBC API 为基于 SQL 的数据库访问提供了调用级 API。JDBC给数据库的连接搭建了桥梁,然后再根据不同的数据库厂商实现JDBC接口的驱动,就可以轻松的连接各种关系型数据库了。

eb744833b219497ea5a7bdc62073cb4d.png点击并拖拽以移动

JDBC的重要性

JDBC是Java操作数据库的唯一方式,所以说JDBC非常的重要,尽管我们后面会学习框架,但是这是框架的底层必定都封装了JDBC的代码。

开始准备

我们需要MySQL的驱动,驱动下载网址:Maven Repository: mysql » mysql-connector-java (mvnrepository.com)(我选的是mysql-connector-java-8.0.X.jar)

1eeb0dbc027b462da75799eb4c6d6a1e.png点击并拖拽以移动

5d5e79085632409d85d966fec7019268.png点击并拖拽以移动

JDBC连接数据库

连接步骤:

ef189d3228aa4702abdff1ff003bd4f5.png点击并拖拽以移动

1. 首先需要导入对应数据库的驱动包

要访问MySQL时间就必须要用到MySQL驱动包(前面已经给出了链接),下载然后导入即可。本例用的是IDEA导入这个jar包

导包步骤: 点击当前项目左上角File—>Project Structur—>Modules—>点击右边+号—>Jars Or directories:

b2f2b7d1501d4b75a4933f0c1855e2e0.png点击并拖拽以移动

2.加载驱动

驱动的加载我们一般使用反射Class.forName(“com.mysql.jdbc.Driver”)来加载Driver这个类(因为它只会创建一次)。也可以使用 DriverManager.registerDriver(new Driver())来加载,但这种方式会new两个Driver,从而造成资源浪费,所以不推荐使用这种方式

1
2
3
4
5
6
try {
Class.forName("com.mysql.jdbc.Driver");

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

点击并拖拽以移动

3.写用户信息与url

1
2
3
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=ture&useSSL=ture";
String username="root";
Strng password="123456";

点击并拖拽以移动

4.与数据库建立连接

建立连接需要我们提供上面三个参数,url、username和password

1
Connection con=DriverManager.getConnection(url,username,password);

点击并拖拽以移动

各自的参数的含义依次如下:

  • 协议:jdbc
  • 子协议:mysql
  • 数据库服务端的IP地址:localhost或127.0.0.1
  • 数据库端口:3306
  • 连接的数据库名称:jdbcstudy
  • 编码格式:?characterEncoding=UTF-8
  • 数据库用户名:root
  • 数据库密码:123456(数据库密码是你安装时设置的密码)

5.创建sql对象,并执行sql

  • 使用Statement执行语句

1
2
3
4
5
Statement statement = con.createStatement();
//添加数据
String insert_sql="insert into t_user(username,password) values ('张三',123456)";
int count = statement.executeUpdate(insert_sql);
System.out.println("受影响行数:"+count);

点击并拖拽以移动

sql注入问题

使用Statement有一个极大的缺点,会导致SQL注入。当SQL语句的 where 条件后面带有 or 1=1 的条件时,数据库会认为是true可以执行的,所以外界可以对数据库进行删、改操作,这样的数据库如同虚设,如下:

1
2
3
4
5
6
7
8
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcstudy?characterEncoding=UTF-8", "root", "root");
Statement statement = con.createStatement();
//删除数据
String id="1 or 1=1";
String delete_sql="delete from t_user where id="+id;
int count = statement.executeUpdate(delete_sql);
System.out.println("影响的行数:"+count);

点击并拖拽以移动

以上显然会把数据全部删除;

  • 使用PreparedStatement执行语句(防止sql注入问题)

​ 与Statement不同的是PrepareStatement中的SQL使用了占位符(也可以执行没有占位符的SQL语句)。“?”在SQL中就起到占位符的作用。这种方式除了避免了Statement拼接字符串的繁琐之外,还能够提高性能。

​ 填入数据使用PreparedStatement实例的setXXX(int parameterIndex, String x)方法,其中第一个参数时索引位置,第二个是传入数据。要主要的PreparedStatement中的索引是从 1开始的,而不是从0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Connection con=null;
PreparedStatement ps=null;
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcstudy?characterEncoding=UTF-8", "root", "123456");
String sql="insert into t_user(username,password) values (?,?)";
ps=con.prepareStatement(sql);
ps.setString(1,"威哥");
ps.setString(2,"123456");
int count = ps.executeUpdate();
System.out.println("受影响行数:"+count);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}

点击并拖拽以移动

6.遍历出结果(注意这是执行查询操作时的步骤)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcstudy?characterEncoding=UTF-8", "root", "123456");
String sql="select * from t_user where username like ?";//查询SQL
ps= con.prepareStatement(sql);
ps.setString(1,"张"+"%");//查询条件
rs = ps.executeQuery();////通过PreparedStatement对象调用executeQuery方法,执行sql语句,返回一个ResultSet对象
while (rs.next()){//相当于一个指针,开始指向整个结果集第一行数据之前,每调用一次就向后移动一次,若没有数据就返回false。
int id=rs.getInt(1);//用索引
String username=rs.getString("username");//用字段名
String password=rs.getString("password");
System.out.print("编号:"+id+";");
System.out.print("姓名:"+username+";");
System.out.print("密码:"+password+";");
System.out.println();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}

点击并拖拽以移动

第一次执行next()后,它指向第一行结果,继续执行next(),他会继续指向下一行

next的返回结果是布尔值,它可以用来判断是否有下一行。ResultSet中常用的方法在前面第二点已经给出来了,可自行划上去瞄一眼

7.关闭连接

对数据库的操作完成后,一定要关闭连接,因为数据库连接非常的耗资源。顺序是后创建的先关闭,这些对象通常是ResultSet, Statement和Connection。

而且还要在关闭语句中加try catch已经以防止前面关闭出错,导致后面的关闭不了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
finally {
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {


}
}
}

点击并拖拽以移动


补充:

常用Statement方法:

    • execute(String sql):运行语句,返回是否有结果集
  • executeQuery(String sql):运行select语句,返回ResultSet结果集。
  • executeUpdate(String sql):运行insert/update/delete操作,返回更新的行数。
  • addBatch(String sql) :把多条sql语句放到一个批处理中。
  • executeBatch():向数据库发送一批sql语句执行。

ResultSet接口

ResultSet提供检索不同类型字段的方法,常用的有:

    • getString(int index)、getString(String columnName):获得在数据库里是varchar、char等类型的数据对象。
  • getFloat(int index)、getFloat(String columnName):获得在数据库里是Float类型的数据对象。
  • getDate(int index)、getDate(String columnName):获得在数据库里是Date类型的数据。
  • getBoolean(int index)、getBoolean(String columnName):获得在数据库里是Boolean类型的数据。
  • getObject(int index)、getObject(String columnName):获取在数据库里任意类型的数据。

ResultSet还提供了对结果集进行滚动的方法:

    • next():移动到下一行
  • Previous():移动到前一行
  • absolute(int row):移动到指定行
  • beforeFirst():移动resultSet的最前面。
  • afterLast() :移动到resultSet的最后面

使用后依次关闭对象及连接:ResultSet → Statement → Connection