学习SQL操作数据库不能满足业务要求,所以需要通过Java代码来操作数据库。
数据库的种类有很多,并且每一个数据库提供的接口可能都是不同的,而在Java标准库中把操作各种数据库统一成了一组类来完成,这样就可以屏蔽各种数据库的差异,而可以直接通过Java代码来方便地操作各种数据库。
如果想要使用JDBC的话,不仅需要JDBC软件也需要下载JDBC驱动包。JDBC驱动不是真正的驱动(运行在操作系统和硬件设备之间),而是只是使用JDBC所需要的一些文件而已。
要下载JDBC驱动包,去maven中央仓库下载,注意JADC驱动的版本要和自己mysql的版本一致才可以。
下载下来是一个jar包,即一个压缩文件包,里面按照目录结构存放了很多的.class文件可以被java识别,通过将class文件打包的方式使得用户可以方便的下载和使用。
使用JDBC的时候,需要在Java项目中引入这个驱动。新建一个目录将jar包放进去,然后将这个目录键入library即可。
下面开始写代码啦~~~
下面这个代码就是进行了执行了一条插入语句,其中除了执行SQL的地方是自己需要根据需求动态修改的之外,其余的部分都是固定的格式,自己理解一遍之后直接“照抄”即可。
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 TestJDBC {
public static void main(String[] args) throws SQLException {
// 1. 创建一个DataSource类型的实例(JDBC提供的)
// DataSource描述的来源
DataSource dataSource = new MysqlDataSource();
// 通过url来访问数据库的地址
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java_test?characterEncoding=utf8&useSSL=false");
// 设置数据库的用户
((MysqlDataSource) dataSource).setUser("root");
// 设置数据库的用户的密码
((MysqlDataSource)dataSource).setPassword("xxx");
// 2. 找到数据库后需要对数据库进行连接
Connection connection = dataSource.getConnection();
// 3. 构造SQL语句
String sql = "insert into student values(1, 'zhy', 20)";
PreparedStatement statement = connection.prepareStatement(sql);
// 4. 执行SQL
// statement提供了两个系列的execute
// 1. executeUpdate,用于增加,删除,修改数据。返回值为int,表示影响表记录的行数
// 2. executeQuery,用于查找数据。返回值为ResultSet,表示返回的结果集,一个虚拟的表
int res = statement.executeUpdate();
System.out.println("res = " + res);
// 5. 释放相关资源
// 释放的顺序和申请资源的顺序相反
// 如果不释放资源,那么statement和connection持有的内存资源等资源就不能被释放,最终导致资源泄漏问题
statement.close();
connection.close();
}
}
JDBC的5大步骤:
- 创建一个DataSource实例
- DataSource是同一个通用接口,各种数据库都和DataSource关联,但是MysqlDataSource只针对MySQL数据库。MySQL是一个CS程序,所以需要用户名和面。如果是其他像SQLite数据库就没有用户名和密码的概念。
为什么要先向上转型再向下转型?
- 因为DataSource是通用类型,如果后续想要更改数据库的话,改动成本比较小。如果直接写成MysqlDataSource类型也可以,但是如果一旦要更换数据库的话,那么所有出现MysqlDataSource的地方都需要更改,它的变更性就比较差了。
- 使用dataSource实例来连接数据库
- getConnection()这个异常需要显式地处理。有两种方法处理:
- 将异常通过throws将异常抛到上一层调用的函数中
- throw是抛出了一个异常,throws是可能会抛出一个异常
- 通过try - catch将这个异常在本层函数中进行处理
- 将异常通过throws将异常抛到上一层调用的函数中
- Connection描述的是数据库连接的对象,一个程序可以只有一个Connection,也可以有多个Connection。
- 一般只有一个Connection的情况下,都是服务器启动时就创建Connection,当服务器收到收到一个请求就通过这个Connection来访问数据库
- 一般有多个Connection的情况下,是服务器在启动后,每收到一个连接就建立一个Connection。
- getConnection()这个异常需要显式地处理。有两种方法处理:
关于数据库连接失败的问题
-
Communications link failure
- 连接协议写错了
- 数据库的ip和port连接错了
- 数据库的用户名或者密码写错了
- 没有启动mysql服务
-
useSSL没有设置成false,证书认证失败
-
使用PreStatement类写SQL语句
一般需要用户来执行SQL的语句的时候,使用字符串拼接的方式,不仅书写不方便,而且有安全隐患。最常见的攻击就是SQL注入。
- 静态:编译起确定结果
- 注意:这里的静态和static没有关系,static修饰类的成员变量或者类成员方法可以使得变量和方法变成类属性和类方法
- 动态:运行时确定结果
所以一般在动态写SQL的时候,就需要使用PreStatement类,使用其中的·setInt(index, content)
,setString()
等方法可以帮助我们将SQL语句中的占位符?
替换成我们想要的内容,在替换的同时也会进行数据的校验,这样就保证了数据的安全性。
- 执行SQL
使用PreStatement也可以执行execute
系列方法来执行SQL语句。其中execute
分成两种。
-
executeUpdate
:用于增加,删除,修改数据。返回值为int,表示有多少行收到了影响。 -
executeQuery
:用于查询数据。返回值为ResultSet,表示一张虚表,即查询出来的内容。 -
释放相关资源
- JDBC的DataSource会对Connection进行缓存,所以即使Connection对象被close掉了,但是底层并真的没有将连接释放掉,而是存放在一个地方,当下一次使用到的时候,可以直接拿出来用,而是不是重新进行一次连接。
以上5步就是JDBC的“套路”,其中只有3,4两步需要根据需求来改动,其余部分都是固定的。
案例展示
- 删除一条数据
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 TestJDBC2 {
public static void main(String[] args) throws SQLException {
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java_test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource) dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("xxx");
Connection connection = dataSource.getConnection();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入id:");
int id = scanner.nextInt(); // 输入:1
System.out.println("请输入name:");
String name = scanner.next(); // 输入:张三
System.out.println("请输入age:");
int age = scanner.nextInt(); // 输入:18
// 动态拼接sql语句
String sql = "insert into student values(?, ?, ?)";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setInt(1, id);
statement.setString(2, name);
statement.setInt(3, age);
// 打印结果:com.mysql.jdbc.JDBC42PreparedStatement@4bf558aa: insert into student values(1, '张三', 18)
System.out.println(statement);
int res = statement.executeUpdate();
System.out.println("res = " + res);
statement.close();
connection.close();
}
}
- 查询数据
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 testJDBC4 {
public static void main(String[] args) throws SQLException {
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java_test?character=utf8&useSSL=false");
((MysqlDataSource) dataSource).setUser("root");
((MysqlDataSource) dataSource).setPassword("zhy");
Connection connection = dataSource.getConnection();
String sql = "select * from student";
PreparedStatement statement = connection.prepareStatement(sql);
// resultSet是查询后的内容
ResultSet resultSet = statement.executeQuery();
// 使用next可以遍历每一行
while (resultSet.next()) {
// 使用resultSet中的getInt方法可以获得一行的对应的哪一列
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
System.out.println(id + "\t" + name + "\t" + age);
}
resultSet.close();
statement.close();
connection.close();
}
}
总结:
- 锁定数据库位置,创建DataSource示例
- 寻找数据库进行连接,创建Connection对象连接
- 写SQL,操作数据库
- 执行SQL
- 释放资源,关闭数据库Connection,PreStatement对象等资源