JAVA学习第二阶段模块二

模块二 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操作
  • 常见解析器

    • 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());
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值