JDBC和XML的学习
JDBC
JDBC的概述
JDBC(Java Data Base Connectivity) 是 Java 访问数据库的标准规范.是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范。
JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。
JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口),而数据库厂商需要实现这套接口,提供数据库驱动jar包, 我们可以使用这套接口编程,真正执行的代码是对应驱动包中的实现类。
-
API的使用:注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
-
获得链接 :
获取连接的静态方法 | 说明 |
---|---|
Connection getConnection(String url, String user, String password) | 通过连接字符串和用户名,密码来获取数据库连接对象 |
getConnection方法 3个 连接参数说明
连接参数 | 说明 |
---|---|
user | 登录用户名 |
password | 登录密码 |
url | mySql URL的格式 jdbc:mysql://localhost:3306/db4 |
String url = "jdbc:mysql://localhost:3306/jcx?characterEncoding=UTF-8&serverTimezone=GMT%2B8";
- 获取语句执行平台
通过Connection 的 createStatement方法 获取sql语句执行对象
Connection接口中的方法 | 说明 |
---|---|
Statement createStatement() | 创建 SQL语句执行对象 |
Statement : 代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。
Statement类 常用方法 | 说明 |
---|---|
int executeUpdate(String sql); | 执行insert update delete语句.返回int类型,代表受影响的行数 |
ResultSet executeQuery(String sql); | 执行select语句, 返回ResultSet结果集对象 |
ResultSet接口
作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。
ResultSet接口方法 | 说明 |
---|---|
boolean next() | 1) 游标向下一行2) 返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false |
xxx getXxx( String or int) | 1) 通过列名,参数是 String 类型。返回不同的类型2) 通过列号,参数是整数,从 1 开始。返回不同的类型 |
- 释放资源
- 需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
- 释放原则:先开的后关,后开的先关。ResultSet ==> Statement ==> Connection
- 放在finally 块中:
- 步骤总结
- 获取驱动(可以省略) 2. 获取连接3. 获取Statement对象4. 处理结果集(只在查询时处理) 5. 释放资源
SQL注入问题
SQL注入
我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了 原有SQL 真正的意义,以上问题称为 SQL 注入 .
预处理对象
-
PreparedStatement 接口介绍
PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句对象.
预编译: 是指SQL 语句被预编译,并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。 -
PreparedStatement 特点
因为有预先编译的功能,提高 SQL 的执行效率。
可以有效的防止 SQL 注入的问题,安全性更高 -
获取PreparedStatement对象
通过Connection创建PreparedStatement对象
Connection 接口中的方法 | 说明 |
---|---|
PreparedStatement prepareStatement(String sql) | 指定预编译的 SQL 语句,SQL 语句中使用占位符 ? 创建一个语句对象 |
常用方法 | 说明 |
---|---|
int executeUpdate(); | 执行insert update delete语句. |
ResultSet executeQuery(); 执行select语句. | 返回结果集对象 Resulet |
- 使用PreparedStatement的步骤
1)编写 SQL 语句,未知内容使用?占位:
2) 获得 PreparedStatement 对象
3) 设置实际参数:setXxx( 占位符的位置, 真实的值)
4) 执行参数化 SQL 语句
5)关闭资源
setXxx重载方法 | 说明 |
---|---|
void setDouble(int parameterIndex, double x) | 将指定参数设置为给定 Java double 值。 |
void setInt(int parameterIndex, int x) | 将指定参数设置为给定 Java int 值。 |
void setString(int parameterIndex, String x) | 将指定参数设置为给定 Java String 值。 |
void setObject(int parameterIndex, Object x) | 使用给定对象设置指定参数的值。 |
-
Statement 与 PreparedStatement的区别?
- Statement用于执行静态SQL语句,在执行时,必须指定一个事先准备好的SQL语句。
- PrepareStatement是预编译的SQL语句对象,语句中可以包含动态参数“?”,在执行时可以为“?”动态设置参数值。
- PrepareStatement可以减少编译次数提高数据库性能。
JDBC 控制事务
我们使用 Connection中的方法实现事务管理
方法 | 说明 |
---|---|
void setAutoCommit(boolean autoCommit) | 参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务 |
void commit() | 提交事务 |
void rollback() | 回滚事务 |
数据库连接池和DBUtils
数据库连接池
** 什么是连接池**
实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池.
连接池的好处
用池来管理Connection,这样可以重复使用Connection。 当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。常见的连接池有 DBCP连接池, C3P0连接池, Druid连接池
DBUtils工具类
DBUtils简介
使用JDBC我们发现冗余的代码太多了,为了简化开发 我们选择使用 DbUtils Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。
- 使用方式:
DBUtils就是JDBC的简化开发工具包。需要项目导入commons-dbutils-1.6.jar。
** Dbutils核心功能介绍**
- QueryRunner 中提供对sql语句操作的API.
- ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
- DbUtils类,他就是一个工具类,定3义了关闭资源与事务处理相关方法.
** JavaBean组件**
- JavaBean 就是一个类, 开发中通常用于封装数据,有一下特点
- 需要实现 序列化接口, Serializable (暂时可以省略)
- 提供私有字段: private 类型 变量名;
- 提供 getter 和 setter
- 提供 空参构造
DBUtils完成 CRUD
QueryRunner核心类
- 构造方法
QueryRunner() QueryRunner(DataSource ds) ,提供数据源(连接池),DBUtils底层自动维护连接connection - 常用方法
update(Connection conn, String sql, Object… params) ,用来完成表数据的增加、删除、更新操作
query(Connection conn, String sql, ResultSetHandler rsh, Object… params) ,用来完成表数据的查询操作
QueryRunner实现增、删、改操作
QueryRunner实现查询操作
ResultSetHandler接口简介:ResultSetHandler可以对查询出来的ResultSet结果集进行处理,达到一些业务上的需求。
ResultSetHandler 结果集处理类
ResultSetHandler实现类 | 说明 |
---|---|
ArrayHandler | 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值 |
ArrayListHandler | 将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。 |
BeanHandler | 将结果集中第一条记录封装到一个指定的javaBean中. |
BeanListHandler | 将结果集中每一条记录封装到指定的javaBean中,再将这些javaBean在封装到List集合中 |
ColumnListHandler | 将结果集中指定的列的字段值,封装到一个List集合中 |
KeyedHandler | 将结果集中每一条记录封装到Map<String,Object>,在将这个map集合做为另一个Map的value,另一个Map集合的key是指定的字段的值。 |
MapHandler | 将结果集中第一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值 |
MapListHandler | 将结果集中每一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值,在将这些Map封装到List集合中。 |
ScalarHandler | 它是用于封装单个数据。例如 select count(*) from 表操作。 |
数据库批处理
Statement和PreparedStatement都支持批处理操作,PreparedStatement的批处理方式:
方法 | 说明 |
---|---|
void addBatch() | 将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。通过调用方法 executeBatch 可以批量执行此列表中的命令。 |
int[] executeBatch() | 每次提交一批命令到数据库中执行,如果所有的命令都成功执行了,那么返回一个数组,这个数组是说明每条命令所影响的行数 |
mysql 批处理是默认关闭的,所以需要加一个参数才打开mysql 数据库批处理,在url中添加
rewriteBatchedStatements=true
MySql元数据
- 除了表之外的数据都是元数据,可以分为三类
- 查询结果信息: UPDATE 或 DELETE语句 受影响的记录数。
- 数据库和数据表的信息: 包含了数据库及数据表的结构信息。
- MySQL服务器信息: 包含了数据库服务器的当前状态,版本号等。
常用命令
- select version(); 获取mysql服务器的版本信息
- show status; 查看服务器的状态信息
- show columns from table_name; 显示表的字段信息等,和desc table_name一样
- show index from table_name; 显示数据表的详细索引信息,包括PRIMARY KEY(主键)
- show databases:列出所有数据库
- show tables : 显示当前数据库的所有表
- select database(): 获取当前的数据库名
使用JDBC 获取元数据
JDBC中描述元数据的类:
元数据类 | 作用 |
---|---|
DatabaseMetaData | 描述数据库的元数据对象 |
ResultSetMetaData | 描述结果集的元数据对象 |
- 获取元数据对象的方法 : getMetaData ()
connection 连接对象, 调用 getMetaData () 方法,获取的是DatabaseMetaData 数据库元数据对象
PrepareStatement 预处理对象调用 getMetaData () , 获取的是ResultSetMetaData , 结果集元数据对象
DatabaseMetaData的常用方法
方法 | 作用 |
---|---|
getURL() | 获取数据库的URL |
getUserName() | 获取当前数据库的用户名 |
getDatabaseProductName() | 获取数据库的产品名称 |
getDatabaseProductVersion() | 获取数据的版本号 |
getDriverName() | 返回驱动程序的名称 |
isReadOnly() | 判断数据库是否只允许只读 true 代表只读 |
ResultSetMetaData的常用方法
方法 | 作用 |
---|---|
getColumnCount() | 当前结果集共有多少列 |
getColumnName(int i) | 获取指定列号的列名, 参数是整数 从1开始 |
getColumnTypeName(int i) | 获取指定列号列的类型, 参数是整数 从1开始 |
XML
XML基本介绍
XML即可扩展标记语言(Extensible Markup Language)
特点
- 可扩展的, 标签都是自定义的
- 语法十分严格
XML的作用
功能 | 说明 |
---|---|
存储数据 | 通常,我们在数据库中存储数据。不过,如果希望数据的可移植性更强,我们可以把数据存储 XML 文件中 |
配置文件 | 作为各种技术框架的配置文件使用 (最多)在网络中 |
传输 | 客户端可以使用XML格式向服务器端发送数据,服务器接收到xml格式数据,进行解析 |
XML的语法
XML文档声明格式
文档声明必须为结束;
文档声明必写在第一行;
<?xml version="1.0" encoding="UTF-8"?>
属性说明:
- versioin:指定XML文档版本。必须属性,因为我们不会选择1.1,只会选择1.0;
- encoding:指定当前文档的编码。可选属性,默认值是utf-8;
元素
Element 元素: 是XML文档中最重要的组成部分
元素的命名规则:
1. 不能使用空格,不能使用冒号
2. xml 标签名称区分大小写
3. XML 必须有且只有一个根元素
语法格式:
1) XML 必须有且只有一个根元素,它是所有其他元素的父元素
2) 普通元素的结构开始标签、元素体、结束标签组成
3) 元素体:元素体可以是元素,也可以是文本
4) 空元素:空元素只有开始标签,而没有结束标签,但元素必须自己闭合
属性
1. 属性是元素的一部分,它必须出现在元素的开始标签中
2. 属性的定义格式:属性名=属性值,其中属性值必须使用单引或双引
3. 一个元素可以有0~N个属性,但一个元素中不能出现同名属性
4. 属性名不能使用空格、冒号等特殊字符,且必须以字母开头
注释
XML的注释,以“
”结束。注释内容会被XML解析器忽略!
XML约束
- 在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束。
- 常见的xml约束:
DTD
Schema
DTD约束
DTD(Document Type Definition),文档类型定义,用来约束XML文档。规定XML文档中元素的名称,子元素的名称及顺序,元素的属性等。
引入DTD
<!DOCTYPE students SYSTEM "student.dtd">
Schema约束
- Schema是新的XML文档约束, 比DTD强大很多,是DTD 替代者;
- Schema本身也是XML文档,但Schema文档的扩展名为xsd,而不是xml。
- Schema 功能更强大,内置多种简单和复杂的数据类型
- Schema 支持命名空间 (一个XML中可以引入多个约束文档)
XML引入Schema约束
<?xml version="1.0" encoding="UTF-8" ?>
1)查看schema文档,找到根元素,在xml中写出来
<students
2) 根元素来自哪个命名空间。使用xmlns指令来声明
xmlns="http://www.lagou.com/xml"
3) 引入 w3c的标准命名空间
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4) 引入的命名空间跟哪个xsd文件对应
xsi:schemaLocation="http://www.lagou.com/xml student.xsd"
>
</students>
XML 解析
XML解析方式
开发中比较常见的解析方式有两种,如下:
- DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象。
优点:元素与元素之间保留结构关系,故可以进行增删改查操作。
缺点:XML文档过大,可能出现内存溢出显现。 - SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都将触发对应的事件
优点:占用内存少 处理速度快,可以处理大文件
缺点:只能读,逐行后将释放资源。
dom4j 的使用
导入JAR包
使用核心类SaxReader加载xml文档获得Document,通过Document 对象获得文档的根元素,然后就可以操作了
常用API如下:
- SaxReader对象
read(…) 加载执行xml文档 - Document对象
getRootElement() 获得根元素 - Element对象
elements(…) 获得指定名称的所有子元素。可以不指定名称
element(…) 获得指定名称的第一个子元素。可以不指定名称
getName() 获得当前元素的元素名
attributeValue(…) 获得指定属性名的属性值
elementText(…) 获得指定名称子元素的文本值
getText() 获得当前元素的文本内容
** xpath方式读取xml**
XPath基本语法介绍
语法 | 说明 |
---|---|
/AAA/DDD/BBB | 表示一层一层的,AAA下面 DDD下面的BBB |
//BBB | 表示和这个名称相同,表示只要名称是BBB,都得到 |
//* | 所有元素 |
BBB[1] , BBB[last()] | 第一种表示第一个BBB元素, 第二种表示最后一个BBB元素 |
//BBB[@id] | 表示只要BBB元素上面有id属性,都得到 |
//BBB[@id=‘b1’] | 表示元素名称是BBB,在BBB上面有id属性,并且id的属性值是b1 |
常用方法:
- selectSingleNode(query): 查找和 XPath 查询匹配的一个节点。
参数是Xpath 查询串。 - selectNodes(query): 得到的是xml根节点下的所有满足 xpath 的节点;
参数是Xpath 查询串。 - Node: 节点对象