JDBC API是一个Java API可以访问任何类型的数据库的数据,尤其是存储在关系数据库中的数据。通过JDBC API可以方便地实现对各种主流数据库的操作。本篇将以MySQL为例,介绍一下如何使用JDBC操作数据库。
JDBC
-
客户端操作MySQL数据库的方式:
- 使用第三方客户端来访问 MySQL:Navicat、SQLWave、MyDB Studio、EMS SQL Manager for MySQL
- 使用 MySQL 自带的命令行方式
- 通过 Java 来访问 MySQL 数据库,本文要介绍的内容。
-
概念:Java DataBase Connectivity Java 数据库连接, Java语言操作数据库。
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。 -
使用JDBC的好处:
- 如果要开发访问数据库的程序,只需要会调用 JDBC 接口中的方法即可,不用关注类是如何实现的。
- 使用同一套 Java 代码,进行少量的修改就可以访问其他 JDBC 支持的数据库。
-
使用步骤:
使用JDBC主要有八个步骤,分别是:- 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
- 注册驱动
- 获取数据库连接对象 Connection
- 定义sql
- 获取执行sql语句的对象 Statement
- 执行sql,接受返回结果
- 处理结果
- 释放资源
下面举个例子来说明下这八个步骤。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class Demo1 {
public static void main(String[] args) throws Exception {
//0.首先导入jar包
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//3.获取数据库连接对象
Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/wbg_logistics","root","root");
//4.sql语句
String sql="update depart set dedpart_no=3 where dedpart_no=1";
//5.获取执行sql的对象 Statement
Statement stmt=conn.createStatement();
//6.执行sql
int count=stmt.executeUpdate(sql);
//7.打印结果
System.out.println("影响的行数:"+count);
//8.释放资源
stmt.close();
conn.close();
}
}
**注意:**报错Exception in thread “main” java.lang.ClassNotFoundException: com.mysql.jdbc.Driver:加载类的时候找不到该类,缺少对应的mysql-connector-java的jar包。
3.JDBC的核心API介绍:
-
DriverManager:管理和注册驱动,得到数据库连接对象。为什么
Class.forName(数据库驱动实现类)
可以注册驱动?因为Driver 接口是所有数据库厂商必须实现的接口,表示这是一个驱动类。com.mysql.jdbc.Driver 源代码如下:public class Driver implements java.sql.Driver { public Driver() throws SQLException { } static { try { DriverManager.registerDriver(new Driver()); //注册数据库驱动 } catch (SQLException var1) { throw new RuntimeException("Can't register driver!"); } } }
-
Connection:数据库连接对象,可用于创建 Statement 和 PreparedStatement 对象。
-
主要方法:
Connection 接口中的方法 描述 Statement createStatement() 创建一条 SQL 语句对象
-
-
Statement:执行sql的对象
-
主要方法
Statement 接口中的方法 描述 int executeUpdate(String sql) 用于发送 DML 语句,增删改的操作,insert、update、delete 参数:SQL 语句 返回值:返回对数据库影响的行数 ResultSet executeQuery(String sql) 用于发送 DQL 语句,执行查询的操作。select 参数:SQL 语句 返回值:查询的结果集
-
-
ResultSet:结果集对象,封装查询结果
ResultSet 接口中的方法 描述 boolean next() 1) 游标向下移动 1 行 2) 返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false 数据类型 getXxx()【比如boolean getBoolean】 1) 通过字段名,参数是 String 类型。返回不同的类型 2) 通过列号,参数是整数,从 1 开始。返回不同的类型
-
PreparedStatement:执行sql的对象,是 Statement 的子接口
- SQL注入问题:在拼接sql的时候,有一些sql的特殊关键字参与字符串的拼接,可能会造成安全问题。为了解决这个问题,使用PreparedStatement对象来解决。
- 预编译的SQL:参数使用?作为占位符
抽取JDBC工具类:JDBUtils
其实不难发现,当增删查改的时候按照这样的方法需要写很多遍连接数据库、加载驱动还有关闭资源等代码,因为这些功能经常用到,所以建议把它做成一个工具类,抽取出来,方便可以在不同的地方重用。
目录结构:
1.在src目录下新建一个文件mysql.properties,,user和password分别写用户和密码。localhost可以写ip地址(本机的和远程的都可以),3306是端口号。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/修改为自己索要连接的数据库名称
user=root
password=root
2.在src目录下新建dbConfig.java,主要是加载配置文件用的。
import java.io.FileInputStream;
import java.util.Properties;
public class dbConfig {
private static Properties p = null;
static {
try {
p = new Properties();
// 加载配置文件
p.load(new FileInputStream("src/mysql.properties"));
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取键对应的值ֵ
public static String getValue(String key) {
return p.get(key).toString();
}
}
3.在src下新建utils包,utils包中新建JDBCUtils.java,用来写连接数据库和释放资源等操作,后续也可以将CRUD的操作写在该文件中,简化操作。
import java.sql.*;
public class JDBUtils {
private static Connection conn = null;
private static ResultSet rs=null;
private static PreparedStatement pstmt=null;
/**
* 得到数据库连接
*/
public static Connection getConnection() throws ClassNotFoundException,
SQLException, InstantiationException, IllegalAccessException {
// 通过dbConfig获取数据库配置信息
String driver = dbConfig.getValue("driver");
String url = dbConfig.getValue("url");
String user = dbConfig.getValue("user");
String pwd = dbConfig.getValue("password");
try {
// 指定驱动程序
Class.forName(driver);
// 建立数据库连结
conn = DriverManager.getConnection(url, user, pwd);
return conn;
} catch (Exception e) {
// 如果连接过程出现异常,抛出异常信息
throw new SQLException("驱动错误或连接失败!");
}
}
/**
* 释放资源
*/
public static void closeAll() {
// 如果rs不空,关闭rs
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 如果pstmt不空,关闭pstmt
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 如果conn不空,关闭conn
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
JDBC控制事务
1.事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
2.相关操作:
- 开启事务
- 提交事务
- 回滚事务
3.使用Connection对象来管理事务
- 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务。
在执行sql之前开启事务
- 提交事务:commit()。
当所有sql都执行完提交事务
- 回滚事务:rollback() 。
在catch中回滚事务
4.例子
假设某银行中有这样两个用户A和B,A和B的账户余额均为3000元,因为某种不可抗拒的因素,账户A要给账户B转账500元,那么转账成功后A账户的余额应为2500元,B账户的余额应为3500.假设如果银行在A账户中划走了500元,此时银行划走的500元尚未转账给B账户就恰好出现了故障,程序抛出异常无法完成给B转账的工作,这样的情况不能称之为交易成功。那么基于这样的情况就需要回滚事务,把从A账户中划走的500元还给A。
import com.nayelya.utils.JDBUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement pst1=null;
PreparedStatement pst2=null;
String sql1="update my_account set balance=balance - ? where name=? ";
String sql2="update my_account set balance=balance + ? where name=? ";
try {
conn = JDBUtils.getConnection();
pst1=conn.prepareStatement(sql1);
pst2=conn.prepareStatement(sql2);
pst1.setDouble(1,500);
pst1.setString(2,"A");
/*假设此处出现异常*/
int res=6/0;
pst2.setDouble(1,500);
pst2.setString(2,"B");
pst1.executeUpdate();
pst2.executeUpdate();
} catch (SQLException e) {
try {
if(conn != null) {
conn.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBUtils.closeAll();
}
}
}