JDBC的简介
- JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
- JDBC可以在各种平台上使用Java,如Windows,Mac OS和各种版本的UNIX。
- JDBC库包括与数据库使用相关的API。
JDBC体系结构
- JDBC API支持用于数据库访问的两层和三层处理模型,但通常,JDBC体系结构由两层组成:
- JDBC:提供了应用程序到数据库连接规范。
- JDBC驱动程序:连接数据库的驱动程序的实现。
JDBC核心组件
DriverManager: 此类管理数据库驱动程序列表。使用通信协议将来自java应用程序的连接请求与适当的数据库驱动程序匹配。 Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互。而是使用DriverManager对象来管理这种类型的对象。 Connection:该接口具有用于连接数据库的所有方法。连接对象表示通信上下文,数据库的所有通信仅通过连接对象。 Statement:使用从此接口创建的对象将SQL语句提交到数据库。除了执行存储过程之外,一些派生接口还接受参数。 ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为一个迭代器,允许我们移动其数据。 SQLException:此类处理数据库应用程序中发生的任何异常。
JDBC初始
使用步骤
(1) 导入JDBC驱动包:需要下载包含数据库编程所需的JDBC的jar包。
- 在项目下创建lib目录,右击目录,选择Add as Library
(2) 注册JDBC驱动程序:要求您初始化驱动程序,以便您可以打开与数据库的通信通道。
- 代码示例:
//两种方式注册驱动 1. Class.forName("com.mysql.jdbc.Driver");//(推荐使用) 2. Driver myDriver = new com.mysql.jdbc.Driver(); DriverManager.registerDriver( myDriver );
(3) 创建连接:需要使用
DriverManager.getConnection()
方法创建一个Connection
对象,该对象表示与数据库的物理连接。
- 三个重载的DriverManager.getConnection()方法:
- getConnection(String url)
- getConnection(String url,Properties prop)
- getConnection(String url,String user,String password)
RDBMS JDBC驱动程序名称 连接字符串格式 MySQL的 com.mysql.jdbc.Driver jdbc:mysql://hostname:3306 / databaseName ORACLE oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@ hostname:port Number:databaseName DB2 COM.ibm.db2.jdbc.net.DB2Driver jdbc:db2:hostname:port Number / databaseName SYBASE com.sybase.jdbc.SybDriver jdbc:sybase:Tds: hostname:port Number / databaseName
- 代码示例:
//也可以使用jdbc:mysql:///xxx //三个斜杠代表“localhost:3306 String URL = "jdbc:mysql://localhost:3306/xxx"; String USER = "root"; String PASS = "root" Connection conn = DriverManager.getConnection(URL, USER, PASS);
(4) 执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
- 代码示例:
Statement stmt = conn.createStatement( );
- 创建Statement对象后,您可以使用它来执行一个SQL语句,其中有三个执行方法之一。
- boolean execute(String SQL):如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。
- int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响多个行的SQL语句,例如INSERT,UPDATE或DELETE语句。
- ResultSet executeQuery(String SQL):返回一个ResultSet对象。当您希望获得结果集时,请使用此方法,就像使用SELECT语句一样。
关闭Statement对象
- 就像我们关闭一个Connection对象以保存数据库资源一样,由于同样的原因,还应该关闭Statement对象。
- 一个简单的调用close()方法将执行该作业。如果先关闭Connection对象,它也会关闭Statement对象。但是,应始终显式关闭Statement对象,以确保正确清理。
- 代码示例:
stmt.close();
(5) 从结果集中提取数据:需要使用相应的
ResultSet.getXXX()
方法从结果集中检索数据。
- 使用next()获取数据,也可使用previous()倒序。使用倒序时,需要让指针指向最后一个元素,才可逆序打印
ResultSet
- SELECT语句是从数据库中选择行并在结果集中查看行的标准方法。该java.sql.ResultSet中的接口表示结果集数据库查询。
- ResultSet对象维护指向结果集中当前行的游标。术语“结果集”是指包含在ResultSet对象中的行和列数据。
- 如果没有指定任何ResultSet类型,您将自动获得一个TYPE_FORWARD_ONLY。
类型 描述 ResultSet.TYPE_FORWARD_ONLY 光标只能在结果集中向前移动。 ResultSet.TYPE_SCROLL_INSENSITIVE 光标可以向前和向后滚动,结果集对创建结果集后发生的数据库的其他更改不敏感。 ResultSet.TYPE_SCROLL_SENSITIVE。 光标可以向前和向后滚动,结果集对创建结果集之后发生的其他数据库所做的更改敏感。
(6) 释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。
- 代码示例:
conn.close();
JDBC执行SQL语句
- 一旦获得了连接,我们可以与数据库进行交互。JDBC Statement和PreparedStatement接口定义了使您能够发送SQL命令并从数据库接收数据的方法和属性。
接口 使用 Statement 用于对数据库进行通用访问。在运行时使用静态SQL语句时很有用。Statement接口不能接受参数。 PreparedStatement(推荐使用) 当您计划多次使用SQL语句时使用。PreparedStatement接口在运行时接受输入参数。
SQL注入
- 就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击。
- 代码示例:
String username = xxx ' or 1=1 #;//' ResultSet rs=stat.executeQuery("select * from user where username='"+username+"' and password='"+password+"'");
- 解释:当username等于上面的变量后(不包括
//'
),那个单引号就和SQL语句中的单引号匹配上,而且#
后面的会被注释掉。那么这个SQL语句就失去了原来的执行能力。(可以把上面SQL语句复制到MySQL中进行测试)
PreparedStatement
- 该
PreparedStatement
的接口扩展了Statement接口,它为您提供了一个通用的Statement对象有两个优点附加功能。
- 作用:
- 1预编译,效率高
- 2 安全,避免SQL注入
- 代码示例:
String SQL = "Update Employees SET age = ? WHERE id = ?"; PreparedStatement pstmt = conn.prepareStatement(SQL);
- JDBC中的所有参数都由
?
符号,这被称为参数标记(占位符)。在执行SQL语句之前,必须为每个参数提供值。- 所述的
setXXX()
方法将值绑定到所述参数,其中XXX
代表要绑定到输入参数的值的Java数据类型。如果忘记提供值,将收到一个SQLException。- 每个参数标记由其顺序位置引用。第一个标记表示位置1,下一个位置2等等。该方法与Java数组索引不同,从0开始。
- 代码示例:
//和上面对应,第一个参数是"?"(占位符)的位置 pstmt.setInt(1,12);//age pstmt.setInt(2,1);//id PreparedStatement pstmt = conn.prepareStatement(SQL);
关闭PreparedStatement对象
- 就像关闭Statement对象一样,由于同样的原因,还应该关闭PreparedStatement对象。
- 一个简单的调用close()方法将执行该作业。如果先关闭Connection对象,它也会关闭PreparedStatement对象。但是,应始终显式关闭PreparedStatement对象,以确保正确清理。
抽取数据库工具类
- 代码示例:
public class DbUtil { private static String driver;//驱动名称 private static String url;//URL连接字符 private static String username;//数据库用户名 private static String password;//数据库密码 static { //driver="com.mysql.jdbc.Driver"; //url="jdbc:mysql://localhost:3306/myschool?useSSL=true&characterEncoding=utf8"; //username="root"; //password="root"; try {//改用读取配置文件形式。把上面注释的写入db.properties配置文件中,手动创建db.prperties文件(db.properties书写形式,不会就百度) Properties properties = new Properties(); InputStream is = DbUtil.class.getClassLoader().getResourceAsStream("db.properties"); properties.load(is); driver = properties.getProperty("driver"); url = properties.getProperty("url"); username = properties.getProperty("username"); password = properties.getProperty("password"); Class.forName(driver); } catch (Exception e) { e.printStackTrace(); System.out.println("创建驱动失败"); } } //创建连接 public static Connection getConnection() { try { return DriverManager.getConnection(url, username, password); } catch (SQLException e) { e.printStackTrace(); } return null; } //执行命令 public static int executeUpdate(String sql, Object... params) { Connection conn = getConnection(); PreparedStatement ps = null; try { ps = conn.prepareStatement(sql); if (params != null) { for (int i = 0; i < params.length; i++) { ps.setObject(i + 1, params[i]); } } return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { closeAll(conn, ps, null); } return -1; } //释放资源 public static void closeAll(Connection conn, Statement stat, ResultSet rs) { try { if (conn != null) { conn.close(); } if (stat != null) { stat.close(); } if (rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } } }