JDBC规范定义接口,具体的实现由各大数据库厂商来实现。
JDBC是Java访问数据库的标准规范,真正的怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的驱动。所以只需要会调用JDBC接口中的方法即可,数据库驱动由数据库厂商提供
会使用到的包 | 说明 |
---|---|
java.sql | 所有与JDBC访问数据库相关的接口和类 |
javax.sql | 数据库扩展,提供数据库额外的功能。 |
数据库的驱动 | 由各大数据库厂商提供,需要额外去下载,是对JDBC接口实现的类 |
接口或类 | 作用 |
---|---|
DriverManager类 | 1. 管理和注册数据库驱动;2. 得到数据库连接对象 |
Connection 接⼝ | ⼀个连接对象,可⽤于创建 Statement 和 PreparedStatement对象 |
Statement 接⼝ | ⼀个 SQL 语句对象,⽤于将 SQL 语句发送给数据库服务器。 |
PreparedStatement 接⼝ | ⼀个 SQL 语句对象,是 Statement 的⼦接⼝ |
ResultSet 接⼝ | ⽤于封装数据库查询的结果集,返回给客户端 Java 程序 |
加载和注册驱动的⽅法 | 描述 |
---|---|
Class.forName(数据驱动实现类) | 加载和注册数据库驱动,数据库驱动由数据库厂商实现; MySQL ⼚商: “com.mysql.jdbc.Driver” |
public class Demo1 { public static void main(String[] args) throws ClassNotFoundException { //抛出类找不到的异常,注册数据库驱动 Class.forName("com.mysql.jdbc.Driver"); } }
从JDBC3开始,目前已经普遍使用的版本,可以不用注册驱动而直接使用,Class.forName这句话可以省略
DriverManager类中的静态方法 | 描述 |
---|---|
Connection getConnection(String url, String user,String password) | 通过连接字符串,⽤户名,密码来得到数据库的连接对象 |
Connection getConnection (String url, Properties info) | 通过连接字符串,属性对象来得到连接对象 |
JDBC连接数据库的四个参数 | 说明 |
---|---|
⽤户名 | 登录的⽤户名 |
密码 | 登录的密码 |
连接字符串 URL | 不同的数据库 URL 是不同的,mysql 的写法jdbc:mysql://localhost:3306/数据库[?参数名=参数值] |
驱动类的字符串名 | com.mysql.jdbc.Driver |
URL用于标识数据库的位置,程序员通过URL地址
JDBC程序连接哪个数据库,URL的写法为:
jdbc:mysql://localhost:3306/test?参数=参数值
注:jdbc:协议;
mysql:子协议;
localhost:3306: 主机:端口
test:子协议
前提:必须是本地服务器,端口号是3306
jdbc:mysql:///数据库名
如果数据库出现乱码,可以指定参数:?characterEncoding=utf8,表示让数据库以UFT-8编码来处理数据。
jdbc:mysql://localhost:3306/数据库?characterEncoding=utf8
流程:
Connection接口,具体的实现类由数据库的厂商实现,代表一个连接对象。
Connection接口中的方法:
Statement createStatement() -- 创建一条SQL语句对象
代表一条语句对象,用于发送SQL语句给服务器,用于执行静态SQL语句并返回它所生成结果的对象。
Statement接口中的方法 | 描述 |
---|---|
int executeUpdate(String sql) | 用于发送DML语句,增删改的操作,insert、update、delete 参数:SQL语句 返回值:返回对数据库影响的行数 |
ResultSet executeQuery(String sql) | 用于发送DQL语句,执行查询的操作select 参数:SQL语句 返回值:查询的结果集 |
步骤:
步骤:
作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录
接口中的方法
ResultSet 接⼝中的⽅法 | 描述 |
---|---|
boolean next() | 1. 游标向下移动 1 ⾏;2. 返回 boolean 类型,如果还有下⼀条记录,返回 true,否则返回 false |
数据类型 getXxx() | 1. 通过字段名,参数是 String 类型。返回不同的类型;2. 通过列号,参数是整数,从 1 开始。返回不同的类型 |
注:java.sql.Date、Time、Timestamp(时间戳),三个共同⽗类是:java.util.Date
确保数据库中有3条以上的记录,查询所有的学员信息
上述知识要点整合代码: import java.sql.*; public class JDBCDemo01 { public static void main(String[] args) { try { //可能出现的异常:ClassNotFoundException /*原因: * 1.java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Drive 类名写错 * 2.jar包未导入 * */ Class.forName("com.mysql.cj.jdbc.Driver"); //3.可能出现的异常:获得数据库连接 /*SQLException * 原因:1.jdbc:mysql: 其中任何一段字符串写错, ip地址协议错误 * 2. Unknown database xxxx 数据库名字错误 找不到这个数据库 * 3.SQLException: Access denied for user 'roo'@'localhost' (using password: YES) 数据库用户名或密码错误 * com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure localhost:330 * 原因:端口错误,防火墙阻拦 *ip地址出错,不会抛出异常,程序会阻塞,一直尝试连接 * */ String url = "jdbc:mysql://localhost:3306/java2106"; Connection connection = DriverManager.getConnection(url,"root","123456"); //System.out.println(connection); //4.获得执行SQL语句的Statement对象 Statement statement = connection.createStatement(); //执行DDL 通常用execute /*String sql = "create table test01(id int(6) PRIMARY KEY)"; boolean execute = statement.execute(sql); System.out.println(execute);*/ /*//执行DML 通常用executeUpdate 如果增删改成功则返回1,增删改失败则返回0 String sql = "update test01 set id = 1"; int i = statement.executeUpdate(sql); System.out.println(i);*/ //5.执行DQL获得 ResultSet String sql = "select * from emp"; //执行可能发生的异常SQLSyntaxErrorException 一般是sql语句出现异常,根据具体信息修改异常 ResultSet rs = statement.executeQuery(sql); //处理结果集 rs.next() boolean 移动到下一个位置,判断是否存在字段,如果存在则返回true while (rs.next()){ int empno = rs.getInt("empno"); String ename = rs.getString("ename"); Date hiredate = rs.getDate("hiredate"); System.out.println(empno + " " + ename + " " + hiredate); } //上述代码使得next()指向了结果集的最后行,再下一个则会超出范围 //SQLException: After end of result set /*int no = rs.getInt("empno"); String name = rs.getString("ename"); Date hireDate = rs.getDate("hiredate"); System.out.println(no + name + hireDate);*/ //关闭资源 rs.close(); statement.close(); connection.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
一些注意事项整理 import java.sql.*; public class JDBCDemo02 { public static void main(String[] args) { try { Connection connection = JDBCUtils.getConnection(); //4.获得执行SQL语句的Statement对象 Statement statement = connection.createStatement(); String sql = "select * from emp"; ResultSet rs = statement.executeQuery(sql); //处理结果集 rs.next() boolean 移动到下一个位置,判断是否存在字段,如果存在则返回true while (rs.next()){ /*int empno = rs.getInt("empno"); String ename = rs.getString("ename"); Date hiredate = rs.getDate("hiredate"); System.out.println(empno + " " + ename + " " + hiredate);*/ Emp emp = new Emp(); emp.setEmpno(rs.getInt("empno")); } //上述代码使得next()指向了结果集的最后行,再下一个则会超出范围 //SQLException: After end of result set /*int no = rs.getInt("empno"); String name = rs.getString("ename"); Date hireDate = rs.getDate("hiredate"); System.out.println(no + name + hireDate);*/ //关闭资源 rs.close(); statement.close(); connection.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
自己创建工具类:
如果一个功能经常要用到,建议把这个功能做成一个工具类,可以再不同的地方重用。
出现很多的重复的代码,可以把这些公共代码抽取出来。
可以把几个字符串定义成常量:用户名,密码,URL,驱动类
得到数据库的连接:getConnection()
关闭所有打开的资源
close(Connection conn, Statement stmt),close(Connection conn, Statement stmt, ResultSet rs)
得到用户从控制台上输入的用户名和密码来查询数据库
写一个登陆方法
a. 通过工具类得到连接
b. 创建语句对象,使用拼接字符串的方式生成SQL语句
c. 查询数据库,如果有记录则登陆成功,否则登录失败
d. 释放资源
用户输入的密码和SQL语句的字符串拼接。用户输入的内容作为SQL语句语法的一部分,改变了原有SQL真正的意义,以上问题称为SQL注入,要解决SQL注入就不能让用户输入的密码和我们的SQL语句进行简单的字符串拼接。
接口:Statement、Wrapper
所有已知子接口:
CallableStatement
preparedStatement是Statement接口的子接口,继承于父接口中所有的方法。它是一个预编译的SQL语句。
作用:
Connection 接⼝中的⽅法 | 描述 |
---|---|
PreparedStatement prepareStatement(String sql) | 指定预编译的 SQL 语句,SQL 语句中使⽤占位符?创建⼀个语句对象 |
PreparedStatement 接⼝中的⽅法 | 描述 |
---|---|
int executeUpdate() | 执⾏ DML,增删改的操作,返回影响的⾏数。 |
ResultSet executeQuery() | 执⾏ DQL,查询的操作,返回结果集 |
PreparedStatement 中设置参数的⽅法 | 描述 |
---|---|
void setDouble(int parameterIndex, double x) | 将指定参数设置为给定 Java double值。 |
void setFloat(int parameterIndex, float x) | 将指定参数设置为给定 Java float 值。 |
void setInt(int parameterIndex, int x) | 将指定参数设置为给定 Java int 值。 |
void setLong(int parameterIndex, long x) | 将指定参数设置为给定 Java long 值。 |
void setObject(int parameterIndex, Object x) | 使⽤给定对象设置指定参数的值。 |
void setString(int parameterIndex, String x) | 将指定参数设置为给定 Java String 值。 |
import java.sql.*; import java.util.Scanner; public class LoginDemo02 { public static void main(String[] args) throws Exception { Scanner scanner = new Scanner(System.in); System.out.println("请输入用户名:"); String username = scanner.nextLine(); System.out.println("请输入密码:"); String password = scanner.nextLine(); Connection connection = JDBCUtils.getConnection(); String sql = "select * from user where username=? and password=?"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1,username); preparedStatement.setString(2,password); //String sql = "select * from user where username = '" + username +"' and password = '"+ password +"'"; ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()){ System.out.println("用户登陆成功"); }else { System.out.println("用户名或密码错误"); } resultSet.close(); preparedStatement.close(); connection.close(); } }
Connection 接⼝中与事务有关的⽅法 | 说明 |
---|---|
void setAutoCommit(boolean | |
autoCommit) | 参数是 true 或 false。如果设置为 false,表示关闭⾃动提交,相当于开启事务 |
void commit() | 提交事务 |
void rollback() | 回滚事务 |
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class Demo04 { public static void main(String[] args) { Connection connection = JDBCUtils.getConnection();//连接 String sql1 = "update customer set account = account - ? where cust_id = ?";//转出 String sql2 = "update customer set account = account + ? where cust_id = ?";//转入 try { //事务手动提交设置 connection.setAutoCommit(false); PreparedStatement statement1 = connection.prepareStatement(sql1); PreparedStatement statement2 = connection.prepareStatement(sql2); statement1.setInt(1,100); statement1.setInt(2,1); statement1.executeUpdate(); //出现异常 //int i = 1/0; statement2.setInt(1,100); statement2.setInt(2,2); statement2.executeUpdate(); //转账入账的流程结束,提交事务,事务流程结束 connection.commit(); } catch (SQLException throwables) { try { //如果出现异常就对事务进行回滚,结束事务 connection.rollback(); } catch (SQLException e) { e.printStackTrace(); } } } }
import java.io.*; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class JDBCUtils { private static String url; private static String username; private static String password; private static String driver; static { Properties pro = new Properties(); try { pro.load(JDBCUtils.class.getResourceAsStream("jdbc.properties")); url = pro.getProperty("jdbc.url"); username = pro.getProperty("jdbc.username"); password = pro.getProperty("jdbc.password"); driver = pro.getProperty("jdbc.driver"); Class.forName(driver); }catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection(){ try { return DriverManager.getConnection(url,username,password); } catch (SQLException throwables) { throwables.printStackTrace(); return null; } } }
jdbc.driver = com.mysql.cj.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/java2106 jdbc.username = root jdbc.password = 123456