数据库连接技术浅析"/>
测试方向基础——JDBC数据库连接技术浅析
DBC数据库连接技术浅析
- 数据库简介
- Java中JDBC的基本操作
- 数据库造作的完整封装(DAO)
数据库简介
-
没有文件以前,数据的存储方式以内存为主,无法长期保存。文件系统的产生,数据可以长期保存在文件中。常见的文件类型:
(1)纯文本:没有格式要求
(2)数据传输格式:html,xml,json,规定一定的规范的纯文本文件
(3)制定公司特定格式:excel,csv等
(4)专门做数据存储的公司:mysql,sqlsever,oracle,DB2等 -
关于数据库:
数据库服务器:硬件
数据库服务、数据库客户端:软件
命令行:sql语句; 客户端软件:不唯一;数据库的名字:一般代表某一个应用程序 -
数据库的主要职能:保存大量数据、检索数据、数据维护(备份、压缩等)
-
常见数据库:MySql, SqlServer, Oracle,SqILite,通用语言都是SQL
-
SQL是Structured Query Language(
结构化查询语言
)的缩写,SQL是专为数据库而建立的操作命令集
,是一种功能齐全的数据库语言
-
SQL对数据库的操作:
(1)数据定义
:称为“SQL DDL”,定义数据库的逻辑结构,包括定义数据库、基本表、视图和索引
(2)数据操纵
:称为“SQL DML”,其中包括数据查询和数据更新两大类操作,其中数据更新又包括插入、删除和更新
(3)数据控制
:称为“DCL”,对用户访问数据的控制有基本表和视图的授权、完整性规则的描述,事务控制语句等
(4)其他要素:规定SQL语句在宿主语言的程序中使用的规则 -
数据控制:
(1)安全性控制
:授权—>GRANT, 回收---->REVOKE…
(2)完整性控制
:数据库的完整性是指数据的正确性和相容性,主要防止语义上不正确的数据进入数据库。
(3)事务控制
:事务提交:COMMIT; 事务撤销:ROLLBACK…
(4)并发控制
:数据库作为共享资源,允许多个用户程序并行地存取数据**。当多个用户并行地操作数据库时,需要通过并发控制对它们加以协调、控制,以保证并发操作的正确执行,并保证数据库的一致性**,LOCK TABLE 表名(或表名集合)IN ……
Java中JDBC的基本操作
-
JDBC的概念:是由一组Java语言编写的
类和接口
组成,是一种用于执行SQL语句的规范
官网链接 -
JDBC API(API: 应用程序编程接口)提供两类主要接口:
(1)面向开发人员的java.sql程序包,使得Java程序员能够进行数据库连接,执行SQL查询,并得到结果集合
(2)面向底层数据库厂商的JDBC Drivers -
创建JDBC应用的步骤:
(1)加载数据库的驱动程序(首先引入数据库驱动的jar包)
下载地址
Class.forName("com.mysql.jdbc.Driver");
(2)建立数据库连接(3)执行数据库操作SQL
Statement stmt = conn.createStatement();
ResultSet rs = stmt.exsuteQuery(sql);
(4)得到ResultSet进行结果处理
(5)关闭数据库连接。 -
DriverManager:是JDBC的管理层,管理一组JDBC驱动程序的基本服务。DriverManager类的主要作用:
追踪可用的驱动程序,并在数据库和相应驱动程序之间建立连接。
调用DriverManager.getConnection()方法将建立与数据库的连接,得到与数据库连接的Connection对象 -
(1) Connection类是JDBC规范中最核心的类,statement对象和ResultSet对象等都直接或者间接的来源于它
(2)Connection对象表示与特定数据库的连接(会话)。
1)得到Statement对象的方法:
createStatement();
prepareStatement(String sql); 【该方法返回一个PreparedStatement对象,并能把sql语句提交到数据库进行预编译
】
prepareCall(String sql)
2)为了保证数据库事务的原子性,Connection可以设置手动提交事务
补充该类的两个方法:
commit()进行当前业务开始以来的所有变化;
rollback()放弃当前业务开始以来的所有改变。 -
Statement是
向数据库提交SQL语句并返回相应结果
的工具。语句可以是SQL查询、修改、插入或者删除
(1)PreparedStatement接口:防止SQL注入攻击(使用占位符“?”); 提高SQL的执行性能(在执行之前有预处理); 避免使用SQL方言; 提高JDBC中有关SQL代码的可读性。
(2)CallableStatement接口用于执行SQL存储过程的接口
(3)Statement常用方法:
* execute:执行给定SQL语句,可能返回多条结果
* executeQuery:执行给定的 SQL 语句,该语句返回单个 ResultSet 对象
* executeUpdate执行,该语句可能为 INSERT、UPDATE 或 DELET给定 SQL 语句
* getConnection:获取生成此 Statement 对象的 Connection 对象
* close:立即释放此 Statement 对象的数据库和 JDBC 资源,而不是等待该对象自动关闭时发生此操作
* getFetchSize:获取结果集合的行数
* getQueryTimeout:获取驱动程序等待 Statement 对象执行的秒数 -
PreparedStatement类:是Statement的子接口。用PreparedStatement类效率会更高。
PreparedStatement实例要通过Connection对象调用prepareStatement(String sql)方法获得。
常用方法:- public ResultSetMetaData getMetaData()
- public void setInt(int parameterIndex, int x)
- public void setFloat(int parameterIndex, float x)
- public void setString(int parameterIndex, String x)
- public void setDate(int parameterIndex, Date x)
-
CallableStatement用于执行 SQL 存储过程的接口
CallableStatement继承了PreparedStatement接口,所以也继承了PreparedStatement的方法(很少用) -
ResultSet:表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
其对象具有指向其当前数据行的光标
常用方法: String getString(int columnIndex):以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指定列的值while (rs.next()) {System.out.println(rs.getString("name")); }
常用方法:
- boolean next():将光标从当前位置向前移一行。当调用 next 方法返回 false 时,光标位于最后一行的后面
- int getInt(String columnIndex):以 Java 编程语言中 int 的形式获取此 ResultSet 对象的当前行中指定列的值。
- next:将光标从当前位置向前移一行
- getXXX:以某种对象的形式获取指定 JDBC 该类型参数的值
- absolute:将光标移动到此 ResultSet 对象的给定行编号
- afterLast:将光标移动到此 ResultSet 对象的末尾,正好位于最后一行之后
- beforeFirst:将光标移动到此 ResultSet 对象的开头,正好位于第一行之前
- close:立即释放此 ResultSet 对象的数据库和 JDBC 资源,而不是等待该对象自动关闭时发生此操作
- first:将光标移动到此 ResultSet 对象的第一行
- getRow:获取当前行编号
- isFirst:获取光标是否位于此 ResultSet 对象的第一行
- isLast:获取光标是否位于此 ResultSet 对象的最后一行
- last:将光标移动到此 ResultSet 对象的最后一行
- previous:将光标移动到此 ResultSet 对象的上一行
-
关于关闭数据库的连接,一共有三处:
检测ResultSet是否关闭,否则关闭
检测Statement是否关闭,否则关闭
检测Connection是否关闭,否则关闭if(rs!=null)try{rs.close();}catch(Exception e){e.printStackTrace();} if(stmt!=null)try{stmt.close();}catch(Exception e){e.printStackTrace();} if(conn!=null)try{conn.close();}catch(Exception e){e.printStackTrace();}
数据库造作的完整封装(DAO)
- 所以我们对于一张表的所有操作,在Java程序中体现到了一个实体类的所有的操作。
一般标准工程中一个实体类会有一个对应的DAO类(Data Access Object),来进行这个类的所有的操作。
下面也都是代码的栗子了:
- 创建一个数据库
package xxx.www.xhx;import java.CookieHandler;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;//创建数据库
public class Demo1 {public static void main(String[] args) {String connUrl = "jdbc:mysql://127.0.0.1:3306";String driverStr = "com.mysql.jdbc.Driver";Statement stmt = null;Connection con = null;try {// 1.加载驱动Class.forName(driverStr);// 2.建立数据库的连接con = DriverManager.getConnection(connUrl, "root", "123456");if (!con.isClosed()) {System.out.println("数据库连接成功");// 3.使用statement执行SQL语句stmt = con.createStatement();boolean flag = stmt.execute("create database demo1112");// 创建一个数据库// 4.对执行结果进行处理if (flag) {System.out.println("数据库创建成功");} else {System.out.println("数据库创建失败");}}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {try {// 5.关闭数据库的连接if (stmt != null) {stmt.close();}if (con != null) {con.close();}} catch (Exception e) {// TODO: handle exception}}}
}
- 查询
在创建的数据库中,可以加入一个表,我这里命名为test0509, 下面代码用来查询表中的信息。
提示,URL后的?useUnicode=true&characterEncoding=utf-8&useSSL=true
或者仅加上?useSSL=true
是因为警告:在没有SSL连接的情况下建立ssl连接不建议使用服务器的身份验证。此用此方法,仅仅是初学,不同太在意。
package xxx.www.xhx;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;//查询
public class Demo2 {public static void main(String[] args) throws ClassNotFoundException, SQLException {String connUrl = "jdbc:mysql://127.0.0.1:3306/test0509?useUnicode=true&characterEncoding=utf-8&useSSL=true";String driverStr = "com.mysql.jdbc.Driver";String querySql = "select id,name as username,password,age from user";Class.forName(driverStr);Connection conn = DriverManager.getConnection(connUrl, "root", "123456");Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(querySql);// 执行sql语句while (rs.next()) {int id = rs.getInt(1);// 对应的查询结果的第几列String name = rs.getString("username");// 形参是字段名String password = rs.getString("password");System.out.println("---" + id + "---" + name + "----" + password);}rs.close();stmt.close();conn.close();}
}
打印出来的效果如下:
下面基于此运行结果,示例几个常用的方法。
package xxx.www.xhx;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;//查询
public class Demo2 {public static void main(String[] args) throws ClassNotFoundException, SQLException {String connUrl = "jdbc:mysql://127.0.0.1:3306/test0509?useSSL=true";String driverStr = "com.mysql.jdbc.Driver";String querySql = "select id,name as username,password,age from user";Class.forName(driverStr);Connection conn = DriverManager.getConnection(connUrl, "root", "123456");Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(querySql);// 执行sql语句// ResultSet 指针初始值在第一行之前rs.absolute(3);// 指针定位到第三行System.out.println(rs.getString("username")); // 第三行打印出tom3rs.beforeFirst(); // 指针定位到第一行之前rs.next();// 指针定位到下一行,即第一行,应该为tom1System.out.println(rs.getString("username"));rs.afterLast();// 指针定位到最后一行之后rs.previous();// 指针向前移动一行,即tomSystem.out.println(rs.getString("username"));rs.close();stmt.close();conn.close();}
}
结果如下:
查询结果的列名获取。
package xxx.www.xhx;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;//查询
public class Demo2 {public static void main(String[] args) throws ClassNotFoundException, SQLException {String connUrl = "jdbc:mysql://127.0.0.1:3306/test0509?useSSL=true";String driverStr = "com.mysql.jdbc.Driver";String querySql = "select id,name as username,password,age from user";Class.forName(driverStr);Connection conn = DriverManager.getConnection(connUrl, "root", "123456");Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(querySql);// 执行sql语句ResultSetMetaData metaData = rs.getMetaData(); //返回结果的列名int count = metaData.getColumnCount();System.out.println(count);System.out.println(metaData.getColumnLabel(2));// as之后的别名System.out.println(metaData.getColumnName(2));// as之前的原列名rs.close();stmt.close();conn.close();}
}
结果如下:
在此,我们需要了解一个问题:SQL注入问题。在此就浅浅的了解一下吧。举个例子:
插入or 1 = 1 --
后,所有信息都会被查出。
上面那一大堆类中,有浅浅的一个细节,hh,你品,你慢慢品,就是prepareStatement得到statement对象
,他会把sql语句提交到数据库进行预编译。效率更高一点,更安全些。
package xxx.www.xhx;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;import javax.naming.spi.DirStateFactory.Result;public class Demo4 {public static void main(String[] args) throws SQLException {String sql = "select count(*) from user where name = ? and password = ?";// 这个问号就相当于一个占位符Connection conn = DBUtils.openConnection();PreparedStatement pStatement = conn.prepareStatement(sql);// 普通的一个查询pStatement.setString(1, "tom1");// 1表示第一个占位符pStatement.setString(2, "123");// 2表示第二个占位符ResultSet rSet = pStatement.executeQuery();// 返回结果// 因为只有一行,我们用if即可。超过一行就得用循环rSet.next(); // 移动到第一行System.out.println(rSet.getInt(1));// SQL注入查询pStatement.setString(1, "'or 1=1 -- '");// 1表示第一个占位符pStatement.setString(2, "123");// 2表示第二个占位符rSet = pStatement.executeQuery();// 返回结果// 因为只有一行,我们用if即可。超过一行就得用循环rSet.next(); // 移动到第一行System.out.println(rSet.getInt(1));//关闭连接}
}
效果如下:
- 插入
封装的意识:我们不妨把建立连接,关闭连接的代码装在一个类里。
package xxx.www.xhx;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class DBUtils {static String connUrl = "jdbc:mysql://127.0.0.1:3306/test0509?useSSL=true";static String driverStr = "com.mysql.jdbc.Driver";static {try {Class.forName(driverStr);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static Connection openConnection() {Connection conn = null;try {conn = DriverManager.getConnection(connUrl, "root", "123456");} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return conn;}public static void closeCoonection(Connection conn) {if (conn != null) {try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}
插入一条数据
package xxx.www.xhx;import java.lang.Thread.State;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;//插入
public class Demo3 {public static void main(String[] args) throws SQLException {String insert_sql="INSERT INTO user(name, password, age) "+ "VALUES ('tom13', '123', '20')";Connection conn = DBUtils.openConnection();Statement stmt = conn.createStatement();int count = stmt.executeUpdate(insert_sql);//影响了多少行System.out.println(count);stmt.close();DBUtils.closeCoonection(conn);}
}
输出为1.
用prepareStatement实现插入:
package xxx.www.xhx;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;import com.mysql.jdbc.Driver;public class Demo5 {public static void main(String[] args) throws ClassNotFoundException, SQLException {Class.forName("com.mysql.jdbc.Driver");String connStr = "jdbc:mysql://127.0.0.1:3306/test0509?useSSL=true";String sql = "INSERT INTO user (name,password,age) VALUES (?, ?, ?)";Connection connection = DriverManager.getConnection(connStr, "root", "123456");PreparedStatement pstmt = connection.prepareStatement(sql);for (int i = 15; i < 29; i++) {pstmt.setString(1, "tom" + i);pstmt.setString(2, "11112333");pstmt.setInt(3, 33);int count = pstmt.executeUpdate();// 不放循环里,只插入一次}pstmt.close();connection.close();}
}
查看表,可以发现插入成功:
更新操作,只需要修改sql语句即可
update user set age =?
更新操作封装时,可能出现参数个数不确定的问题,浅浅给出一个代码,不想看就别看了。
public static int update(String sql, Object...objects) {return 0;}
更多推荐
测试方向基础——JDBC数据库连接技术浅析
发布评论