JDBC 基本概念
JDBC: Java DataBase Connectivity, 即 Java 数据库连接.
JDBC本质: 是官方定义的一套操作所有关系型数据库的规则, 即接口, 各个数据库厂商去实现这套接口, 提供数据库驱动 jar 包, 我们可以使用这套 (JDBC) 编程, 真正执行的代码是驱动 jar 包中的实现类.
使用 mysql jar 包操作数据库的步骤:
首先需在 mysql 上创建数据库
-
在项目里边导入 mysql jar 包, 注册驱动
-
获取数据库连接对象, 获取游标对象 cursor
-
组织 sql 语句
-
使用 cursor 执行 sql
-
处理结果
-
释放资源
demo:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; /** * JDBC 初步使用 */ public class ConnectDataBase { public static void main(String[] args) throws Exception { // 导入 mysql jar 包, 注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 获取数据库连接对象, 获取 cursor Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.0.115/JDBC", "username", "passwd"); Statement st = conn.createStatement(); // 写 sql String sql = "create table student(id int unsigned primary key auto_increment not null, name varchar(150))"; // 执行 sql int num = st.executeUpdate(sql); // 处理结果 // 执行成功返回 0, 再次执行: Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'student' already exists System.out.println(num); // 释放资源 st.close(); conn.close(); } }
JDBC 包中各个实现类详解
-
Class.forName("com.mysql.jdbc.Driver");
通过查看源码发现, 在 com.mysql.jdbc.Driver 类中存在静态代码块:
static { try { java.sql.DriverManager.registerDriver(new Dirver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
提示: mysql 1.5版本之后的 jar 包可以省略注册驱动的步骤 (会根据配置文件自动导入)
-
获取数据库连接
public static Connection getConnection(String url, String user, String password)
-
Statement createStatement();
PreparedStatement prepareStatement(String sql);
-
管理事务
开启事务: void setAutoCommit(boolean autoCommit);
提交事务: commit()
回滚事务: rollback()
Statement: 执行 sql 的对象
-
执行sql
int executeUpdate(String sql): 执行 DML (insert, update, delete) , DDL (create, alter, drop)
ResultSet executeQuery(String sql): 执行DQL (select)
boolean execute(String sql): 可以执行任意的sql (不常用)
ResultSet: 结果集对象
封装查询结果
常用方法:
-
boolean next(): 游标向下移动一行
-
int getInt(int columnIndex): 获取一个 int 类型的值 (传编号[编号从1开始] 或 列名)
-
int getInt(String columnLabel)
-
String getString(int columnIndex): 获取一个 String 类型的值 (传编号 或 列名)
-
String getString(String columnLabel)
PreparedStatement: 执行 sql 的对象
使用 PreparedStatement 对象能解决 sql 注入的问题,
JDBC 操作数据库练习
插入一条数据:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * 使用 JDBC 插入一条数据 */ public class JdbcDemo01 { public static void main(String[] args) { Connection conn = null; Statement st = null; try { // 1.注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 2.编写sql String sql = "insert into student values(null, 'johny')"; // 3.获取数据库连接 conn = DriverManager.getConnection("jdbc:mysql://192.168.0.115:3306/JDBC", "username", "passwd"); // 4.获取statement操作对象 st = conn.createStatement(); // 5.执行sql int num = st.executeUpdate(sql); // 6.处理sql执行结果 System.out.println(num); // 1 } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { // 7.释放资源 try { st.close(); } catch (SQLException e) { e.printStackTrace(); } try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
查询一条数据:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.sql.ResultSet; /** * 使用 JDBC 查询一条数据 */ public class JdbcDemo01 { public static void main(String[] args) { Connection conn = null; Statement st = null; ResultSet ret = null; try { // 1.注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 2.编写sql String sql = "select * from student"; // 3.获取数据库连接 conn = DriverManager.getConnection("jdbc:mysql://192.168.0.115:3306/JDBC", "username", "passwd"); // 4.获取statement操作对象 st = conn.createStatement(); // 5.执行sql ret = st.executeQuery(sql); // 6.处理sql执行结果 ret.next(); int id = ret.getInt(1); String name = ret.getString("name"); System.out.println(String.format("id: %s, name: %s", id, name)); // id: 1, name: johny } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { // 7.释放资源 try { ret.close(); } catch (SQLException e) { e.printStackTrace(); } try { st.close(); } catch (SQLException e) { e.printStackTrace(); } try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
抽取 JDBC 工具类
步骤:
-
封装 JDBCUtils 工具类
-
通过 properties 配置文件来读取数据库连接信息
-
通过静态代码块来初始化, 连接到数据库
-
封装释放资源的静态方法
jdbc.properties:
ipaddr=192.168.0.115
port=3306
dbname=JDBC
username=chenkai
passwd=chenkai
JDBCUtils:

import java.sql.*; import java.util.Properties; import java.io.IOException; import java.io.FileReader; import java.net.URL; /** * 封装 JDBC 的工具类 */ public class JDBCUtils { private static String ipaddr; private static String port; private static String dbname; private static String username; private static String passwd; static { try { // 读取配置文件, 初始化连接数据库 Properties pro = new Properties(); // 获取 src 路径下的文件 --> ClassLoader ClassLoader cl = JDBCUtils.class.getClassLoader(); URL url = cl.getResource("jdbc.properties"); String path = url.getPath(); // 配置文件的绝对路径 // 加载配置文件 pro.load(new FileReader(path)); // 获取配置文件中的参数 ipaddr = pro.getProperty("ipaddr"); port = pro.getProperty("port"); dbname = pro.getProperty("dbname"); username = pro.getProperty("username"); passwd = pro.getProperty("passwd"); } catch (IOException e) { e.printStackTrace(); } } // 获取连接 public static Connection getConnection(){ try { // 注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 获取连接 Connection conn = DriverManager.getConnection(String.format("jdbc:mysql://%s:%s/%s", ipaddr, port, dbname), username, passwd); return conn; } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } // return null; } public static void close(ResultSet ret, Statement statement, Connection conn){ if (ret!=null) { try { ret.close(); } catch (SQLException e) { e.printStackTrace(); } } if (statement!=null) { try { ret.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn!=null) { try { ret.close(); } catch (SQLException e) { e.printStackTrace(); } } } public static void close(PreparedStatement pstatement, Connection conn){ if (pstatement!=null) { try { pstatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn!=null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
demo:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.sql.ResultSet; /** * 使用 JDBC 查询一条数据 */ public class JdbcDemo01 { public static void main(String[] args) { Connection conn = null; Statement st = null; ResultSet ret = null; try { // 1.获取数据库连接 conn = JDBCUtils.getConnection(); // 2.编写sql String sql = "select * from student"; // 4.获取statement操作对象 st = conn.createStatement(); // 5.执行sql ret = st.executeQuery(sql); // 6.处理sql执行结果 ret.next(); int id = ret.getInt(1); String name = ret.getString("name"); System.out.println(String.format("id: %s, name: %s", id, name)); } catch (SQLException e) { e.printStackTrace(); } finally { // 7.释放资源 JDBCUtils.close(ret, st, conn); } } }
使用 PreparedStatement 对象执行sql的步骤:
-
导入驱动包
-
获取数据库连接对象
-
定义 sql (使用 ? 作为占位符)
-
获取sql执行对象 (PreparedStatement)
-
给 ? 赋值(setInt, setString... 传递两个参数, 位置和值, 位置从 1 开始)
-
执行sql (不需要再传递 sql 语句)
-
处理结果
-
释放资源
后边操作数据库都用 PreparedStatement 对象来完成增删改查的所有操作
模拟用户登录, 处理 sql 注入问题:
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Scanner; /** * 模拟用户登录, 处理sql注入问题 */ public class UserLogin { public Connection conn = null; public PreparedStatement pstat = null; public ResultSet ret = null; public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("请输入用户名:"); String username = sc.nextLine(); System.out.print("请输入密码:"); String passwd = sc.nextLine(); boolean ret = new UserLogin().login(username, passwd); if (ret) { System.out.println("登录成功"); } else { System.out.println("用户名或密码输入错误!"); } } public boolean login(String username, String passwd){ if (username == null | passwd == null) { return false; } try{ // 通过 JDBCUtils 获取数据库连接 conn = JDBCUtils.getConnection(); // 拼写sql String sql = "select * from user where username = ? and passwd = ?"; // 获取 PreparedStatement 对象 pstat = conn.prepareStatement(sql); // 给 sql 赋值 pstat.setString(1, username); pstat.setString(2, passwd); // 执行 sql ret = pstat.executeQuery(); // 处理结果 return ret.next(); } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtils.close(ret, pstat, conn); } return false; } }
JDBC 控制事务
事务: 它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的操作单位.
使用 Connection 对象来管理事务
-
开启事务: setAutoCommit(boolean autoCommit): 调用该方法设置参数为 false, 即开启事务
执行 sql 前开启事务.
-
提交事务: commit()
所有 sql 都执行完提交事务.
-
回滚事务: rollback()
在 catch 中回滚事务.
demo:
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * JDBC 事务的应用, 模拟转账 */ public class JdbcDemo02 { public static void main(String[] args) { Connection conn = null; PreparedStatement pstat1 = null; PreparedStatement pstat2 = null; try { // 获取数据库连接 conn = JDBCUtils.getConnection(); // 开启事务!!! conn.setAutoCommit(false); // 编写sql String sql1 = "update user set balance = balance - 500 where username = ?"; String sql2 = "update user set balance = balance + 500 where username = ?"; // 获取 preparedStatement 对象 pstat1 = conn.prepareStatement(sql1); pstat2 = conn.prepareStatement(sql2); // 给 sql 赋值 pstat1.setString(1, "xiaoming"); pstat2.setString(1, "xiaohong"); // 执行sql pstat1.executeUpdate(); pstat2.executeUpdate(); //手动抛出异常 int a = 3 / 0; // 提交事务 conn.commit(); System.out.println("处理完成"); } catch (Exception e) { e.printStackTrace(); // 回滚事务, 数据库连接不为空的时候进行回滚 (不会滚也不会更新成功, 回滚是不是在释放资源 ?) if (conn != null) { try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } } finally { // 释放资源 JDBCUtils.close(pstat1, conn); JDBCUtils.close(pstat2, null); } } }
ending ~