模块二 JDBC和XML
JDBC
-
什么是JDBC?
- 一套操作关系型数据库的规则(接口)
- 数据库厂商需要实现这套接口,并且提供数据库驱动jar包
- 我们去使用这套接口,真正执行的是对应的驱动包中的实现类
- Java代码访问数据库的标准规范(接口),具体的实现方式由数据库厂商完成
- 面向接口编程,不依赖于任何数据库
-
第一步 注册驱动(可省略)
Class.forName("com.mysql.jdbc.Driver");
// Driver类是由mysql驱动包提供的一个实现类,实现了java.sql.Driver
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
// 静态代码块 随着类的加载而加载,只加载一次
static {
try {
//DriverManager就是驱动管理类,registerDriver方法就是用来注册驱动的
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
- 第二步 获得连接,连接对象
- URL:jdbc:mysql//localhost:3306/db4?characterEncoding=UTF-8
- 协议名://主机:端口号/数据库名?参数=参数值
//url:jdbc:mysql://localhost:3306/db4
//user:root
//password:123456
public static Connection getConnection(String url,
String user, String password) ;
DriverManager.getConnection("","","");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db4", "root", "123456");
//com.mysql.jdbc.JDBC4Connection@1aa7ecca 对象由mysql包提供
System.out.println(connection);
- 第三步 获取语句执行平台
Connection connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/db4", "root", "123456");
//com.mysql.jdbc.JDBC4Connection@1aa7ecca
System.out.println(connection);
//获取Statement对象
Statement statement = connection.createStatement();
//返回受影响的行数
int i = statement.executeUpdate("create table test(id int,name varchar(20));");
System.out.println(i);
//关闭流
statement.close();
connection.close();
-
第四步 处理结果集
- ResultSet接口方法
方法名 功能介绍 boolean next() 方法 判断是否下一条数据 xxx getXXx(String or int) 如果传递的参数是String类型,则表示通过列名查询
如果传递的参数是int类型,则表示通过列号查询
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db4", "root", "123456");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from jdbc_user;");
while (resultSet.next()){
System.out.print(resultSet.getInt("id"));
System.out.print(resultSet.getString("username"));
System.out.print(resultSet.getString("password"));
System.out.println(resultSet.getDate("birthday"));
}
resultSet.close();
statement.close();
connection.close();
}
- 第五步 释放资源
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db4", "root", "123456");
statement = connection.createStatement();
resultSet = statement.executeQuery("select * from jdbc_user;");
while (resultSet.next()) {
System.out.print(resultSet.getInt("id"));
System.out.print(resultSet.getString("username"));
System.out.print(resultSet.getString("password"));
System.out.println(resultSet.getDate("birthday"));
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
resultSet.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
SQL注入
- 字符串拼接SQL语句容易造成SQL注入问题,不安全
- 条件语句 + or 1=1;
select * from user where username = '123' or 1 = 1;
- 使用预处理对象方式防止SQL注入
- PerpareStatement是Statement接口的子接口
- 预处理对象具有预编译的功能,提高SQL的执行效率
- 预处理对象使用占位符的方式
public static void main(String[] args) {
Connection connection = null;
PreparedStatement ps = null;
Scanner sc = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/db4", "root", "123456");
String sql = "select * from jdbc_user where username = ? and password = ?";
ps = connection.prepareStatement(sql);
sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = sc.next();
System.out.println("请输入密码:");
String password = sc.next();
//给占位符赋值
ps.setString(1, username);
ps.setString(2, password);
resultSet = ps.executeQuery();
if (resultSet.next()) {
System.out.println("登录成功!");
} else {
System.out.println("登录失败!");
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
resultSet.close();
sc.close();
ps.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
JDBC控制事务
- 使用Connection中的方法实现事务管理
方法名 | 功能介绍 |
---|---|
void setAutoCommit(boolean autoCommit) | 参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务 |
void commit() | 提交事务 |
void rollback() | 回滚事务 |
public static void main(String[] args) {
Connection connection = null;
PreparedStatement ps = null;
PreparedStatement ps2 = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/db4", "root", "123456");
//开启事务 false代表手动提交事务
connection.setAutoCommit(false);
String sql1 = "update account set money = money - ? where name = ?";
String sql2 = "update account set money = money + ? where NAME = ?";
ps = connection.prepareStatement(sql1);
ps.setDouble(1,500.0);
ps.setString(2,"tom");
ps.executeUpdate();
ps2 = connection.prepareStatement(sql2);
ps2.setDouble(1,500.0);
ps2.setString(2,"jack");
ps2.executeUpdate();
//提交事务
connection.commit();
System.out.println("转账成功");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
//发生异常后回滚
try {
System.out.println("发生异常,执行回滚操作");
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} finally {
try {
ps2.close();
ps.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
数据库连接池
- 什么是连接池
- 管理数据库连接,可以重复的使用连接
- 关闭连接不代表销毁了connection,只是将连接进行了归还
- DataSource
- javax.sql.DataSource接口,各个厂商需要让自己的连接池实现这个接口
- 常见连接池
- DBCP连接池
- C3P0连接池
- Druid连接池(阿里)
DBCP连接池
- 导入apache.commons.dbcp包
- 编写dbcp连接池工具类
package com.lagou.utils;
import org.apache.commons.dbcp.BasicDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DBCPUtils {
//1.定义常量 保存数据库连接信息
public static final String DRIVER_NAME = "com.mysql.jdbc.Driver";
public static final String URL = "jdbc:mysql://localhost:3306/db5?characterEncoding=UTF-8";
public static final String USERNAME = "root";
public static final String PASSWORD = "123456";
//2.创建连接池对象(由DBCP提供的)
public static BasicDataSource bds = new BasicDataSource();
//3.使用静态代码块进行配置
static {
bds.setDriverClassName(DRIVER_NAME);
bds.setUrl(URL);
bds.setUsername(USERNAME);
bds.setPassword(PASSWORD);
}
//4.获取连接的方法
public static Connection getConnection() throws SQLException {
//从连接池中获取连接
return bds.getConnection();
}
//5.关闭连接释放资源
public static void close(Connection connection, Statement statement) {
if (connection != null && statement != null) {
try {
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//重载方法关闭ResultSet查询连接
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
if (connection != null && statement != null && resultSet != null) {
try {
resultSet.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- 测试
public class TestDBCP {
public static void main(String[] args) throws SQLException {
//1.从DBCP连接池中获取连接
Connection connection = DBCPUtils.getConnection();
//2.获取Statement对象
Statement statement = connection.createStatement();
//3.查询所有员工姓名
String sql = "select ename from employee";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println(resultSet.getString("ename"));
}
//4.释放资源
DBCPUtils.close(connection,statement,resultSet);
}
}
- 常用配置项
属性 | 功能介绍 |
---|---|
driverClassName | 数据库驱动名称 |
url | 数据库地址 |
username | 用户名 |
password | 密码 |
maxActive | 最大连接数量 |
maxIdle | 最大空闲连接 |
minIdle | 最小空闲连接 |
initialSize | 初始化连接 |
C3P0连接池
- C3P0是一个开源的JDBC连接池,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等
- 导入C3P0相关jar包和配置文件
<c3p0-config>
<!--默认配置-->
<default-config>
<!-- initialPoolSize:初始化时获取三个连接,
取值应在minPoolSize与maxPoolSize之间。 -->
<property name="initialPoolSize">3</property>
<!-- maxIdleTime:最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。-->
<property name="maxIdleTime">60</property>
<!-- maxPoolSize:连接池中保留的最大连接数 -->
<property name="maxPoolSize">100</property>
<!-- minPoolSize: 连接池中保留的最小连接数 -->
<property name="minPoolSize">10</property>
</default-config>
<!--配置连接池mysql-->
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db5?characterEncoding=UTF-8</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
</named-config>
<!--配置连接池2,可以配置多个-->
</c3p0-config>
- C3P0工具类编写
package com.lagou.utils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class C3P0Utils {
//1.创建连接池对象 C3P0对DataSource接口的实现类
//使用无参构造方法使用的是默认配置
//public static ComboPooledDataSource dataSource = new ComboPooledDataSource();
//使用自定义配置 使用的是c3p0-config.xml中<named-config name="mysql">
public static ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
//2.获取连接对象
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//3.关闭连接释放资源
public static void close(Connection connection, Statement statement) {
if (connection != null && statement != null) {
try {
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//重载方法关闭ResultSet查询连接
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
if (connection != null && statement != null && resultSet != null) {
try {
resultSet.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- 测试
package com.lagou.testpool;
import com.lagou.utils.C3P0Utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestC3P0 {
public static void main(String[] args) throws SQLException {
//1.从C3P0连接池中获取连接
Connection connection = C3P0Utils.getConnection();
//2.获取Statement对象
Statement statement = connection.createStatement();
//3.查询所有员工姓名
String sql = "select ename from employee";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println(resultSet.getString("ename"));
}
//4.释放资源
C3P0Utils.close(connection,statement,resultSet);
}
}
Druid连接池
- Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接SQL的执行情况。
- 导入配置文件(.properties)
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db5?characterEncoding=UTF-8
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
- 编写工具类
package com.lagou.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DruidUtils {
//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();
}
}
//3.测试工具类
//获取连接的方法
public static Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
//关闭连接释放资源
public static void close(Connection connection, Statement statement) {
if (connection != null && statement != null) {
try {
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//重载方法关闭ResultSet查询连接
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
if (connection != null && statement != null && resultSet != null) {
try {
resultSet.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- 测试
package com.lagou.testpool;
import com.lagou.utils.DBCPUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDruid {
//需求: 查询薪资在3000 - 5000元之间的员工姓名
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = DBCPUtils.getConnection();
statement = connection.createStatement();
String sql = "select ename from employee where salary between 3000 and 5000";
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString("ename"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBCPUtils.close(connection, statement, resultSet);
}
}
}
DBUtils工具类
- apache组织提供的工具类库
- 不会影响程序的性能
- 需要导入common-dbutis-1.6jar包
核心类
- QueryRunner 中提供对sql语句操作的API.
- ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
- DbUtils类,他就是一个工具类,定义了关闭资源与事务处理相关方法
表和类之间的关系
- 可以将一张表看成一个类
- 表中的列可以看做类的属性,将表中的列和类中的属性对应
JavaBean
- 属性与表中的列对应,包括名称和类型
- 实现Serializable接口
- 提供共有的set、get方法
package com.lagou.entity;
import java.io.Serializable;
import java.util.Date;
/**
* JavaBean类
*/
public class Employee implements Serializable {
private static final long serialVersionUID = 3998403112058917645L;
private int id;
private String ename;
private int age;
private String sex;
private double salary;
private Date empdate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Date getEmpdate() {
return empdate;
}
public void setEmpdate(Date empdate) {
this.empdate = empdate;
}
}
QueryRunner
- QueryRunner 核心类的创建方式
public static void main(String[] args) {
//方式1:手动模式 使用无参方式构造
QueryRunner queryRunner = new QueryRunner();
//方式2:自动模式 提供数据库连接池对象 DBUtils会自动维护连接
QueryRunner queryRunner2 = new QueryRunner(DruidUtils.getDataSource());
}
-
手动模式
- 插入操作
@Test public void testInsert() throws SQLException { //1.创建QueryRunner对象 手动模式 QueryRunner queryRunner = new QueryRunner(); //2.编写占位符方式sql String sql = "insert into employee values(?,?,?,?,?,?)"; //3.设置占位符的参数 Object[] param = {null, "张百万", 20, "女", 10000, "1990-12-26"}; //4.执行update方法 Connection connection = DruidUtils.getConnection(); queryRunner.update(connection, sql, param); DbUtils.closeQuietly(connection); }
-
自动模式
- 修改操作
@Test public void testUpdate() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "update employee set salary = ? where ename = ?"; //3.设置占位符的参数 Object[] param = {15000,"张百万"}; //4.自动模式不需要传入Connection对象 queryRunner.update(sql,param); //5.不需要关闭连接 }
- 删除操作
@Test public void testDelete() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "delete from employee where ename = ?"; //3.只有一个参数不需要创建数组 //4.自动模式不需要传入Connection对象 queryRunner.update(sql,"张百万"); //5.不需要关闭连接 }
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 表操作 |
-
常用实现类
- ArrayHandler(将查询到的第一条数据添加到一个Object数组)
/** * 使用ArrayHandler * 将查询到的第一条数据添加到一个Object数组 */ @Test public void testQuery() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "select * from employee where ename = ?"; ArrayHandler arrayHandler = new ArrayHandler(); //3.执行查询操作 Object[] query = queryRunner.query(sql, arrayHandler, "李白"); System.out.println(Arrays.toString(query)); }
- ArrayListHandler(可以将每条数据封装到Object数组集合中)
/** * 使用ArrayListHandler * 可以将每条数据封装到数组中 */ @Test public void testQueryAll() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "select * from employee"; ArrayListHandler arrayListHandler = new ArrayListHandler(); //3.执行查询操作 List<Object[]> query = queryRunner.query(sql, arrayListHandler); for (Object[] objects : query) { System.out.println(Arrays.toString(objects)); } }
- BeanHandler(可以将结果集的第一条数据封装到JavaBean中)
/** * 使用BeanHandler * 可以将结果集的第一条数据封装到JavaBean中 */ @Test public void testQueryBean() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "select * from employee"; //3.执行查询操作 Employee employee = queryRunner.query(sql, new BeanHandler<>(Employee.class)); System.out.println(employee); }
- BeanListHandler(可以将结果集的每一条数据封装到JavaBean中再将JavaBean放入集合中)
/** * 使用BeanListHandler * 可以将结果集的每一条数据封装到JavaBean中再将JavaBean放入集合中 */ @Test public void testQueryBeanList() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "select * from employee"; //3.执行查询操作 List<Employee> employee = queryRunner.query(sql, new BeanListHandler<>(Employee.class)); for (Employee employee1 : employee) { System.out.println(employee1); } }
- MapHandler(可以将结果集的第一条数据封装到Map中)
/** * 使用MapHandler * 可以将结果集的第一条数据封装到Map中 */ @Test public void testQueryMap() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "select * from employee "; //3.执行查询操作 Map<String, Object> map = queryRunner.query(sql, new MapHandler()); System.out.println(map); }
- MapListHandler(可以将结果集的每一条数据封装到Map中,再将多个Map放入集合中)
/** * 使用MapListHandler * 可以将结果集的每一条数据封装到Map中,再将多个Map放入集合中 */ @Test public void testQueryMapList() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "select * from employee "; //3.执行查询操作 List<Map<String, Object>> mapList = queryRunner.query(sql, new MapListHandler()); for (Map<String, Object> map : mapList) { System.out.println(map); } }
- ScalaHandler(用于封装单个数据)
/** * 使用ScalaHandler * 用于封装单个数据 */ @Test public void testQueryScala() throws SQLException { //1.创建QueryRunner对象 自动模式 QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //2.编写占位符方式sql String sql = "select sum(salary) from employee "; //3.执行查询操作 Object query = queryRunner.query(sql, new ScalarHandler<>()); System.out.println(query); }
批处理操作
- Statement和PrepareStatement都支持批处理操作
方法名 | 功能介绍 |
---|---|
void addBatch() | 将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。 通过调用方法 executeBatch 可以批量执行此列表中的命令。 |
int[] executeBatch() | 每次提交一批命令到数据库中执行,如果所有的命令都成功执行了, 那么返回一个数组,这个数组是说明每条命令所影响的行数 |
- mysql 批处理是默认关闭的,所以需要加一个参数才打开mysql 数据库批处理,在url中添加
rewriteBatchedStatements=true
例如: url=jdbc:mysql://127.0.0.1:3306/db5?characterEncoding=UTF-8&rewriteBatchedStatements=true
//使用批处理 向表中添加10000条数据
public static void main(String[] args) throws SQLException {
//1.获取连接
Connection connection = DruidUtils.getConnection();
//2.获取预处理对象
PreparedStatement ps = connection.prepareStatement("insert into test_batch values (null, ?)");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
ps.setString(1, "小强" + i);
//3.将sql添加到批处理列表
ps.addBatch();
}
//4.循环结束统一执行批处理操作
ps.executeBatch();
//5.关闭连接
DruidUtils.close(connection, ps);
System.out.println(System.currentTimeMillis() - startTime + "ms"); // 141ms
}
Mysql元数据
-- 元数据相关的命令介绍
-- 1.查看服务器当前状态
show status;
-- 2.查看MySQl的版本信息
select version();
-- 3.查询表中的详细信息
show columns from table_name;
-- 4.显示数据表的详细索引信息
show index from table_name;
-- 5.列出所有数据库
show databases;
-- 6.显示当前数据库的所有表
show tables;
-- 7.获取当前的数据库名
select database();
JDBC获取元数据
- JDBC中描述元数据的类
- DatabaseMetaData 描述数据库的元数据对象
- ResultSetMetaData 描述结果集的元数据对象
- DatabaseMetaData
@Test
public void testMetaData() throws SQLException {
Connection connection = DruidUtils.getConnection();
DatabaseMetaData metaData = connection.getMetaData();
String url = metaData.getURL();
String userName = metaData.getUserName();
//获取数据库产品名称
String databaseProductName = metaData.getDatabaseProductName();
//获取数据库产品版本
String databaseProductVersion = metaData.getDatabaseProductVersion();
//获取驱动名称
String driverName = metaData.getDriverName();
//是否只读
boolean readOnly = metaData.isReadOnly();
System.out.println(url);
System.out.println(userName);
System.out.println(databaseProductName);
System.out.println(databaseProductVersion);
System.out.println(driverName);
System.out.println(readOnly);
}
- ResultSetMetaData
@Test
public void testResultData() throws SQLException {
Connection connection = DruidUtils.getConnection();
PreparedStatement prepareStatement = connection.prepareStatement("select * from employee");
ResultSetMetaData metaData = prepareStatement.getMetaData();
//获取列的数量
int columnCount = metaData.getColumnCount();
//获取列名
String columnName = metaData.getColumnName(1);
//获取列类型名称
String columnTypeName = metaData.getColumnTypeName(1);
System.out.println(columnCount);
System.out.println(columnName);
System.out.println(columnTypeName);
}
XML
- 可扩展标记语言,由W3C(万维网)发布
- 可扩展的,标签都是自定义的,语法十分严格
- XML能做什么
- 可以存储数据
- 作为配置文件使用
- 语法定义
<?xml version="1.0" encoding="UTF-8" ?>
<users>
<user id="123">
<name>张百万</name>
<age>15</age>
</user>
<user id="456">
<name>小斌</name>
<age>18</age>
<hobby>
</hobby>
</user>
<!--空元素没有结束标签-->
<close/>
</users>
<!-- xml的注释
1.xml中必须有文档声明
version:版本信息
encoding:编码
2.xml中的文档声明必须写在第一行
3.xml中的元素标签的命名规则
标签定义不能使用空格或者冒号
标签的名称区分大小写
4.xml中有且只有一个根元素
5.元素体可以是文本也可以是另外一个标签
6.属性是元素的一部分,只能出现在元素的开始标签中
7.属性值必须使用单引号或者双引号包裹
-->
XML约束
- 常见的xml约束
- DTD约束
- Schema约束
- 会引入、会使用即可,无需会编写约束
DTD约束
- 常见的DTD约束有Strust2、hibernate等
- 编写DTD约束
<!ELEMENT students (student+) >
<!ELEMENT student (name,age,sex)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ATTLIST student number ID #REQUIRED>
<!--
ELEMENT: 用来定义元素
students (student+) : 代表根元素 必须是 <students>
student+ : 根标签中至少有一个 student子元素, + 代表至少一个
student (name,age,sex): student 标签中包含的子元素,按顺序出现
#PCDATA: 是普通文本内容
ATTLIST: 用来定义属性
student number ID #REQUIRED
student子元素中 有一个ID属性叫做 number,是必须填写的
ID: 唯一 值只能是字母或者下划线开头
-->
- 引入DTD约束,两种方式
- 内部dtd:将约束规则定义在xml内
- 外部dtd:将约束的规则定义在外部的dtd文件中
- 本地:<!DOCTYPE students SYSTEM “student.dtd”>
- 网络:
- 引入DTD约束
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE students SYSTEM "students.dtd">
<students>
<student number="S1">
<name>长海</name>
<age>20</age>
<sex>男</sex>
</student>
<student number="S2">
<name>大玲子</name>
<age>18</age>
<sex>女</sex>
</student>
</students>
Schema约束
- 什么是Schema
- Schema是新的XML文档约束, 比DTD强大很多,是DTD 替代者;
- Schema本身也是XML文档,但Schema文档的扩展名为xsd,而不是xml。
- Schema 功能更强大,内置多种简单和复杂的数据类型
- Schema 支持命名空间 (一个XML中可以引入多个约束文档)
- Schema约束示例
<?xml version="1.0"?>
<xsd:schema xmlns="http://www.lagou.com/xml" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.lagou.com/xml" elementFormDefault="qualified">
<xsd:element name="students" type="studentsType"/>
<xsd:complexType name="studentsType">
<xsd:sequence>
<xsd:element name="student" type="studentType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="studentType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType"/>
<xsd:element name="sex" type="sexType"/>
</xsd:sequence>
<xsd:attribute name="number" type="numberType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="sexType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="male"/>
<xsd:enumeration value="female"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="200"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<!-- Xml Schema的根元素:-->
<!-- 3.2.3 XML引入Schema约束-->
<!-- xml中引入schema约束的步骤:-->
<!-- 1) 查看schema文档,找到根元素,在xml中写出来-->
<!-- 2) 根元素来自哪个命名空间。使用xmlns指令来声明-->
<!-- 3) 引入 w3c的标准命名空间, 复制即可-->
<!-- 4) 引入的命名空间跟哪个xsd文件对应?-->
<!-- 使用schemaLocation来指定:两个取值:第一个为命名空间 第二个为xsd文件的路径-->
<xsd:restriction base="xsd:string">
<xsd:pattern value="hehe_\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
- 引入Schema约束
<?xml version="1.0" encoding="UTF-8" ?>
<students xmlns="http://www.lagou.com/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.lagou.com/xml student.xsd">
<student number="hehe_1234">
<name>大哥</name>
<age>20</age>
<sex>female</sex>
</student>
</students>
XML解析
-
两种方式
- DOM方式:将整个XML读取到内存,生成一个document对象
- 优点:元素与元素之间有结构关系,可以进行CRUD操作
- 缺点:占用的内存太多,容易内存溢出
- SAX方式:一边扫描一边解析,逐行读取,读完即释放资源
- 优点:速度快,占用内存少
- 缺点:只能进行解析操作,无法进行CRUD操作
- DOM方式:将整个XML读取到内存,生成一个document对象
-
常见解析器
- JAXP:sun公司提供的解析器,支持DOM和SAX两种思想
- DOM4J:一款非常优秀的解析器 , Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
- Jsoup:jsoup 是一款Java 的HTML解析器 ,也可以解析XML
- PULL:Android内置的XML解析方式,类似SAX。
dom4j使用
- 引入dom4j jar包 --> dom4j-1.6.1.jar
常用API
-
SaxReader对象
- read(…) 加载执行xml文档
-
Document对象
- getRootElement() 获得根元素
-
Element对象
- elements(…) 获得指定名称的所有子元素。可以不指定名称
- element(…) 获得指定名称的第一个子元素。可以不指定名称
- getName() 获得当前元素的元素名
- attributeValue(…) 获得指定属性名的属性值
- elementText(…) 获得指定名称子元素的文本值
- getText() 获得当前元素的文本内容
-
使用dom4j获取xml文件中的标签信息
<?xml version="1.0" encoding="UTF-8" ?>
<users xmlns="http://www.lagou.com/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.lagou.com/xml user.xsd"
>
<user id="001">
<name>大哥</name>
<age>20</age>
<hobby>抽烟</hobby>
</user>
<user id="002">
<name>二弟</name>
<age>18</age>
<hobby>喝酒</hobby>
</user>
<user id="003">
<name>三弟</name>
<age>16</age>
<hobby>烫头</hobby>
</user>
</users>
//获取XML文件中的所有元素(标签)
@Test
public void test1() throws DocumentException {
//1.获取XML解析对象
SAXReader saxReader = new SAXReader();
//2.解析XML,获取文档document对象
Document document = saxReader.read("D:\\Code\\LJ_study\\stage2\\xml_task03\\src\\com\\lagou\\xml03\\user.xml");
//3.获取根元素
Element rootElement = document.getRootElement();
System.out.println(rootElement);
//4.获取根元素下的标签
List<Element> elements = rootElement.elements();
for (Element element : elements) {
System.out.println(element.getName());
List<Element> elements1 = element.elements();
for (Element element1 : elements1) {
System.out.println(element1.getName());
}
}
}
- 使用dom4j获取XML文件中标签的文本信息和属性信息
//获取XML中标签的文本信息和属性信息
@Test
public void test2() throws DocumentException {
//1.获取XML解析对象
SAXReader saxReader = new SAXReader();
//2.解析XML,获取文档document对象
Document document = saxReader.read("D:\\Code\\LJ_study\\stage2\\xml_task03\\src\\com\\lagou\\xml03\\user.xml");
//3.获取根元素
Element rootElement = document.getRootElement();
//4.获取根元素下的标签
List<Element> elements = rootElement.elements();
//5.获取集合中的第一个子节点
Element user = elements.get(0);
//6.获取节点中的文本信息1
String id = user.attributeValue("id");
String name = user.elementText("name");
String age = user.elementText("age");
//6.获取节点中的文本信息2
String hobby = user.element("hobby").getText();
System.out.println(id);
System.out.println(name);
System.out.println(age);
System.out.println(hobby);
}
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: 节点对象
- 使用selectSingleNode获取标签名和属性值
@Test
public void test1() throws DocumentException {
//1.获取XML解析对象
SAXReader saxReader = new SAXReader();
//2.解析XML,获取文档document对象
Document document = saxReader.read("D:\\Code\\LJ_study\\stage2\\xml_task03\\src\\com\\lagou\\xml04\\book.xml");
//3.通过selectSingleNode方法获取name节点
Node node = document.selectSingleNode("/bookstore/book/name");
System.out.println(node.getName());
System.out.println(node.getText());
//4.获取第二本书
Node node2 = document.selectSingleNode("/bookstore/book[2]/name");
System.out.println(node2.getName());
System.out.println(node2.getText());
}
- 使用selectSingleNode获取属性值,或者属性值对应的节点
@Test
public void test2() throws DocumentException {
//1.创建解析器对象
SAXReader sr = new SAXReader();
//2.获取文档对象
Document document =
sr.read("D:\\Code\\LJ_study\\stage2\\xml_task03\\src\\com\\lagou\\xml04\\book.xml");
//3.获取第一个book节点的 id属性的值
Node node1 = document.selectSingleNode("/bookstore/book/attribute::id");
System.out.println("第一个book的id值为: " + node1.getText());
//4.获取最后一个book节点的 id属性的值
Node node2 =
document.selectSingleNode("/bookstore/book[last()]/attribute::id");
System.out.println("最后一个book节点的id值为: " + node2.getText());
//5.获取id属性值为 book2的 书名
Node node3 = document.selectSingleNode("/bookstore/book[@id='book2']");
String name = node3.selectSingleNode("name").getText();
System.out.println("id为book2的书名是: " + name);
}
- 使用selectNodes()方法 获取对应名称的所有节点
@Test
public void test3() throws DocumentException {
//1.创建解析器对象
SAXReader sr = new SAXReader();
//2.获取文档对象
Document document =
sr.read("D:\\Code\\LJ_study\\stage2\\xml_task03\\src\\com\\lagou\\xml04\\book.xml");
//3.获取所有节点,打印节点名
List<Node> list = document.selectNodes("//*");
for (Node node : list) {
System.out.println("节点名: " + node.getName());
}
//4.获取所有的书名
List<Node> names = document.selectNodes("//name");
for (Node name : names) {
System.out.println(name.getText());
}
//5.获取指定 id值为book1的节点的所有 内容
List<Node> book1 =
document.selectNodes("/bookstore/book[@id='book1']//*");
for (Node node : book1) {
System.out.println(node.getName() + " = " + node.getText());
}
}