文章内容输出来源:拉勾教育java就业急训营
笔记说明
本篇笔记来自于拉勾教育java就业急训营第二阶段模块二学习记录。本篇课程包括
- JDBC操作数据库。
此模块课程拉勾讲师首先讲解了什么是JDBC以及JDBC的作用,然后通过代码,源码解读讲解JDBC的基本使用流程,在通过对JDBC实现基本工具类的方式对JDBC基本使用有了深刻的印象。通过实际案例进入到sql注入问题,循序渐进进入JDBC预处理对象内容。最后进入JDBC控制事务的高级特性种。
- 连接池
为解决连接数据库和释放资源消耗性能的问题,引入连接池技术。此块知识讲师通过实际代码操作讲解了DBCP连接池, C3P0连接池, Druid连接池的使用方式。为了简化开发,进入DbUtils工具类库的使用学习,学习完使用CRUD之后,继续进入学习批处理操作。最后讲解类对mysql元数据的学习和开发。
- xml
此节内容主要简介了xml基本知识,包含基本语法,约束和解析方式xPath以及如何使用xml配置文件。
- 实际案例
通过商场案例对所学知识运用于实际场景,加深理解和锻炼实际代码使用操作能力
JDBC
JDBC概述
![cecb2f2884e88b1c9e6046568557d7bb.png](https://i-blog.csdnimg.cn/blog_migrate/a26e554bc00222c23efc37da22cfb082.jpeg)
JDBC开发流程
![4ebc6379c983b39957b3f6227f5e6ace.png](https://i-blog.csdnimg.cn/blog_migrate/33ba7e4b7dd00c2673df6e35757c1473.jpeg)
public
1. 注册驱动
- Driver类源码
// Driver类是MySql提供的数据库驱动类, 实现了JDBC的Driver接口
java.sql.Driver public class Driver extends NonRegisteringDriver implements java.sql.Driver {
// 空参构造
public Driver() throws SQLException {
}
//静态代码块,Class类的 forName()方法将Driver类 加载到内存, static代码块会自动执行
static {
try {
/*
DriverManager 驱动管理类
registerDriver(new Driver) 注册驱动的方法
注册数据库驱动
*/
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
2 获取连接
Connection
3 获取执行对象
Statement
Statement类 常用方法 | 说明 |
---|---|
int executeUpdate(String sql); | 执行insert update delete语句.返回int类型,代表受影响的行 数 |
ResultSet executeQuery(String sql); |
4 结果处理
![fd809b1975def11a05488250b114ed8f.png](https://i-blog.csdnimg.cn/blog_migrate/84ffe74fdd978ff7c2b782c888ee0718.jpeg)
5. 释放资源
- 需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
- 释放原则:先开的后关,后开的先关。ResultSet ==> Statement ==> Connection
- 放在哪个代码块中:finally 块
![4c837aacf642a8c186ff0539fa34b8d0.png](https://i-blog.csdnimg.cn/blog_migrate/3ce54f5c4a242368112fdf7ae6e048f6.jpeg)
sql注入
Statement使用存在sql注入的问题
sql注入是攻击者通过sql注入漏洞绕过应用程序安全措施,检索整个sql数据库内容,甚至进行插入删除修改操作。简而言之,就是攻击者用拼接sql语句可以直接对sql进行增删改查。
比如select * from table where name = "+appName+",利用appName参数值的输入,来生成恶意的sql语句,如将['or'1'='1'] 传入可在数据库中执行。
String
- 如何解决
/*
* SQL注入
* 用户输入的用户名和密码 与我们编写的SQL进行了拼接,用户输入的内容成为了SQL语法的一部分,
* 用户会利用这里漏洞 输入一些其他的字符串,改变SQL原有的意思
* 如果解决
* 要解决SQL注入 就不能让用户输入的数据和我们的SQL进行直接的拼接
*
* 预处理对象 PrepareStatement 他是 Statement接口的子接口
* 使用预处理对象 他有预编译的功能,提高SQL的执行效率
* 使用预处理对象 通过占位符的方式 设置参数 可以有效的防止SQL注入
* */
//使用 ? 占位符的方式来设置参数
String sql = "select * from jdbc_user where username = ? and password = ?";
PreparedStatement ps = con.prepareStatement(sql);
//设置参数 使用setXXX(占位符的位置(整数),要设置的值)的方法设置占位符的参数
ps.setString(1,name); // 设置第一个问号值 为 name
ps.setString(2,pass);
预处理对象
public
对比
![3514156a4121e62c427c0a0fe7cf2dfe.png](https://i-blog.csdnimg.cn/blog_migrate/062b0665622aa546a8d9fbe5cc3ff9cb.jpeg)
事务执行
![1d67f57f00922752601d555d213d99c1.png](https://i-blog.csdnimg.cn/blog_migrate/48e638acba8ec849a11bfdd7a7aafc8b.jpeg)
/**
连接池
获取连接和释放资源非常消耗系统资源。解决此性能问题,使用连接池技术。
连接池管理数据库连接,重复使用连接
DBCP连接池
DBCP也是一个开源的连接池,是Apache成员之一,在企业开发中也比较常见,tomcat内置的连接池。
//创建连接池对象 (有DBCP提供的实现类)
![9fe963a9223108c04d6ebce8600923f9.png](https://i-blog.csdnimg.cn/blog_migrate/cf1a44c93623aeae98921cc0ca9cecd7.jpeg)
C3P0连接池
C3P0是一个开源的JDBC连接池,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、 Spring等。
- c3p0-config.xml
<c3p0-config>
Druid连接池
Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功 能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行 情况。
- druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db5?characterEncoding=UTF-8&rewriteBatchedStatements=true
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
//1.定义成员变量
public static DataSource dataSource;
//2.静态代码块
static{
try {
//3.创建属性集对象
Properties p = new Properties();
//4.加载配置文件 Druid 连接池不能够主动加载配置文件 ,需要指定文件
InputStream inputStream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//5. 使用Properties对象的 load方法 从字节流中读取配置信息
p.load(inputStream);
//6. 通过工厂类获取连接池对象
dataSource = DruidDataSourceFactory.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接的方法
dataSource.getConnection()
DBUtils
QueryRunner 中提供对sql语句操作的API.
ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
DbUtils类,他就是一个工具类,定义了关闭资源与事务处理相关方法.
//QueryRunner 核心类的创建方式
- 查询操作
/*
数据库批处理
批处理指的是一次操作中执行多条SQL语句,批处理相比于一次一次执行效率会提高很多。 当向数据库中添加大量的数据时,需要用到批处理。
- 打开数据库批处理
rewriteBatchedStatements=true
例如: url=jdbc:mysql://127.0.0.1:3306/db5?characterEncoding=UTF-8&rewriteBatchedStatements=true
//使用批处理 向表中添加 10000条数据
Mysql元数据
- 查询结果信息: UPDATE 或 DELETE语句 受影响的记录数。
- 数据库和数据表的信息: 包含了数据库及数据表的结构信息
- MySQL服务器信息: 包含了数据库服务器的当前状态,版本号等。
//1.获取数据库相关的元数据信息 使用DatabaseMetaData
XML
可扩展标记语言(Extensible Markup Language)
![69c9a7879464e27aefd5948ebad64406.png](https://i-blog.csdnimg.cn/blog_migrate/ab758a5bb592e248516a992786a25680.jpeg)
- 基本语法
<!-- XML的注释 -->
- 约束
<!-- dtd约束 -->
- 解析方式
DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象。
优点:元素与元素之间保留结构关系,故可以进行增删改查操作。
缺点:XML文档过大,可能出现内存溢出显现。
SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方 式进行具体解析,每执行一行,都将触发对应的事件。(了解)
优点:占用内存少 处理速度快,可以处理大文件
缺点:只能读,逐行后将释放资源。
- 解析器
JAXP:sun公司提供的解析器,支持DOM和SAX两种思想
DOM4J:一款非常优秀的解析器 , Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。 它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
Jsoup:jsoup 是一款Java 的HTML解析器 ,也可以解析XML
PULL:Android内置的XML解析方式,类似SAX。
- dom4j
常用API如下:
SaxReader对象- read(…) 加载执行xml文档 Document对象
- getRootElement() 获得根元素
Element对象
-
- elements(…) 获得指定名称的所有子元素。可以不指定名称
- element(…) 获得指定名称的第一个子元素。可以不指定名称
- getName() 获得当前元素的元素名
- attributeValue(…) 获得指定属性名的属性值
- elementText(…) 获得指定名称子元素的文本值
- getText() 获得当前元素的文本内容
- XPath
![a197b25c1b21f1d7f0ec8097e598825d.png](https://i-blog.csdnimg.cn/blog_migrate/cb2256e62b5eb5b82434b1943c34b071.jpeg)
public void test1() throws DocumentException {
//1.创建XML解析对象
SAXReader reader = new SAXReader();
//2.解析XML 获取 文档对象
Document document = reader.read("H:jdbc_workxml_task03srccomlagouxml04book.xml");
//通过selectSingleNode() 方法获取 name节点
Node node1 = document.selectSingleNode("/bookstore/book/name");
System.out.println("节点的名称: " + node1.getName());
System.out.println("书名: " + node1.getText());
//获取第二本书的书名
Node node2 = document.selectSingleNode("/bookstore/book[3]/name");
//获取第一个booke节点中的 id属性的值
Node node1 = document.selectSingleNode("/bookstore/book/attribute::id");
System.out.println("第一个book的id属性值: " + node1.getText() );
//获取最后一个book节点的 id属性值
Node node2 = document.selectSingleNode("/bookstore/book[last()]/attribute::id");
System.out.println("最后一个book节点中的属性值: " + node2.getText());
//通过id的值 获取book2节点 中的书名
Node node3 = document.selectSingleNode("/bookstore/book[@id='book2']");
String name = node3.selectSingleNode("name").getText();
System.out.println("id为book2的 节点的书名是: " + name);
System.out.println("书名: " + node2.getText());
}