任务五_JDBC
1.JDBC 概述
1.1客户端操作数据库的方式
1)方式1: 使用第三方客户端来访问 MySQL:SQLyog
2)方式2: 使用命令行
3)我们今天要学习的是通过 Java程序 来访问 MySQL 数据库
1.2什么是JDBC
JDBC( Java Data Base Connectivity) 是 Java 访问数据库的标准规范.是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范.
1.3JDBC 原理
JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。
总结:
JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口),而数据库厂商需要实现这套接口,提供数据库驱动jar包, 我们可以使用这套接口编程,真正执行的代码是对应驱动包中的实现类。
2.JDBC 开发
2.1数据准备
2.2MySql驱动包
1.将MySQL驱动包添加到jar包库文件夹中,Myjar文件夹,用于存放当前项目需要的所有jar包
2.在 idea中 配置jar包库的位置
3.创建一个新的项目jdbc_task01, 配置jar包库
2.3API使用: 1.注册驱动
JDBC规范定义驱动接口: java.sql.Driver
MySql驱动包提供了实现类:
加载注册驱动的方式 描述
Class.forName(数据库驱动实现类) 加载和注册数据库驱动,数据库驱动由数据库厂商MySql提供
“com.mysql.jdbc.Driver”
1)代码示例
2)为什么这样可以注册驱动?
我们知道 Class类的forName方法 ,可以将一个类初始化, 现在我们一起Driver类的 看一下源码
注:
从 JDBC3 开始,目前已经普遍使用的版本。可以不用注册驱动而直接使用。 Class.forName 这句话可以省略。
2.4API使用: 2.获得连接
Connection 接口,代表一个连接对象 ,具体的实现类由数据库的厂商实现使用 DriverManager类的静态方法,getConnection可以获取数据库的连接
获取连接的静态方法 说明
Connection getConnection(String url, String user, String password) 通过连接字符串和用户名,密码来获取数据库连接对象
1)getConnection方法 3个 连接参数说明
连接参数 说明
user 登录用户名
password 登录密码
url mySql URL的格式jdbc:mysql://localhost:3306/db4
2)对URL的详细说明
JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。 第一部分是协议 jdbc,这是固定的;
第二部分是子协议,就是数据库名称,连接mysql数据库,第二部分当然是mysql了;
第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及要使用的 数据库名称 组成。
3)代码示例
2.5API 使用: 3.获取语句执行平台
通过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结果集对象
代码示例
2.6API 使用: 4.处理结果集
只有在进行查询操作的时候, 才会处理结果集代码示例
2.6.1ResultSet接口
作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。
ResultSet接口方法 说明
boolean next() 1)游标向下一行
2)返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false
xxx getXxx( String or int) 1)通过列名,参数是 String 类型。返回不同的类型
2)通过列号,参数是整数,从 1 开始。返回不同的类型
代码示例
2.7API 使用: 5.释放资源
1)需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
2)释放原则:先开的后关,后开的先关。ResultSet ==> Statement ==> Connection
3)放在哪个代码块中:finally 块
与IO流一样,使用后的东西都需要关闭!关闭的顺序是先开后关, 先得到的后关闭,后得到的先关闭
代码示例
public static void main(String[] args) {
Connection connection = null; Statement statement = null; ResultSet resultSet = null;
try {
//1.注册驱动(省略)
//2.获取连接
String url = “jdbc:mysql://localhost:3306/db4”;
connection = DriverManager.getConnection(url, “root”, “123456”);
//3.获取 Statement对象
statement = connection.createStatement();
String sql = “select * from jdbc_user”; resultSet = statement.executeQuery(sql);
} catch (SQLException e) { e.printStackTrace();
} finally {
/**
*开启顺序: connection ==> statement => resultSet
*关闭顺序: resultSet ==> statement ==> connection
*/ try {
connection.close(); resultSet.close(); statement.close();
} catch (SQLException e) { e.printStackTrace();
}
}
}
}
2.8步骤总结
1.获取驱动(可以省略)
2.获取连接
3.获取Statement对象
4.处理结果集(只在查询时处理)
5.释放资源
3.JDBC实现增删改查
3.1JDBC工具类
什么时候自己创建工具类?
如果一个功能经常要用到,我们建议把这个功能做成一个工具类,可以在不同的地方重用。
“获得数据库连接”操作,将在以后的增删改查所有功能中都存在,可以封装工具类JDBCUtils。提供获取 连接对象的方法,从而达到代码的重复利用。
工具类包含的内容
1)可以把几个字符串定义成常量:用户名,密码,URL,驱动类
2)得到数据库的连接:getConnection()
3)关闭所有打开的资源:
代码示例
/**
//1. 定义字符串常量, 记录获取连接所需要的信息
public static final String DRIVERNAME = “com.mysql.jdbc.Driver”;
public static final String URL = “jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8”; public static final String USER = “root”;
public static final String PASSWORD = “123456”;
//2. 静态代码块, 随着类的加载而加载
static{
try {
//注册驱动Class.forName(DRIVERNAME);
} catch (ClassNotFoundException e) { e.printStackTrace();
}
}
//3.获取连接的静态方法
public static Connection getConnection(){
try {
//获取连接对象
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
//返回连接对象return connection;
} catch (SQLException e) { e.printStackTrace(); return null;
}
}
//关闭资源的方法
public static void close(Connection con, Statement st){
3.2DML操作
3.2.1插入记录
解决插入中文乱码问题.
代码示例
3.2.2更新记录
根据ID 需改用户名称
3.2.3删除记录
删除id为 3 和 4 的记录
3.3DQL操作
3.3.1 查询姓名为张百万的一条记录
4.SQL注入问题
4.1Sql注入演示
1)向jdbc_user表中 插入两条数据
2)SQL注入演示
如果这是一个登陆操作,那么用户就登陆成功了.显然这不是我们想要看到的结果
4.2sql注入案例:用户登陆
需求
用户在控制台上输入用户名和密码, 然后使用 Statement 字符串拼接的方式 实现用户的登录。
步骤
1)得到用户从控制台上输入的用户名和密码来查询数据库
2)写一个登录的方法
a)通过工具类得到连接
b)创建语句对象,使用拼接字符串的方式生成 SQL 语句
c)查询数据库,如果有记录则表示登录成功,否则登录失败
d)释放资源
代码示例
4.3问题分析
1)什么是SQL注入?
我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了 原有
SQL 真正的意义,以上问题称为 SQL 注入 .
2)如何实现的注入
根据用户输入的数据,拼接处的字符串
3)如何解决
要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进 行简单的字符串拼接。
5.预处理对象
5.1PreparedStatement 接口介绍
PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句对象.
预编译: 是指SQL 语句被预编译,并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。
5.2PreparedStatement 特 点
因为有预先编译的功能,提高 SQL 的执行效率。可以有效的防止 SQL 注入的问题,安全性更高
5.3获取PreparedStatement对象
通过Connection创建PreparedStatement对象
Connection 接口中的方法 说明
PreparedStatement prepareStatement(String sql) 指定预编译的 SQL 语句,
SQL 语句中使用占位符 ? 创建一个语句对象
5.4PreparedStatement接口常用方法
常用方法 说明
int executeUpdate(); 执行insert update delete语句.
ResultSet executeQuery(); 执行select语句. 返回结果集对象 Resulet
5.5使用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) 使用给定对象设置指定参数的值。
5.6使用PreparedStatement完成登录案例
使用 PreparedStatement 预处理对象,可以有效的避免SQL注入
步骤:
1.获取数据库连接对象 2.编写SQL 使用? 占位符方式 3.获取预处理对象 (预编译对象会将Sql发送给数据库 进行预编译) 4.提示用户输入用户名 & 密码 5.设置实际参数:setXxx(占位符的位置, 真实的值) 6.执行查询获取结果集 7.判断是否查询到数据 8.关闭资源
5.7PreparedStatement的执行原理
分别使用 Statement对象 和 PreparedStatement对象进行插入操作代码示例
5.8Statement 与 PreparedStatement的区别?
1.Statement用于执行静态SQL语句,在执行时,必须指定一个事先准备好的SQL语句。
2.PrepareStatement是预编译的SQL语句对象,语句中可以包含动态参数“?”,在执行时可以为“?”动态设置参数 值。
3.PrepareStatement可以减少编译次数提高数据库性能。
6.JDBC 控制事务
之前我们是使用 MySQL 的命令来操作事务。接下来我们使用 JDBC 来操作银行转账的事务。
6.1数据准备
6.2事务相关API
我们使用 Connection中的方法实现事务管理
方法 说明
void setAutoCommit(boolean autoCommit) 参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务
void commit() 提交事务
void rollback() 回滚事务
6.3开发步骤
1.获取连接
2.开启事务
3.获取到 PreparedStatement , 执行两次更新操作
4.正常情况下提交事务
5.出现异常回滚事务
6.最后关闭资源
6.4代码示例
public class JDBCTransaction {
//JDBC 操作事务
public static void main(String[] args) {
Connection con = null; PreparedStatement ps = null;
try {
//1. 获取连接
con = JDBCUtils.getConnection();
//2. 开启事务
con.setAutoCommit(false);
//3. 获取到 PreparedStatement 执行两次更新操作
//3.1 tom 账 户 -500
ps = con.prepareStatement("update account set money = money - ? where name = ? "); ps.setDouble(1,500.0);
ps.setString(2,“tom”); ps.executeUpdate();
//模拟tom转账后 出现异常
System.out.println(1 / 0);
//3.2 jack 账 户 +500
ps = con.prepareStatement("update account set money = money + ? where name = ? "); ps.setDouble(1,500.0);
ps.setString(2,“jack”); ps.executeUpdate();
//4. 正常情况下提交事务con.commit(); System.out.println(“转账成功!”);
} catch (SQLException e) {
e.printStackTrace(); try {
//5. 出现异常回滚事务
con.rollback();
} catch (SQLException ex) { ex.printStackTrace();
}
} finally {
//6. 最后关闭资源
JDBCUtils.close(con,ps);
}
}
}
任务六_数据库连接池&DBUtils
1.数据库连接池
1.1连接池介绍
1)什么是连接池
实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池.
2)连接池的好处
用池来管理Connection,这样可以重复使用Connection。 当使用完Connection后,调用Connection的
close()方法也不会真的关闭Connection,而是把Connection“归还”给池。
1.2JDBC方式与连接池方式
普通 JDBC方式
连接池方式
1.3如何使用数据库连接池
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。 这样应用程序可以方便的切换不同厂商的连接池!
常见的连接池有 DBCP连接池, C3P0连接池, Druid连接池, 接下里我们就详细学习一下
1.4数据准备
1.5DBCP连接池
DBCP也是一个开源的连接池,是Apache成员之一,在企业开发中也比较常见,tomcat内置的连接池。
1.5.1创建项目 导入 jar包
1)将这两个 jar包添加到 myJar文件夹中 (jar包在资料里的软件文件夹中)
2)添加myJar库 到项目的依赖中
1.5.2编写工具类
连接数据库表的工具类, 采用DBCP连接池的方式来完成
Java中提供了一个连接池的规则接口 :
, 它是java中提供的连接池
在DBCP包中提供了DataSource接口的实现类,我们要用的具体的连接池 类
代码示例
1.5.3测试工具类
需求: 查询所有员工的姓名
1.5.4常见配置项
属性 描述
driverClassName 数据库驱动名称
url 数据库地址
username 用户名
password 密码
maxActive 最大连接数量
maxIdle 最大空闲连接
minIdle 最小空闲连接
initialSize 初始化连接
1.6C3P0连接池
C3P0是一个开源的JDBC连接池,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。
1.6.1导入jar包及配置文件
1)将jar包 复制到myJar文件夹即可,IDEA会自动导入
2)导入配置文件 c3p0-config.xml
c3p0-config.xml 文件名不可更改
直接放到src下,也可以放到到资源文件夹中
3
60
100
10
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/db5
root
123456
10
30
100
10
3)在项目下创建一个resource文件夹(专门存放资源文件)
4)选择文件夹,右键 将resource文件夹指定为资源文件夹
5)将文件放在resource目录下即可,创建连接池对象的时候会去加载这个配置文件
1.6.2编写C3P0工具类
C3P0提供的核心工具类,
, 如果想使用连接池,就必须创建该类的对象
new ComboPooledDataSource(); 使用 默认配置
new ComboPooledDataSource(“mysql”); 使用命名配置
1.6.3测试工具类
需求: 查询姓名为 李白的员工信息
1.6.4常见配置
1.7Druid连接池
Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功
能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。
1.7.1导入jar包及配置文件
1)导入 jar包
2)导入配置文件
是properties形式的
可以叫任意名称,可以放在任意目录下,我们统一放到 resources资源目录
1.7.2编写Druid工具类
获取数据库连接池对象
通过工厂来来获取 DruidDataSourceFactory类的createDataSource方法createDataSource(Properties p) 方法参数可以是一个属性集对象
//获取连接的方法
public static Connection getConnection(){ try {
return dataSource.getConnection();
} catch (SQLException e) { e.printStackTrace(); return null;
}
}
//释放资源
public static void close(Connection con, Statement statement){
if(con != null && statement != null){ try {
statement.close();
//归还连接con.close();
} catch (SQLException e) { e.printStackTrace();
}
}
}
public static void close(Connection con, Statement statement, ResultSet resultSet){ if(con != null && statement != null && resultSet != null){
try {
resultSet.close(); statement.close();
//归还连接
con.close();
} catch (SQLException e) { e.printStackTrace();
}
}
}
}
1.7.3测试工具类
需求: 查询薪资在3000 - 5000元之间的员工姓名
2.DBUtils工具类
2.1DBUtils简介
使用JDBC我们发现冗余的代码太多了,为了简化开发 我们选择使用 DbUtils
Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。
使用方式:
DBUtils就是JDBC的简化开发工具包。需要项目导入 commons-dbutils-1.6.jar。
2.1.1Dbutils核心功能介绍
1.QueryRunner 中提供对sql语句操作的API.
2.ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
3.DbUtils类,他就是一个工具类,定义了关闭资源与事务处理相关方法.
2.2案例相关知识
2.2.1表和类之间的关系
整个表可以看做是一个类
表中的一行记录,对应一个类的实例(对象) 表中的一列,对应类中的一个成员属性
2.2.2JavaBean组件
1)JavaBean 就是一个类, 开发中通常用于封装数据,有一下特点
1.需要实现 序列化接口, Serializable (暂时可以省略)
2.提供私有字段: private 类型 变量名;
3.提 供 getter 和 setter
4.提供 空参构造
2)创建Employee类和数据库的employee表对应
我们可以创建一个 entity包,专门用来存放 JavaBean类
2.3DBUtils完成 CRUD
2.3.1QueryRunner核心类
构造方法
常用方法
作
数据的查询操作
2.3.2QueryRunner的创建
手动模式
,提供数据源(连接池),DBUtils底层自动维护连接connection
,用来完成表数据的增加、删除、更新操
,用来完成表
自动模式
自动模式需要传入连接池对象
2.3.3QueryRunner实现增、删、改操作
核心方法
update(Connection conn, String sql, Object… params)
参数 说明
Connection conn 数据库连接对象, 自动模式创建QueryRun 可以不传 ,手动模式必须传递
String sql 占位符形式的SQL ,使用 ? 号占位符
Object… param Object类型的 可变参,用来设置占位符上的参数
步骤
1.创建QueryRunner(手动或自动) 2.占位符方式 编写SQL
3.设置占位符参数
4.执行
2.3.3.1添加
2.3.3.2修改
2.3.3.3删除
2.3.4QueryRunner实现查询操作
2.3.4.1ResultSetHandler接口简介
ResultSetHandler可以对查询出来的ResultSet结果集进行处理,达到一些业务上的需求。
2.3.4.2ResultSetHandler 结果集处理类
本例展示的是使用ResultSetHandler接口的几个常见实现类实现数据库的增删改查,可以大大减少代码量,优化 程序。
每一种实现类都代表了对查询结果集的一种处理方式
ResultSetHandler
实现类 说明
ArrayHandler 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值
ArrayListHandler 将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集 合中。
BeanHandler 将结果集中第一条记录封装到一个指定的javaBean中.
BeanListHandler 将结果集中每一条记录封装到指定的javaBean中,再将这些javaBean在封装到List 集合中
ColumnListHandler 将结果集中指定的列的字段值,封装到一个List集合中
KeyedHandler 将结果集中每一条记录封装到Map
Map的value,另一个Map集合的key是指定的字段的值。
MapHandler 将结果集中第一条记录封装到了Map
value就是字段值
MapListHandler 将结果集中每一条记录封装到了Map
value就是字段值,在将这些Map封装到List集合中。
ScalarHandler 它是用于封装单个数据。例如 select count(*) from 表操作。
2.3.4.3ResultSetHandler 常用实现类测试
QueryRunner的查询方法
query方法的返回值都是泛型,具体的返回值类型,会根据结果集的处理方式,发生变化
方法 说明
query(String sql, handler ,Object[] param) 自动模式创建QueryRunner, 执行查询 query(Connection con,String sql,handler,Object[] param) 手动模式创建QueryRunner, 执行查询
创建一个测试类, 对ResultSetHandler接口的几个常见实现类进行测试查询id为5的记录,封装到数组中
查询所有数据,封装到List集合中
查询id为5的记录,封装到指定JavaBean中
查询薪资大于 3000 的所员工信息,封装到JavaBean中再封装到List集合中查询姓名是 张百万的员工信息,将结果封装到Map集合中
查询所有员工的薪资总额
1)查询id为5的记录,封装到数组中
2)查询所有数据,封装到List集合中
3)根据ID查询,封装到指定JavaBean中
4)查询薪资大于 3000 的所员工信息,封装到JavaBean中再封装到List集合中
5)查询姓名是 张百万的员工信息,将结果封装到Map集合中
6)查询所有员工的薪资总额
3.数据库批处理
3.1什么是批处理
批处理(batch) 操作数据库
批处理指的是一次操作中执行多条SQL语句,批处理相比于一次一次执行效率会提高很多。当向数据库中添加大量的数据时,需要用到批处理。
举例: 送货员的工作:
未使用批处理的时候,送货员每次只能运送 一件货物给商家;
使用批处理,则是送货员将所有要运送的货物, 都用车带到发放处派给客户。
3.2实现批处理
Statement和PreparedStatement都支持批处理操作,这里我们介绍一下PreparedStatement的批处理方式:
1)要用到的方法
方法 说明
void addBatch() 将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。通过调用方法 executeBatch 可以批量执行此列表中的命令。
int[] executeBatch() 每次提交一批命令到数据库中执行,如果所有的命令都成功执行了, 那么返回一个数组,这个数组是说明每条命令所影响的行数
2)mysql 批处理是默认关闭的,所以需要加一个参数才打开mysql 数据库批处理,在url中添加
3)创建一张表
4)测试向表中插入 1万条数据
4.MySql元数据
4.1什么是元数据
除了表之外的数据都是元数据,可以分为三类
查询结果信息: UPDATE 或 DELETE语句 受影响的记录数。数据库和数据表的信息: 包含了数据库及数据表的结构信息。
MySQL服务器信息: 包含了数据库服务器的当前状态,版本号等。
4.2常用命令
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(): 获取当前的数据库名
4.3使用JDBC 获取元数据
通过JDBC 也可以获取到元数据,比如数据库的相关信息,或者当我们使用程序查询一个不熟悉的表时, 我们可以通过获取元素据信息,了解表中有多少个字段,字段的名称 和 字段的类型.
4.3.1常用类介绍
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开始
4.3.2代码示例
String driverName = metaData.getDriverName(); System.out.println("驱动名称: " + driverName);
//判断当前数据库是否只允许只读
boolean b = metaData.isReadOnly(); //如果是 true 就表示 只读
if(b){
System.out.println(“当前数据库只允许读操作!”);
}else{
System.out.println(“不是只读数据库”);
}
connection.close();
}
//获取结果集中的元数据信息@Test
public void testResultSetMetaData() throws SQLException {
//1.获取连接
Connection con = DruidUtils.getConnection();
//2.获取预处理对象
PreparedStatement ps = con.prepareStatement(“select * from employee”); ResultSet resultSet = ps.executeQuery();
//3.获取结果集元素据对象
ResultSetMetaData metaData = ps.getMetaData();
//1.获取当前结果集 共有多少列
int count = metaData.getColumnCount(); System.out.println(“当前结果集中共有: " + count + " 列”);
//2.获结果集中 列的名称 和 类型
for (int i = 1; i <= count; i++) {
String columnName = metaData.getColumnName(i); System.out.println("列名: "+ columnName);
String columnTypeName = metaData.getColumnTypeName(i); System.out.println("类型: " +columnTypeName);
}
//释放资源DruidUtils.close(con,ps,resultSet);
}
}
任务七_XML
1.XML基本介绍
1.1概述
XML即可扩展标记语言(Extensible Markup Language)
W3C在1998年2月发布1.0版本,2004年2月又发布1.1版本,但因为1.1版本不能向下兼容1.0版本,所以1.1没 有人用。同时,在2004年2月W3C又发布了1.0版本的第三版。我们要学习的还是1.0版本 !
特点
可扩展的, 标签都是自定义的语法十分严格
1.2XML的作用
XML能做什么?
功能 说明
存储数据 通常,我们在数据库中存储数据。不过,如果希望数据的可移植性更强,我们可以把数据存 储 XML 文件中
配置文件 作为各种技术框架的配置文件使用 (最多)
在网络中传输 客户端可以使用XML格式向服务器端发送数据,服务器接收到xml格式数据,进行解析
2.XML的语法
2.1XML文档声明格式
文档声明必须为结束; 文档声明必写在第一行;
1)语法格式:
2)属性说明:
versioin:指定XML文档版本。必须属性,因为我们不会选择1.1,只会选择1.0; encoding:指定当前文档的编码。可选属性,默认值是utf-8;
2.2元素
Element 元素: 是XML文档中最重要的组成部分元素的命名规则
1.不能使用空格,不能使用冒号
2.xml 标签名称区分大小写
3.XML 必须有且只有一个根元素
语法格式:
1)XML 必须有且只有一个根元素,它是所有其他元素的父元素,比如以下实例中 users 就是根元素:
2)普通元素的结构开始标签、元素体、结束标签组成。
3)元素体:元素体可以是元素,也可以是文本
4)空元素:空元素只有开始标签,而没有结束标签,但元素必须自己闭合
2.3属性
1.属性是元素的一部分,它必须出现在元素的开始标签中
2.属性的定义格式:属性名=属性值,其中属性值必须使用单引或双引
3.一个元素可以有0~N个属性,但一个元素中不能出现同名属性
4.属性名不能使用空格、冒号等特殊字符,且必须以字母开头
2.4注释
XML的注释,以“ ”结束。注释内容会被XML解析器忽略!
2.5使用XML 描述数据表中的数据
3.XML约束
在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束。 常见的xml约束:
DTD
Schema
作为程序员只要掌握两点会阅读
会引入
不用自己编写
3.1DTD约束
DTD(Document Type Definition),文档类型定义,用来约束XML文档。规定XML文档中元素的名称,子元素的名称及顺序,元素的属性等。
3.1.1编写DTD
开发中,我们不会自己编写DTD约束文档
常情况我们都是通过框架提供的DTD约束文档,编写对应的XML文档。常见框架使用DTD约束有:Struts2、
hibernate等。
创建约束文件 student.dtd
3.1.2引入DTD
引入dtd文档到xml文档中,两种方式
内部dtd:将约束规则定义在xml文档中
外部dtd:将约束的规则定义在外部的dtd文件中
本地: 网络:
student.xml
3.2Schema约束
3.2.1什么是Schema
1.Schema是新的XML文档约束, 比DTD强大很多,是DTD 替代者;
2.Schema本身也是XML文档,但Schema文档的扩展名为xsd,而不是xml。
3.Schema 功能更强大,内置多种简单和复杂的数据类型
4.Schema 支持命名空间 (一个XML中可以引入多个约束文档)
3.2.2Schema约束示例
student.xsd
xsd:sequence
xsd:sequence
Xml Schema的根元素:
3.2.3XML引入Schema约束
xml中引入schema约束的步骤:
1)查看schema文档,找到根元素,在xml中写出来
2)根元素来自哪个命名空间。使用xmlns指令来声明
3)引入 w3c的标准命名空间, 复制即可
4)引入的命名空间跟哪个xsd文件对应? 使用schemaLocation来指定:两个取值:第一个为命名空间 第二个为
xsd文件的路径
5)命名空间
6)student.xml
4.XML 解析
4.1解析概述
当将数据存储在XML后,我们就希望通过程序获得XML的内容。如果我们使用Java基础所学习的IO知识是可以完成 的,不过你需要非常繁琐的操作才可以完成,且开发中会遇到不同问题(只读、读写)。人们为不同问题提供不同 的解析方式,并提交对应的解析器,方便开发人员操作XML。
4.2XML解析方式
开发中比较常见的解析方式有两种,如下:
DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象。 优点:元素与元素之间保留结构关系,故可以进行增删改查操作。
缺点:XML文档过大,可能出现内存溢出显现。
SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都将触发对应的事件。(了解)
优点:占用内存少 处理速度快,可以处理大文件缺点:只能读,逐行后将释放资源。
4.3XML常见的解析器
解析器:就是根据不同的解析方式提供的具体实现。有的解析器操作过于繁琐,为了方便开发人员,有提供易于操 作的解析开发包
JAXP:sun公司提供的解析器,支持DOM和SAX两种思想
DOM4J:一款非常优秀的解析器 , Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
Jsoup:jsoup 是一款Java 的HTML解析器 ,也可以解析XML PULL:Android内置的XML解析方式,类似SAX。
4.4dom4j 的使用
4.4.1导入JAR包
4.4.2API介绍
使用核心类SaxReader加载xml文档获得Document,通过Document 对象获得文档的根元素,然后就可以操作了常用API如下:
SaxReader对象
read(…) 加载执行xml文档
Document对象
getRootElement() 获得根元素
Element对象
elements(…) 获得指定名称的所有子元素。可以不指定名称element(…) 获得指定名称的第一个子元素。可以不指定名称getName() 获得当前元素的元素名
attributeValue(…) 获得指定属性名的属性值elementText(…) 获得指定名称子元素的文本值getText() 获得当前元素的文本内容
4.4.3准备xml文件
编写user.xsd schema约束
编写user.xml 引入约束
4.4.4读取XML
public class TestDOM4j {
//获取XML文件中的 所有的元素名称(标签) @Test
public void test1() throws DocumentException {
//1.获取XML解析对象
SAXReader reader = new SAXReader();
//2.解析XML 获取 文档对象 document Document document =
reader.read(“H:\jdbc_work\xml_task03\src\com\lagou\xml03\user.xml”);
//3.获取根元素
Element rootElement = document.getRootElement();
//获取根元素名称System.out.println(rootElement.getName());
//获取 根元素下的标签
List elements = rootElement.elements(); for (Element element : elements) {
System.out.println("根标签下的子节点: " + element.getName());
List eList = element.elements(); for (Element e : eList) {
System.out.println(“user标签下的子节点” + e.getName());
}
break;
}
}
/**
public void test2() throws DocumentException {
4.5xpath方式读取xml
4.5.1xpath介绍
XPath 是一门在 XML 文档中查找信息的语言。 可以是使用xpath查找xml中的内容。
XPath 的好处
由于DOM4J在解析XML时只能一层一层解析,所以当XML文件层数过多时使用会很不方便,结合XPATH就可以直 接获取到某个元素
1)需要再导入 jaxen-1.1-beta-6.jar
4.5.2XPath基本语法介绍
使用dom4j支持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
4.5.3API介绍
2)常用方法:
selectSingleNode(query): 查找和 XPath 查询匹配的一个节点。参数是Xpath 查询串。
selectNodes(query): 得到的是xml根节点下的所有满足 xpath 的节点; 参数是Xpath 查询串。
Node: 节点对象
4.5.4Xpath读取XML
3)数据准备 book.xml
4)代码示例
1.使用selectSingleNode方法 查询指定节点中的内容
2.使用selectSingleNode方法 获取属性值,或者属性值对应的节点
3.使用 selectNodes()方法 获取对应名称的所有节点
5.JDBC自定义XML
5.1定义配置文件
1)创建自定义xml 文件, 保存 数据库连接信息
jdbc-config.xml
5.2编写工具类(配置式)
2)编写工具类 ,使用xpath 读取数据库信息
5.3测试工具类
3)测试 : 获取所有员工的姓名
任务八 综合案例
1.商城案例表设计
通过对商城项目的部分表关系进行分析,完成数据库表的设计
1.1表关系分析
1.2建库,建表
1)创建名为 store的数据库, 对应商城项目
2)创建用户表
3)创建订单表
4)创建商品分类表
5)创建商品表
2.环境搭建
2.1项目结构
2.2导入所需Jar包
2.3导入配置文件及工具类
3.JavaBean类创建
3.1设计用户与订单
3.1.1一对多关系分析
在Java一对多的数据关系中,需要遵循以下设计原则:
1.Java类的名称 = 实体表的名称
2.Java类的属性 = 实体表的字段
3.Java类的一个对象 = 表的一行记录
4.外键关系 = 引用配置
一个用户拥有多个订单,所以 用户是一的一方, 订单是多的一方
3.1.2User类
3.1.3Orders类
3.1.4Orders类设计分析
第一种方式
根据两张表关系的描述 我们可以在 订单类中 添加一个uid 成员变量,表示订单属于哪个用户
但是这样设计会存在一些问题,比如 我要查询的是订单是属于哪个用户的用户名 ? 但是我们只有一个uid 第二种方式
Java类表示一对多关系,可以在多的一方添加一个成员变量,这个成员变量的类型 就是一的一方的类型.
再在订单表中 添加一个 User对象,User对象中 ,保存该订单关联的用户的所有信息
3.1.4 修改Orders类
3.2设计商品与分类
分类与商品 同样是一对多关系, 我们可以在多的一方进行操作 添加一个成员变量 类型是一的一方的类型
3.2.1Category类
3.2.2Product类
3.3设计订单项
3.3.1多对多关系分析
商品与订单是多对多关系, 一个订单上可以有多个商品, 一个商品可以出现在多个订单中.
多对多建表原则 需要一张中间表,中间表中至少有两个字段,作为中间表的外键分别指向另外两张表的主键
3.3.2创建OrderItem
4.编写DAO类
4.1UserDao
需求一: 编写一个注册用户的方法,接收的参数是一个User对象
需求二: 编写一个 用户登录的方法,接收的参数是 用户名 和密码, 返回值是User对象
4.1.1编写UserDao
public class UserDao {
/**
//1.获取QueryRunner
QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
//2.编写SQL
String sql = “insert into user values(?,?,?,?,?,?)”;
Object[] param = {user.getUid(), user.getUsername(), user.getPassword(), user.getTelephone(), user.getBirthday(), user.getSex()};
//3.执行插入操作
int update = qr.update(sql,param);
//4.返回受影响的行数return update;
}
/**
//返回的是一个User对象 使用BeanHandler将结果集的第一条和数据封装到一个Javabean中
User user = qr.query(sql, new BeanHandler(User.class), username, password);
return user;
}
4.1.2测试注册与登录功能
public class TestUserDao {
//创建UserDao
UserDao userDao = new UserDao();
//测试注册功能@Test
public void testRegister() throws SQLException {
//1. 创建User对象
User user = new User();
//2. 对User对象进行赋值user.setUid(UUIDUtils.getUUID()); user.setUsername(" 大 郎 “); user.setPassword(“654321”); user.setTelephone(“15052005200”); user.setSex(” 男 "); user.setBirthday(DateUtils.getDateFormart());
//3.执行注册
int register = userDao.register(user);
//4.判断注册是否成功if(register > 0){
System.out.println("注册成功,欢迎您: " + user.getUsername());
}else{
System.out.println(“注册失败! !”);
}
}
//测试登录功能@Test
public void testLogin() throws SQLException {
//调用UserDao的 login方法,传入用户名密码
User user = userDao.login(“大郎”, “654321”);
//判断user不为空 登录成功
if(user != null){ System.out.println(user.getUsername() +" 欢迎您!");
}else{
System.out.println(“用户名或者密码错误! !”);
}
}
}
4.2ProductDao
需求1: 根据商品ID 获取商品名称 ,商品价格 以及商品所属分类的名称参数 pid, 返回值 product对象
需求2: 根据分类ID 获取商品分类信息
参数 cid , 返回值 category对象需求3: 查询指定分类ID 下的商品个数
参数 cid , 返回值 int类型 商品个数需求4: 查询指定分类ID 下的所有商品信息
参数分类ID ,返回值 List集合 集合中保存商品对象
4.2.1编写 ProductDao
4.2.2测试 ProductDao
4.3OrdersDao
4.3.1多对一分析
OrderItem表与Orders表的关系是 多对一
之前我们一直是在描述一对多,那么我们再反向描述一下 多对一方式是在Orders中应该有一个 集合用来保存订单中的订单项信息
在Orders类中添加 订单项的集合
4.3.2创建OrdersDao
需求1: 获取 uid为 001 的用户的所有订单信息参数 uid, 返回值 LIst 订单集合
需求2: 获取订单编号为 order001的订单中的所有商品信息参数 oid, 返回值List 商品集合
public class OrdersDao {
//需求1: 获取 uid为 001 的用户的所有订单信息
public List findAllOrders(String uid) throws SQLException { QueryRunner qr = new QueryRunner(DruidUtils.getDataSource()); String sql = “select * from orders where uid = ?”;
//一个用户所有的订单信息
List ordersList = qr.query(sql, new BeanListHandler(Orders.class), uid);
return ordersList;
}
//需求2: 获取订单编号为 order001的订单中的所有商品信息
public List findOrderById(String oid) throws SQLException { QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
//1.查询订单项表 获取订单项表中 订单ID为order001的数据
String sql = "SELECT pid FROM orderitem WHERE oid = ? ";
oid);
//2.查询的结果是 多条订单项数据
List list = qr.query(sql, new BeanListHandler(OrderItem.class),
//3.创建集合保存商品信息
List productList = new ArrayList<>(); ProductDao productDao = new ProductDao();
//4.遍历订单项集合 获取Pid
for (OrderItem orderItem : list) {
//4.1 从 orderitem 中 获 取 pid String pid = orderItem.getPid();
//4.2 调用productDao
4.3.3测试OrdersDao
编程题1
数据准备
1)创建数据库
2)创建表:account(账户表),有如下结构及数据:(复制以下SQL语句执行)
代码编写
1)创建项目 Test_01
2)导入jar包
3)创建包 包结构为
编程题2
数据准备
代码编写
1)继续在项目 Test_01中编写代码即可
2)需求1: 查询价格高于2000元,生产日期是2019年之前的所有手机
3)需求2: 查询所有颜色是白色的手机信息
编程题3
数据准备
1)创建表:dept(部门表),有如下结构及数据:(复制以下SQL语句执行)
2)创建表:employee(员工表) (复制以下SQL语句执行)
代码编写