JDBC
Java数据库连接(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
值得注意的是:JDBC仅仅是一个规范而不是一个实现。意思是各种不同类型的数据库都依这种规范有相应的实现,它们之间的具体实现都是由java类和接口组成。本文中的代码都是针对MySQL数据库实现的。
JDBC常用对象
API | 说明 | 通俗理解 |
---|---|---|
java.sql.Connection | 与特定数据库的连接。能通过getMetaData方法获得数据库提供的信息,所支持的SQL语法、存储过程和此连接的功能等信息。代表了数据库。 | 获得了Connection对象,就相当于连接通了数据库 |
java.sql.Driver | 每个驱动程序类必需实现的接口,同时,每个数据库驱动程序都应该提供一个实现Driver接口的类。 | |
java.sql.DriverManager(Class) | 管理一组JDBC驱动程序的基本服务。作为初始化的一部分,此接口会尝试加载在"jdbc.drivers"系统属性中引用的驱动程序.只是一个辅助类,是工具。 | 是为了获取Connection对象的辅助类 |
java.sql.Statement | 用于执行静态SQL语句并返回其生成结果的对象 | 执行静态sql语句 |
java.sql.PreparedStatement | 继承Statement接口,表示预编译的SQL语句的对象,SQL语句被预编译并且存储在PreparedStatement对象中。然后可以使用此对象高效地多次执行该语句。 | 更加高效的执行sql语句 |
java.sql.CallableStatement | 用来访问数据库中的存储过程。它提供了一些方法来指定语句所使用的输入、输出参数。 | |
java.sql.ResultSet | 指的是查询返回的数据库结果集。 | 封装查询语句返回的结果 |
java.sql.ResultSetMetaData | 可用于获取关于ResultSet对象中列的类型和属性信息的对象。 |
表格参考:https://blog.youkuaiyun.com/weixin_43691058/article/details/103907259
JDBC编程步骤
在此处我使用的是maven
所快速搭建的项目。
1、导入依赖
当 A jar 包用到了 B jar 包中的某些类时,A 就对 B 产生了依赖。在项目中以依赖的方式引入一个我们需要的 jar 包,只需要使用 dependency
标签指定被依赖 jar 包的坐标就可以了。如果我们将maven
的镜像配置文件更改为了阿里云,那么我们就可以直接去阿里仓库寻找我们所需要的依赖。
2、参数配置
//参数配置
private String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
private String useName; //用户名
private String passWord; //密码
private String jdbcDriver = "com.mysql.jdbc.Driver"; //jdbc驱动
private Connection connection; //JDBC与MySQL所建立的连接
url
:确定我们所需要连接的数据库。jdbc:mysql
:和mysql建立连接时使用的协议。127.0.0.1
:mysql服务器所在的ip地址。(此处为本机)3306
:mysql服务器所在的端口号。(此处为MySQL的默认端口)test
:即需要操作的数据库名。
useName
:即登录数据库时所需要的用户名。passWord
:即登录数据库时所需要的密码。jdbcDriver
:使用jdbc时所需要的驱动。
3、加载驱动
Class.forName(jdbcDriver); //加载驱动
4、建立连接
connection = DriverManager.getConnection(url,useName,passWord); //建立连接
加载驱动与建立连接的完整代码:
//加载驱动(驱动加载完成后就可以使用JDBC了)
//建立连接
public void createConnection(){
try {
Class.forName(jdbcDriver); //加载驱动
try {
connection = DriverManager.getConnection(url,useName,passWord); //建立连接
//getConnection方法就是JDBC提供给我们建立连接的方法
//即登录到MySQL服务器的过程
if(!connection.isClosed()){
//判断是否成功建立连接
System.out.println("连接建立成功");
}else {
System.out.println("连接建立失败");
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
5、操作数据库
在这里,JDBC提供了两种操作数据库的对象:Statement 和 PreparedStatement。它们两个的介绍可以看上面的表格。
我们需要注意的是:
当同结构的SQL语句执行多次时,使用PrePareStatement创建对象的执行效率要比使用Statement创建对象的效率高得多。原因是用PrePareStatement创建对象只编译一次,下一次传值只从解析树之后的操作进行,而使用Statement创建对象每次都需要从头编译。
但并不是使用PrePareStatement创建对象的执行效率总比使用Statement创建对象的效率高,当一个结构的SQL语句只执行一次时,用Statement创建对象的执行效率要比使用PrePareStatement创建对象的效率高,原因是用Statement创建对象会直接执行完一条SQL语句,而用PrePareStatement创建对象会在判断SQL语句没有问题后停止线程等待参数传递,此时会使效率低下。
因此在不同的使用场景下要使用不同的对象。其实在实际操作过程中,更多的是使用PrePareStatement创建对象,原因是使用Statement创建对象容易产生SQL注入异常。
而对于正常的操作数据库而言,两者的操作基本是相同的:
- 对数据造成改变的,如insert、update、delete,我们使用的是executeUpdate();方法。
- 对数据不造成改变的,如select,我们使用的是executeQuery();方法。
- 当我们进行select查询语句时,jdbc会给我们返回ResultSet类型的集合,即查询到的结果集的集合。此时,我们需要通过遍历集合的方法达到查询的操作,例如:while (resultSet.next()); //resultSet.next()判断集合中是否还有数据。
以插入数据为例,我们来看看Statement 和 PreparedStatement两种对象在具体操作上有什么不同。
Statement对象
//操作数据库(增删改查操作)
public void insertTest(){ //update delete
String insertSql = "insert into jdbc_test values(1,'jdbc_test')";
try {
statement.executeUpdate(insertSql);
//executeUpdate方法是所有会对数据库数据进行修改的统一方法
} catch (SQLException e) {
e.printStackTrace();
}
}
我们可以看到,statement对象需要将SQL语句完整的写出来,再进行SQL语句的执行。
PreparedStatement对象
//操作数据库(增删改查操作)
public void insertTest(){ //update delete
String insertSql = "insert into jdbc_test values(?,?)"; //定义无参的SQL语句
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(insertSql); //将无参的SQL语句提交给MySQL
//根据字段的不同数据类型给无参的SQL语句提交参数
pre.setInt(1,2);
pre.setString(2,"jdbc_pre");
pre.executeUpdate(); //执行SQL语句
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
pre.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
我们可以看到,PreparedStatement对象会先对无参的SQL语句进行解析,完成后再进行传值,此时就会避免SQL注入异常
,大大的提高了数据库的安全性。
6、关闭数据库连接
connection.close(); //当不再使用数据库时,关闭JDBC连接避免资源浪费
//关闭数据库连接
public void closeConnection(){
try {
connection.close(); //当不再使用数据库时,关闭JDBC连接避免资源浪费
if(connection.isClosed()){
System.out.println("连接已关闭");
}else {
System.out.println("连接关闭失败");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
JDBC操作事务
我们都知道MySQL的事务也是数据库中常用的操作,关于MySQL的事务可以查看MySQL事务。
在这里,我们来用Java代码来测试一下事务的实现。
1、进行MySQL数据库的连接
见上面的JDBC编程步骤。
2、开启事务
connection.setAutoCommit(false); //开启事务(相当于 SET AUTOCOMMIT = 0;)
3、设置事务的隔离级别
//开启事务的隔离级别(相当于 set session transaction isolation level READ COMMITTED;)
//此处更改隔离级别为序列化级别
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
具体代码:
//加载驱动(驱动加载完成后就可以使用JDBC了)
//建立连接
public void createConnection(){
try {
Class.forName(jdbcDriver); //加载驱动
try {
connection = DriverManager.getConnection(url,useName,passWord); //建立连接
//getConnection方法就是JDBC提供给我们建立连接的方法
//即登录到MySQL服务器的过程
if(!connection.isClosed()){
//判断是否成功建立连接
System.out.println("连接建立成功");
connection.setAutoCommit(false); //开启事务(相当于 SET AUTOCOMMIT = 0;)
//开启事务的隔离级别(相当于 set session transaction isolation level READ COMMITTED;)
//此处更改隔离级别为序列化级别
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
}else {
System.out.println("连接建立失败");
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
4、回滚操作测试
//事务的回滚方法测试
public void rollbackTest(){
String selectSql = "select * from jdbc_test";
String insertSql = "insert into jdbc_test values(?,?)";
PreparedStatement selectPre = null,insertPre = null;
try {
selectPre = connection.prepareStatement(selectSql);
insertPre = connection.prepareStatement(insertSql);
} catch (SQLException e) {
e.printStackTrace();
}
selectTest(selectPre);
insertTest(insertPre,3,"jdbc_test");
insertTest(insertPre,4,"jdbc_test");
selectTest(selectPre);
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
selectTest(selectPre);
}
public static void main(String[] args) {
JDBC_Tran jdbc = new JDBC_Tran();
jdbc.createConnection();
jdbc.rollbackTest();
jdbc.closeConnection();
}
测试结果:
5、提交操作测试
//事务的提交操作测试
public void commitTest(){
String selectSql = "select * from jdbc_test";
String insertSql = "insert into jdbc_test values(?,?)";
PreparedStatement selectPre = null,insertPre = null;
try {
selectPre = connection.prepareStatement(selectSql);
insertPre = connection.prepareStatement(insertSql);
} catch (SQLException e) {
e.printStackTrace();
}
selectTest(selectPre);
insertTest(insertPre,3,"jdbc_test");
insertTest(insertPre,4,"jdbc_test");
selectTest(selectPre);
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
selectTest(selectPre);
}
public static void main(String[] args) {
JDBC_Tran jdbc = new JDBC_Tran();
jdbc.createConnection();
jdbc.commitTest();
jdbc.closeConnection();
}
测试结果:
6、保存点回滚操作
//设置保存点、退回保存点测试
public void pointTest(){
String selectSql = "select * from jdbc_test";
String insertSql = "insert into jdbc_test values(?,?)";
PreparedStatement selectPre = null,insertPre = null;
try {
selectPre = connection.prepareStatement(selectSql);
insertPre = connection.prepareStatement(insertSql);
} catch (SQLException e) {
e.printStackTrace();
}
selectTest(selectPre);
insertTest(insertPre,3,"jdbc_test");
insertTest(insertPre,4,"jdbc_test");
try {
Savepoint point1 = connection.setSavepoint("p1");
insertTest(insertPre,5,"jdbc_test");
insertTest(insertPre,6,"jdbc_test");
selectTest(selectPre);
connection.rollback(point1);
selectTest(selectPre);
} catch (SQLException e) {
e.printStackTrace();
}
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JDBC_Tran jdbc = new JDBC_Tran();
jdbc.createConnection();
jdbc.pointTest();
jdbc.closeConnection();
}
测试结果:
7、关闭连接
见上面的JDBC编程步骤。
JDBC实现:
public class JDBC {
//导入jdbc的MySQL依赖 -> pom.xml
//参数配置
private String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
private String useName;
private String passWord;
private String jdbcDriver = "com.mysql.jdbc.Driver"; //jdbc驱动
private Connection connection; JDBC与MySQL所建立的连接
//加载驱动(驱动加载完成后就可以使用JDBC了)
//建立连接
public void createConnection(){
try {
Class.forName(jdbcDriver); //加载驱动
try {
connection = DriverManager.getConnection(url,useName,passWord); //建立连接
//getConnection方法就是JDBC提供给我们建立连接的方法
//即登录到MySQL服务器的过程
if(!connection.isClosed()){
//判断是否成功建立连接
System.out.println("连接建立成功");
}else {
System.out.println("连接建立失败");
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//开启或者关闭事务
public void setAutoCommit(){
try {
if(!connection.isClosed()){
if(connection.getAutoCommit()){
connection.setAutoCommit(false); //开启事务
System.out.println("当前事务已开启");
}else {
connection.setAutoCommit(true); //关闭事务
System.out.println("当前事务已关闭");
}
}else {
System.out.println("当前数据库未连接");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//更改事务的隔离级别
public void setTransactionIsolation(int level){
try {
if(!connection.getAutoCommit()){
connection.setTransactionIsolation(level);
}else {
System.out.println("当前事务未开启");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//操作数据库(增删改查操作)
//插入数据
public void insertTest(int id,String name){ //update delete
String insertSql = "insert into jdbc_test values(?,?)"; //定义无参的SQL语句
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(insertSql); //将无参的SQL语句提交给MySQL
//根据字段的不同数据类型给无参的SQL语句提交参数
pre.setInt(1,id);
pre.setString(2,name);
pre.executeUpdate(); //执行SQL语句
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
pre.close();
dataToDetermine();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//删除数据
public void deleteTest(int id){
String deleteSql = "delete from jdbc_test where id = ?";
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(deleteSql);
pre.setInt(1,id);
pre.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
pre.close();
dataToDetermine();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//更改数据
public void updateTest(int id,String name){
String updateSql = "update jdbc_test set name = ? where id = ?";
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(updateSql);
pre.setString(1,name);
pre.setInt(2,id);
pre.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
pre.close();
dataToDetermine();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//查询数据
public void selectTest(){
String selectSql = "select * from jdbc_test";
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(selectSql);
ResultSet resultSet = pre.executeQuery(); //resultSet查询到的结果集的集合
//executeQuery方法是执行查询操作的专用方法
//通过遍历集合的方法达到查询的操作
while (resultSet.next()){ //resultSet.next()判断集合中是否还有数据
System.out.println("id:"+resultSet.getString(1)
+" name:"+resultSet.getString(2));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
pre.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println();
}
//当开启事务时进行提交操作
public void dataToDetermine(){
try {
if(connection.getAutoCommit()){
return;
}else {
System.out.print("是否正式提交SQL语句(yes/no):");
Scanner scanner = new Scanner(System.in);
String input = scanner.next();
if(input.equals("yes") || input.equals("y")){
connection.commit();
}else {
connection.rollback();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭数据库连接
public void closeConnection(){
try {
connection.close(); //当不再使用数据库时,关闭JDBC连接避免资源浪费
if(connection.isClosed()){
System.out.println("连接已关闭");
}else {
System.out.println("连接关闭失败");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}