JDBC到底是什么?
JDBC(Java Database Connectivity),java数据库连接。JDBC是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,用于执行SQL语句的Java API。这个API由 java.sql.*,javax.sql.* 包中的一些类和接口组成,它为Java 开发人员操作数据库提供了一个标准的API,各种不同类型的数据库都有相应的实现,本文中的代码都是针对MySQL数据库实现的。
JDBC工作原理
JDBC 为多种关系数据库提供了统一访问方式,作为特定厂商数据库访问API的一种高级抽象,它主要包含一些通用的接口类。
JDBC访问数据库层次结构:
JDBC优势:
Java语言访问数据库操作完全面向抽象接口编程
开发数据库应用不用限定在特定数据库厂商的API
程序的可移植性大大增强
数据库编程的必备条件
编程语言,如Java,C、C++、Python等。
数据库,如Oracle,MySQL,SQL Server等。
数据库驱动包:不同的数据库,对应不同的编程语言提供了不同的数据库驱动包,如:MySQL提供了Java的驱动包mysql-connector-java,需要基于Java操作MySQL即需要该驱动包。同样的,要基于Java操作Oracle数据库则需要Oracle的数据库驱动包ojdbc。
JDBC编程步骤
装载相应数据库的JDBC驱动并进行初始化
准备数据库驱动包,并添加到项目的依赖中;导入专用的jar包(不同的数据库需要的jar包不同);注意:访问MySQL数据库需要用到第三方的类,这些第三方的类,都被压缩在一个.jar的文件里。
JDBC常用接口和类的使用规范
在 Java JDBC 编程中对数据库的操作均使用 JDK 自带的 API 统一处理,通常与特定数据库的驱动类是完全解耦的。所以掌握Java JDBC API (位于 java.sql 包下)即可掌握 Java 数据库编程。1.数据库连接(Connection)
Connection 接口实现类由数据库提供,获取 Connection 对象通常有两种方式:一种是通过 DriverManager (驱动管理类)的静态方法获取:// 加载JDBC驱动程序:反射,这样调用初始化com.mysql.jdbc.Driver类,即将该类加载到JVM方法 区,并执行该类的静态方法块、静态属性。 Class.forName("com.mysql.jdbc.Driver"); // 创建数据库连接 Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test ?user=root&password=root&useUnicode=true&characterEncoding=UTF-8"); MySQL数据连接的URL参数格式如下: jdbc:mysql://服务器地址:端口/数据库名?参数名=参数值
因为在进行数据库的增删改查的时候都需要与数据库建立连接,所以可以在项目中将建立连接写成一个工具方法,用的时候直接调用即可:/** * 取得数据库的连接 * @return 一个数据库的连接 */ public static Connection getConnection(){ Connection conn = null; try { //初始化驱动类com.mysql.jdbc.Driver Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/exam?characterEncoding=UTF-8","root", "admin"); //该类就在 mysql-connector-java-5.0.8-bin.jar中,如果忘记了第一个步骤的导包,就会抛出ClassNotFoundException } catch (ClassNotFoundException e) { e.printStackTrace(); }catch (SQLException e) { e.printStackTrace(); } return conn; }
一种是通过DataSource(数据源)对象获取。 实际应用中会使用 DataSource 对象MysqlDataSource db = new MysqlDataSource(); db.setServerName("localhost"); db.setPort(3306); db.setUser("root"); db.setPassword("123456"); db.setDatabaseName("04_03");//数据库名 db.setUseSSL(false); db.setCharacterEncoding("utf-8"); db.setServerTimezone("Asia/Shanghai");//固定参数,大小写都要一致
以上两种方式的区别是:
1. DriverManager类来获取的Connection连接,是无法重复利用的,每次使用完以后释放资源时,通过connection.close()都是关闭物理连接。
2. DataSource提供连接池的支持。连接池在初始化时将创建一定数量的数据库连接,这些连接是可以复用的,每次使用完数据库连接,释放资源调用connection.close()都是将Conncetion连接对象回收。
Statement对象(创建操作命令)
Statement接口创建之后,可以执行SQL语句,完成对数据库的增删改查。其中 ,增删改只需要改变SQL语句的内容就能完成,然而查询略显复杂。
Statement对象主要是将SQL语句发送到数据库中。JDBC API中主要提供了三种Statement对象。实际开发中最常用的是preparedStatement对象,以下是对其的总结:
在Statement中使用字符串拼接的方式,该方式存在句法复杂,容易犯错等缺点,具体在下面的对比中介绍。字符串拼接方式的SQL语句是非常繁琐的,中间有很多的单引号和双引号的混用,极易出错。
Statement s = conn.createStatement(); // 准备sql语句 // 注意: 字符串要用单引号' String sql = "insert into t_courses values(null,"+"'数学')"; //在statement中使用字符串拼接的方式,这种方式存在诸多问题 s.execute(sql); System.out.println("执行插入语句成功");
PreparedStatement也是用来执行sql语句的与创建Statement不同的是,需要根据sql语句创建PreparedStatement。除此之外,还能够通过设置参数,指定相应的值,而不是Statement那样使用字符串拼接。
/** * 添加课程 * @param courseName 课程名称 */ public void addCourse(String courseName){ String sql = "insert into t_course(course_name) values(?)"; //该语句为每个 IN 参数保留一个问号(“?”)作为占位符 Connection conn = null; //和数据库取得连接 PreparedStatement pstmt = null; //创建statement try{ conn = DbUtil.getConnection(); pstmt = (PreparedStatement) conn.prepareStatement(sql); pstmt.setString(1, courseName); //给占位符赋值 pstmt.executeUpdate(); //执行 }catch(SQLException e){ e.printStackTrace(); } finally{ DbUtil.close(pstmt); DbUtil.close(conn); //必须关闭 } }
使用PreparedStatement时,他的SQL语句不再采用字符串拼接的方式,而是采用占位符的方式。“?”在这里就起到占位符的作用。这种方式除了避免了statement拼接字符串的繁琐之外,还能够提高性能。每次SQL语句都是一样的,java类就不会再次编译,这样能够显著提高性能。
String sql = "update t_course set course_name =? where course_id=?";
后面需要用到PreparedStatement接口创建的pstmt的set方法给占位符进行赋值。注意一点,这里的参数索引是从1开始的。
Statement和PreparedStatement的异同及优缺点
同:两者都是用来执SQL语句的异:PreparedStatement需要根据SQL语句来创建,它能够通过设置参数,指定相应的值,不是像Statement那样使用字符串拼接的方式。
PreparedStatement的优点:
1、其使用参数设置,可读性好,不易记错。在statement中使用字符串拼接,可读性和维护性比较差。
2、其具有预编译机制,性能比statement更快。
3、其能够有效防止SQL注入攻击。
两种执行SQL的方法:
executeQuery() 方法执行后返回单个结果集的,通常用于select语句。
executeUpdate()方法返回值是一个整数,指示受影响的行数,通常用于update、insert、delete语句。
ResultSet对象(处理结果集)
ResultSet对象被称为结果集,它代表符合SQL语句条件的所有行,并且它通过一套getXXX方法提供 了对这些行中数据的访问。 ResultSet里的数据一行一行排列,每行有多个字段,并且有一个记录指针,指针所指的数据行叫做当前数据行,我们只能来操作当前的数据行。我们如果想要取得某一条记录,就要使用ResultSet的next()方法 ,如果我们想要得ResultSet里的所有记录,就应该使用while循环。其执行机制类似于集合中的iterator迭代器。
释放资源(关闭结果集、命令、连接)
关闭结果集
if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } }
关闭命令
if (statement != null) { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } }
关闭连接命令if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } }
在JDBC编码的过程中我们创建了Connection、ResultSet等资源,这些资源在使用完毕之后是一定要进行关闭的。关闭的过程中遵循从里到外的原则。因为在增删改查的操作中都要用到这样的关闭操作,为了使代码简单,增加其复用性,将这些关闭的操作写成一个方法和建立连接的方法一起放到一份工具类中。
/** * 封装三个关闭方法 * @param pstmt */ public static void close(PreparedStatement pstmt){ if(pstmt != null){ //避免出现空指针异常 try{ pstmt.close(); }catch(SQLException e){ e.printStackTrace(); } } } public static void close(Connection conn){ if(conn != null){ try { conn.close(); } catch (SQLException e) { // TODO: handle exception e.printStackTrace(); } } } public static void close(ResultSet rs){ if (rs != null) { try { rs.close(); } catch (SQLException e) { // TODO: handle exception e.printStackTrace(); } } }
重点内容总结
JDBC使用步骤:
1. 创建数据库连接Connection
DriverManager创建
DataSource获取
2. 创建操作命令Statement
PreparedStatement
3. 使用操作命令来执行SQL
// 查询操作 preparedStatement.executeQuery(); // 新增、修改、删除操作 preparedStatement.executeUpdate();
4. 处理结果集ResultSetwhile (resultSet.next()) { int xxx = resultSet.getInt("xxx"); String yyy= resultSet.getString("yyy"); ... }
5. 释放资源try { if(resultSet != null){ resultSet.close(); } if(preparedStatement != null){ preparedStatement.close(); } if(connection != null){ connection.close(); } } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException("数据库错误"); }
execute和executeUpdate的区别
相同点:二者都能够执行增加、删除、修改等操作。不同点:
1、execute可以执行查询语句,然后通过getResult把结果取出来。executeUpdate不能执行查询语句。
2、execute返回Boolean类型,true表示执行的是查询语句,false表示执行的insert、delete、update等。executeUpdate的返回值是int,表示有多少条数据受到了影响。
面试题
数据库连接有哪些方式?分别有什么区别
数据库Statement和PreparedStatement有什么区别?