2.2 JDBC&XML

一:JDBC


1.JDBC 概述
  • JDBC(Java Data Base Connectivity) 是 Java 访问数据库的标准规范.是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范.

  • JDBC 原理: JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。

  • JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口),而数据库厂商需要实现这套接口,提供数据库
    驱动jar包, 我们可以使用这套接口编程,真正执行的代码是对应驱动包中的实现类。
    在这里插入图片描述

2.JDBC 开发
  • 1.加载驱动:Class.forName(数据库驱动实现类)
  • 2.获取连接:使用 DriverManager类的静态方法getConnection方法,获取数据库的连接
  • 3.获取Statement对象
  • 4.处理结果集:只有在进行查询操作的时候, 才会处理结果集ResultSet
  • 5.释放资源:先开的后关,后开的先关,ResultSet ==> Statement ==> Connection
    在这里插入图片描述
3.SQL注入问题
  • SQL注入: 我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了原有SQL 真正的意义,以上问题称为 SQL注入。
# SQL注入演示 
-- 填写一个错误的密码 
SELECT * FROM jdbc_user WHERE username = 'tom' AND PASSWORD = '123' OR '1' = '1';

相当于 select * from user where true=true; 查询了所有记录
如果这是一个登陆操作,那么用户就登陆成功了.显然这不是我们想要看到的结果
  • 要解决 SQL 注入,就不能让用户输入的密码和我们的SQL语句进行简单的字符串拼接。
4.预处理对象
  • PreparedStatement 是Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的SQL语句对象.

  • 预编译: 是指SQL语句被预编译,并存储在PreparedStatement对象中。然后可以使用此对象多次高效地执行该语句。

  • PreparedStatement特点: 因为有预先编译的功能,提高SQL的执行效率。可以有效的防止 SQL 注入的问题,安全性更高
    在这里插入图片描述

  • Statement 与 PreparedStatement的区别

  • 1.Statement用于执行静态SQL语句,在执行时,必须指定一个事先准备好的SQL语句。
  • 2.PrepareStatement是预编译的SQL语句对象,语句中可以包含动态参数“?”,在执行时可以为“?”动态设置参数值。
  • 3.PrepareStatement可以减少编译次数提高数据库性能。
5.JDBC 控制事务
  • 使用Connection中的方法实现事务管理
  • void setAutoCommit(boolean autoCommit):参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务
  • void commit():提交事务
  • void rollback():回滚事务
  • 开发步骤
  • 1.获取连接
  • 2.开启事务
  • 3.获取到 PreparedStatement , 执行两次更新操作
  • 4.正常情况下提交事务
  • 5.出现异常回滚事务
  • 6.最后关闭资源
public class TestJDBCTransaction {

    //使用JDBC操作事务
    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement ps = null;

        try {
            //1.获取连接
            con = JDBCUtils.getConnection();

            //2.开启事务
            con.setAutoCommit(false);  //手动提交事务

            //3.获取预处理对象 执行SQL (两次修改操作)
            //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();
            //5.出现异常就回滚事务
            try {
                con.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }

        } finally {
            //6.释放资源
            JDBCUtils.close(con,ps);
        }

    }

}

二:数据库连接池和DBUtils


  • 连接池: 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池.

  • 连接池的好处: 用池来管理Connection,这样可以重复使用Connection。 当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。

  • 普通 JDBC方式:
    在这里插入图片描述

  • 连接池方式:

  • Java为数据库连接池提供了公共的接口: javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!常见的连接池有 DBCP连接池, C3P0连接池, Druid连接池,

  • DBCP 是一个开源的连接池,是Apache成员之一,在企业开发中也比较常见,tomcat内置的连接池。

  • 常见配置项:
  • driverClassName: 数据库驱动名称
  • url: 数据库地址
  • username: 用户名
  • password: 密码
  • maxActive: 最大连接数量
  • maxIdle: 最大空闲连接
  • minIdle: 最小空闲连接
  • initialSize: 初始化连接
		/**
		 * DBCPUtils 工具类
		 */
		public class DBCPUtils {
		
		    //1.定义常量 保存数据库连接的相关信息
		    public static final String DRIVERNAME = "com.mysql.jdbc.Driver";
		    public static final String URL = "jdbc:mysql://localhost:3306/lagou_jy?characterEncoding=UTF-8";
		    public static final String USERNAME = "root";
		    public static final String PASSWORD = "root";
		
		    //2.创建连接池对象 (有DBCP提供的实现类)
		    public static BasicDataSource dataSource = new BasicDataSource();
		
		    //3.使用静态代码块进行配置
		    static{
		        dataSource.setDriverClassName(DRIVERNAME);
		        dataSource.setUrl(URL);
		        dataSource.setUsername(USERNAME);
		        dataSource.setPassword(PASSWORD);
		        dataSource.setMaxActive(20);
		    }
		
		    //4.获取连接的方法
		    public static Connection getConnection() throws SQLException {
		
		        //从连接池中获取连接
		        Connection connection = dataSource.getConnection();
		        return connection;
		    }
		
		    //5.释放资源方法
		    public static void close(Connection con, Statement statement){
		        if(con != null && statement != null){
		            try {
		                statement.close();
		                con.close();
		            } catch (SQLException e) {
		                e.printStackTrace();
		            }
		        }
		
		    }
		
		    //5.释放资源方法
		    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();
		            }
		        }
		
		    }
		
		}
  • C3P0 是一个开源的JDBC连接池,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。

      配置文件c3p0-config.xml,文件名不可更改,直接放到src下,也可以放到到资源文件夹中
    
      <c3p0-config>
      
      	<!--默认配置--> 
      	<default-config> 
      		<property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/lagou_jy?characterEncoding=UTF-8</property> 
      		<property name="user">root</property> 
      		<property name="password">root</property> 
      		
      		<!-- 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/lagou_jy</property>
      	<property name="user">root</property> 
      	<property name="password">root</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提供的核心工具类, ComboPooledDataSource , 如果想使用连接池,就必须创建该类的对象
       *      new ComboPooledDataSource(); 使用 默认配置
       *      new ComboPooledDataSource("mysql"); 使用命名配置
       */
      public class C3P0Utils {
      
          //1.创建连接池对象 C3P0对DataSource接口的实现类
          //使用的配置是 配置文件中的默认配置
          //public static ComboPooledDataSource dataSource = new ComboPooledDataSource();
      
          //使用指定的配置
          public static ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
      
          //获取连接的方法
          public static Connection getConnection() throws SQLException {
              return dataSource.getConnection();
          }
      
          //释放资源
          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();
                  }
              }
          }
      }
    
  • Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。

     	配置文件:druid.properties
     	
     	driverClassName=com.mysql.jdbc.Driver
     	url=jdbc:mysql://localhost:3306/lagou_jy1?characterEncoding=UTF-8
     	username=root
     	password=root
     	initialSize=5
     	maxActive=10
     	maxWait=3000
    
    
     	Druid工具类:
    
     	/**
     	 * 获取数据库连接池对象
     	 *      通过工厂来来获取 DruidDataSourceFactory类的createDataSource方法
     	 *      createDataSource(Properties p) 方法参数可以是一个属性集对象
     	 */
     	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();
     	        }
     	    }
    
     	    //获取连接的方法
     	    public static Connection getConnection(){
     	        try {
     	
     	            return dataSource.getConnection();
     	
     	        } catch (SQLException e) {
     	            e.printStackTrace();
     	            return null;
     	        }
     	    }
     	
     	    //获取Druid连接池对象的方法
     	    public static DataSource getDataSource(){
     	        return dataSource;
     	    }
     	
     	
     	    //释放资源
     	    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();
     	            }
     	        }
     	
     	    }
     	
     	}
    
  • DBUtils工具类: 使用JDBC我们发现冗余的代码太多了,为了简化开发 我们选择使用 DbUtils,Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。(DBUtils就是JDBC的简化开发工具包,需要项目导入commons-dbutils-1.6.jar)

  • 步骤:
    1.创建QueryRunner(手动或自动)
    2.占位符方式 编写SQL
    3.设置占位符参数
    4.执行
  • Dbutils核心功能
  • 1.QueryRunner 中提供对sql语句操作的API.
  • 2.ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
  • 3.DbUtils类,他就是一个工具类,定义了关闭资源与事务处理相关方法
  • QueryRunner核心类

      构造方法:
      	QueryRunner() 
      	QueryRunner(DataSource ds) ,提供数据源(连接池),DBUtils底层自动维护连接connection
      
      常用方法:
      	update(Connection conn, String sql, Object... params) ,用来完成表数据的增加、删除、更新操作
    
      	query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) ,用来完成表数据的查询操作
    
      QueryRunner的创建模式:
      	//手动方式 创建QueryRunner对象 
      	QueryRunner qr = new QueryRunner();
    
      	//自动创建 传入数据库连接池对象 
      	QueryRunner qr2 = new QueryRunner(DruidUtils.getDataSource());
    
      	//获取连接池对象(自动模式需要传入连接池对象)
      	public static DataSource getDataSource(){ return dataSource; }
    
       QueryRunner实现增、删、改操作核心方法:
      	update(Connection conn, String sql, Object... params)
    
      	Connection conn:数据库连接对象, 自动模式创建QueryRun 可以不传 ,手动模式必须传递
      	String sql:占位符形式的SQL ,使用 ? 号占位符
      	Object... param:Object类型的 可变参,用来设置占位符上的参数
    
  • QueryRunner实现查询操作

  • ResultSetHandler接口 可以对查询出来的ResultSet结果集进行处理,达到一些业务上的需求。
  • 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 表操作。
  • QueryRunner的查询方法: query方法的返回值都是泛型,具体的返回值类型,会根据结果集的处理方式,发生变化
query(String sql, handler ,Object[] param) 自动模式创建QueryRunner, 执行查询

query(Connection con,String sql,handler,Object[] param) 手动模式创建QueryRunner, 执行查询
  • JavaBean组件: JavaBean就是一个类, 开发中通常用于封装数据,创建实体类和数据库的表对应。
  • 特点:
  1. 需要实现 序列化接口, Serializable (暂时可以省略)
  2. 提供私有字段: private 类型 变量名;
  3. 提供 getter 和 setter
  4. 提供 空参构造
数据库批处理
  • 批处理(batch) 操作数据库:批处理指的是一次操作中执行多条SQL语句,批处理相比于一次一次执行效率会提高很多。当向数据库中添加大量的数据时,需要用到批处理。
  • 举例: 送货员的工作,未使用批处理的时候,送货员每次只能运送 一件货物给商家;使用批处理,则是送货员将所有要运送的货物, 都用车带到发放处派给客户。
  • 实现批处理: Statement和PreparedStatement都支持批处理操作,
要用到的方法:
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
MySql元数据
  • 元数据: 除了表之外的数据都是元数据,可以分为三类
  • 查询结果信息: UPDATE 或 DELETE语句 受影响的记录数。
  • 数据库和数据表的信息: 包含了数据库及数据表的结构信息。
  • MySQL服务器信息: 包含了数据库服务器的当前状态,版本号等。
元数据相关的命令介绍 
-- 1.查看服务器当前状态 
show status; 

-- 2.mysql服务器的版本信息
select version(); 

-- 3.查询表中的详细信息,和desc table_name一样
show columns from table_name; 

-- 4.显示数据表的详细索引信息,包括PRIMARY KEY(主键) 
show index from table_name;

-- 5.列出所有数据库 
show databases;

-- 6.显示当前数据库的所有表 
show tables;

-- 7.获取当前的数据库名
select database();
  • 使用JDBC 获取元数据: 通过JDBC 也可以获取到元数据,比如数据库的相关信息,或者当我们使用程序查询一个不熟悉的表时, 我们可以通过获取元素据信息,了解表中有多少个字段,字段的名称 和 字段的类型
JDBC中描述元数据的类

   DatabaseMetaData: 描述数据库的元数据对象
   ResultSetMetaData: 描述结果集的元数据对象
获取元数据对象的方法 : getMetaData ()
  1.connection 连接对象, 调用 getMetaData () 方法,获取的是DatabaseMetaData 数据库元数据对象
  2.PrepareStatement 预处理对象调用 getMetaData () , 获取的是ResultSetMetaData , 结果集元数据对象


  DatabaseMetaData的常用方法:
  getURL() : 获取数据库的URL
  getUserName(): 获取当前数据库的用户名
  getDatabaseProductName(): 获取数据库的产品名称
  getDatabaseProductVersion(): 获取数据的版本号
  getDriverName(): 返回驱动程序的名称
  isReadOnly(): 判断数据库是否只允许只读 true 代表只读
ResultSetMetaData的常用方法:
  getColumnCount() : 当前结果集共有多少列
  getColumnName(int i) : 获取指定列号的列名, 参数是整数 从1开始
  getColumnTypeName(int i): 获取指定列号列的类型, 参数是整数 从1开始

三:XML


  • 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版本 !
  • 特点: 可扩展的, 标签都是自定义的,语法十分严格
  • XML的作用:
  • 存储数据: 通常我们在数据库中存储数据。不过,如果希望数据的可移植性更强,我们可以把数据存储 XML 文件中
  • 配置文件: 作为各种技术框架的配置文件使用 (最多)
  • 在网络中传输: 客户端可以使用XML格式向服务器端发送数据,服务器接收到xml格式数据,进行解析
XML的语法
  • XML文档声明格式: 文档声明必须为结束,文档声明必写在第一行;
语法格式: <?xml version="1.0" encoding="UTF-8"?>
属性说明:
  versioin:指定XML文档版本。必须属性,因为我们不会选择1.1,只会选择1.0;
  encoding:指定当前文档的编码。可选属性,默认值是utf-8;
  • 元素: Element 元素,是XML文档中最重要的组成部分
元素的命名规则:
	1.不能使用空格,不能使用冒号
	2.xml 标签名称区分大小写
	3.XML 必须有且只有一个根元素

语法格式: <users><users>

XML 必须有且只有一个根元素,它是所有其他元素的父元素,比如以下实例中 users 就是根元素:
<?xml version="1.0" encoding="utf-8" ?
<users</users>

普通元素的结构开始标签、元素体、结束标签组成
<hello大家好 </hello>

元素体:元素体可以是元素,也可以是文本
<hello
	<a>你好</a
</hello>

空元素:空元素只有开始标签,而没有结束标签,但元素必须自己闭合
<close/>
  • 属性
  1. 属性是元素的一部分,它必须出现在元素的开始标签中
  2. 属性的定义格式:属性名=属性值,其中属性值必须使用单引或双引
  3. 一个元素可以有0~N个属性,但一个元素中不能出现同名属性
  4. 属性名不能使用空格、冒号等特殊字符,且必须以字母开头
  <bean id="" class=""</bean>
  • 注释: XML的注释,以“ ”结束。注释内容会被XML解析器忽略!

  • 使用XML 描述数据表中的数据

      <?xml version="1.0" encoding="UTF-8" ?>
          <employees>
      	   <employee eid="2">
      		     <ename>林黛玉</ename>
      		     <age>20</age
      		     <sex>女</sex
      		     <salary>5000</salary>
      		     <empdate>2019-03-14</empdate>
      	    </employee>
      	    
      	    <employee eid="3">
      		     <ename>杜甫</ename>
      		     <age>40</age>
      		     <sex>男</sex>
      		     <salary>15000</salary>
      		     <empdate>2010-01-01</empdate>
          	</employee>
    
     		</employees>
    
  • XML约束: 在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束。

  • 常见的xml约束:DTD,Schema
  • 作为程序员只要掌握两点:会阅读,会引入,不用自己编写
    在这里插入图片描述
  • DTD约束(Document Type Definition):文档类型定义,用来约束XML文档。 规定XML文档中元素的名称,子元素的名称及顺序,元素的属性等。,开发中,我们不会自己编写DTD约束文档,通常情况我们都是通过框架提供的DTD约束文档,编写对应的XML文档。常见框架使用DTD约束有:
    Struts2、hibernate等。

      创建约束文件 student.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:将约束规则定义在xml文档中
      	外部dtd:将约束的规则定义在外部的dtd文件中
      			本地:
      			网络:
      		
    
      student.xml
    
      <?xml version="1.0" encoding="UTF-8" ?> 
      <!DOCTYPE students SYSTEM "student.dtd"> 
      
      <students>
      	<student number="s1"> 
      		<name>小斌</name> 
      		<age>22</age> 
      		<sex>男</sex>
      	</student> 
    
      	<student number="s2"> 
      		<name>广坤</name> 
      		<age>55</age> 
      		<sex>男</sex> 
      	</student> 
      </students>
    
  • Schema约束:

  1. Schema是新的XML文档约束, 比DTD强大很多,是DTD 替代者;
  2. Schema本身也是XML文档,但Schema文档的扩展名为xsd,而不是xml。
  3. Schema 功能更强大,内置多种简单和复杂的数据类型
  4. Schema 支持命名空间 (一个XML中可以引入多个约束文档)
  • Schema约束示例

      student.xsd
      
      <?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">
              <xsd:restriction base="xsd:string">
                  <xsd:pattern value="hehe_\d{4}"/>
              </xsd:restriction>
          </xsd:simpleType>
      
      </xsd:schema>
    

在这里插入图片描述

  • XML引入Schema约束

      student.xml
    
      xml中引入schema约束的步骤:
      
      <?xml version="1.0" encoding="UTF-8" ?> 
      	<-- 1.查看schema文档,找到根元素<students> </students>,在xml中写出来 -->
      	<-- 2.根元素来自哪个命名空间。使用xmlns指令来声明 -->
      	<students xmlns="http://www.lagou.com/xml" 
    
      			  <-- 3.引入 w3c的标准命名空间, 复制即可 -->
      		 	  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    
       			  <-- 4.引入的命名空间跟哪个xsd文件对应:使用schemaLocation来指定
      				两个取值:
      					第一个为命名空间 
      					第二个为xsd文件的路径 
      				命名空间:指的是一个环境,所用的标签来自于哪个环境定义的。 -->
      			  xsi:schemaLocation="http://www.lagou.com/xml student.xsd" >
      
      		<student number="hehe_1234"> 
      			<name>张百万</name> 
      			<age>25</age> 
      			<sex>female</sex> 
      		</student> 
      		
      		<student number="hehe_0000"> 
      			<name>小斌</name> 
      			<age>20</age> 
      			<sex>male</sex> 
      		</student> 
      
      	</students>
    
XML 解析
  • 概述: 当将数据存储在XML后,我们就希望通过程序获得XML的内容。如果我们使用Java基础所学习的IO知识是可以完成的,不过你需要非常繁琐的操作才可以完成,且开发中会遇到不同问题(只读、读写)。人们为不同问题提供不同的解析方式,并提交对应的解析器,方便开发人员操作XML。

  • XML解析方式: 开发中比较常见的解析方式有两种

  • DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象。

  • 优点:元素与元素之间保留结构关系,故可以进行增删改查操作。

  • 缺点:XML文档过大,可能出现内存溢出显现。

  • **SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。**并以事件驱动的方式进行具体解析,每执行一行,都将触发对应的事件。(了解)

  • 优点:占用内存少 处理速度快,可以处理大文件

  • 缺点:只能读,逐行后将释放资源。
    在这里插入图片描述

  • XML常见的解析器: 解析器,就是根据不同的解析方式提供的具体实现。有的解析器操作过于繁琐,为了方便开发人员,有提供易于操作的解析开发包
  • JAXP: sun公司提供的解析器,支持DOM和SAX两种思想
  • DOM4J: 一款非常优秀的解析器 , Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
  • Jsoup: jsoup 是一款Java 的HTML解析器 ,也可以解析XML
  • PULL: Android内置的XML解析方式,类似SAX。
dom4j 的使用
  • 使用核心类SaxReader加载xml文档获得Document,通过Document 对象获得文档的根元素,然后就可以操作了。
常用API如下:
SaxReader对象:
  read(…) 加载执行xml文档
  
Document对象: 
  getRootElement() 获得根元素
  
Element对象:
  elements(…) 获得指定名称的所有子元素。可以不指定名称
  element(…) 获得指定名称的第一个子元素。可以不指定名称
  getName() 获得当前元素的元素名
  attributeValue(…) 获得指定属性名的属性值
  elementText(…) 获得指定名称子元素的文本值
  getText() 获得当前元素的文本内容
  • 1.导入JAR包
  • 2.准备xml文件
	编写user.xsd schema约束

	<?xml version="1.0" encoding="UTF-8" ?>
	<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="users" type="usersType"/>
	    <xsd:complexType name="usersType">
	        <xsd:sequence>
	            <xsd:element name="user" type="userType" minOccurs="0" maxOccurs="unbounded"/>
	        </xsd:sequence>
	    </xsd:complexType>
	
	    <xsd:complexType name="userType">
	        <xsd:sequence>
	            <xsd:element name="name" type="xsd:string"/>
	            <xsd:element name="age" type="ageType" />
	            <xsd:element name="hobby" type="hobbyType" />
	        </xsd:sequence>
	        <xsd:attribute name="id" type="numberType" use="required"/>
	    </xsd:complexType>
	
	    <xsd:simpleType name="ageType">
	        <xsd:restriction base="xsd:integer">
	            <xsd:minInclusive value="0"/>
	            <xsd:maxInclusive value="100"/>
	        </xsd:restriction>
	    </xsd:simpleType>
	
	    <xsd:simpleType name="hobbyType">
	        <xsd:restriction base="xsd:string">
	            <xsd:enumeration value="抽烟"/>
	            <xsd:enumeration value="喝酒"/>
	            <xsd:enumeration value="烫头"/>
	        </xsd:restriction>
	    </xsd:simpleType>
	
	    <xsd:simpleType name="numberType">
	        <xsd:restriction base="xsd:string">
	            <xsd:pattern value="\d{3}"/>
	        </xsd:restriction>
	    </xsd:simpleType>
	
	</xsd:schema>


	编写user.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>25</age>
	        <hobby>抽烟</hobby>
	    </user>
	
	    <user id="002">
	        <name>于谦</name>
	        <age>55</age>
	        <hobby>烫头</hobby>
	    </user>
	
	    <user id="003">
	        <name>小斌</name>
	        <age>25</age>
	        <hobby>喝酒</hobby>
	    </user>
	
	</users>
  • 3.读取XML
	public class TestDOM4j {
	
	    //获取XML文件中的 所有的元素名称(标签)
	    @Test
	    public void test1() throws DocumentException {
	
	        //1.获取XML解析对象
	        SAXReader reader = new SAXReader();
	
	        //2.解析XML 获取 文档对象 document
	        Document document = reader.read("src\\com\\lagou\\xml03\\user.xml");
	
	        //3.获取根元素
	        Element rootElement = document.getRootElement();
	
	        //获取根元素名称
	        System.out.println(rootElement.getName());
	
	        //获取 根元素下的标签
	        List<Element> elements = rootElement.elements();
	        for (Element element : elements) {
	            System.out.println("根标签下的子节点: " + element.getName());
	
	            List<Element> eList = element.elements();
	            for (Element e : eList) {
	                System.out.println("user标签下的子节点" + e.getName());
	            }
	
	            break;
	        }
	
	    }

	    //获取具体的节点内容,XML中标签的文本信息 和 属性信息
	    @Test
	    public void test2() throws DocumentException {
	
	        //1.获取解析XML的 SAXReader
	        SAXReader reader = new SAXReader();
	
	        //2.获取文档对象
	        Document document = reader.read("src\\com\\lagou\\xml03\\user.xml");
	
	        //3.获取根节点
	        Element rootElement = document.getRootElement();
	
	        //4.获取子节点 user
	        List<Element> elements = rootElement.elements();
	
	        //5.获取集合中的第一个 子节点
	        Element user = elements.get(0);
	
	        //6.获取节点中的文本信息
	        String id = user.attributeValue("id");//获取属性 id的值
	        String name = user.elementText("name");
	        String age = user.elementText("age");
	        String hobby = user.element("hobby").getText(); //使用getText获取当前元素的文本内容
	
	        //打印
	        System.out.println(id + " " + name +" " + age + " " + hobby);
	    }
	}
xpath方式读取xml
  • XPath 是一门在 XML 文档中查找信息的语言。可以是使用xpath查找xml中的内容。
  • XPath的好处: 由于DOM4J在解析XML时只能一层一层解析,所以当XML文件层数过多时使用会很不方便,结合XPATH就可以直接获取到某个元素.(需导入 jaxen-1.1-beta-6.jar)

使用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

常用方法:
	selectSingleNode(query): 查找和 XPath 查询匹配的一个节点。
		参数是Xpath 查询串。
	selectNodes(query): 得到的是xml根节点下的所有满足 xpath 的节点;
		参数是Xpath 查询串。
	Node: 节点对象
  • Xpath读取XML

     数据准备 book.xml
     
     <?xml version="1.0" encoding="UTF-8" ?>
     <bookstore>
         <book id="book1">
             <name>金瓶梅</name>
             <author>金圣叹</author>
             <price>99</price>
         </book>
         <book id="book2">
             <name>红楼梦</name>
             <author>曹雪芹</author>
             <price>69</price>
         </book>
         <book id="book3">
             <name>Java编程思想</name>
             <author>埃克尔</author>
             <price>59</price>
         </book>
    
     </bookstore>
    
    
    
     
     public class TestXPath {
     
         /*
         *  使用selectSingleNode() 方法 查询自定的节点信息
         *
         * */
         @Test
         public void test1() throws DocumentException {
     
             //1.创建XML解析对象
             SAXReader reader = new SAXReader();
     
             //2.解析XML 获取 文档对象
             Document document = reader.read("src\\com\\lagou\\xml04\\book.xml");
     
             //3.通过selectSingleNode() 方法获取 name节点
             Node node1 = document.selectSingleNode("/bookstore/book/name");
             System.out.println("节点的名称: " + node1.getName());
             System.out.println("书名: " + node1.getText());
     
             //4.获取第二本书的书名
             Node node2 = document.selectSingleNode("/bookstore/book[3]/name");
             System.out.println("书名: " + node2.getText());
         }
    
     
         /*
         * 使用 selectSIngleNode() 方法获取 属性值 或者 通过属性值获取到节点信息
         *
         * */
         @Test
         public void test2() throws DocumentException {
     
             SAXReader reader = new SAXReader();
     
             Document document = reader.read("src\\com\\lagou\\xml04\\book.xml");
     
             //1.获取第一个booke节点中的  id属性的值
             Node node1 = document.selectSingleNode("/bookstore/book/attribute::id");
             System.out.println("第一个book的id属性值: " + node1.getText() );
     
             //2.获取最后一个book节点的 id属性值
             Node node2 = document.selectSingleNode("/bookstore/book[last()]/attribute::id");
             System.out.println("最后一个book节点中的属性值: " + node2.getText());
     
             //3.通过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 {
     
             SAXReader reader = new SAXReader();
     
             Document document = reader.read("src\\com\\lagou\\xml04\\book.xml");
     
             //1.查询所有的节点
             List<Node> list = document.selectNodes("//*");
     
             for (Node node : list) {
                 System.out.println("节点名: " + node.getName());
             }
     
             //2.获取所有的书名
             List<Node> list1 = document.selectNodes("//name");
             for (Node node : list1) {
                 System.out.println("书名: " + node.getText());
             }
     
             //3.获取 id值为 book1 的节点中的所有内容
             List<Node> list2 = document.selectNodes("/bookstore/book[@id='book1']//*");
             for (Node node : list2) {
                 System.out.println(node.getName() + " = " + node.getText());
             }
         }
     }
    
JDBC自定义XML
	创建自定义jdbc-config.xml 文件, 保存 数据库连接信息
	
	<?xml version="1.0" encoding="UTF-8" ?>
	<jdbc>
	    <property name="driverClass">com.mysql.jdbc.Driver</property>
	    <property name="jdbcUrl">jdbc:mysql://localhost:3306/lagou_db5?characterEncoding=UTF-8</property>
	    <property name="user">root</property>
	    <property name="password">root</property>
	</jdbc>


	编写工具类 ,使用xpath 读取数据库信息
	
	public class JDBCUtils {
	
	    //1.定义字符串变量 保存连接信息
	    public static String DRIVERNAME;
	    public static String URL;
	    public static String USER;
	    public static String PASSWORD;
	
	    //2.静态代码块
	    static{
	        //使用 XPath语法 对xml中的数据进行读取
	        SAXReader reader = new SAXReader();
	        try {
	            Document document = reader.read("src\\com\\lagou\\xml05\\jdbc-config.xml");
	
	            //1.获取驱动名称
	            Node driver = document.selectSingleNode("/jdbc/property[@name='driverClass']");
	            DRIVERNAME = driver.getText();
	
	            //2.获取URL
	            Node url = document.selectSingleNode("/jdbc/property[@name='jdbcUrl']");
	            URL = url.getText();
	
	            //3.获取用户名
	            Node user = document.selectSingleNode("/jdbc/property[@name='user']");
	            USER = user.getText();
	
	            //4.获取密码
	            Node password = document.selectSingleNode("/jdbc/property[@name='password']");
	            PASSWORD = password.getText();
	
	            //注册驱动
	            Class.forName(DRIVERNAME);
	
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	
	    }

	    //获取连接
	    public static Connection getConnection(){
	        try {
	
	            Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
	
	            return connection;
	        } catch (SQLException e) {
	            e.printStackTrace();
	            return null;
	        }
	
	    }
	
	}

四:综合案例—商城


1.分析设计表关系

在这里插入图片描述

2.环境搭建
  • 项目结构
  • com.lagou.app 测试包 用于对DAO代码进行测试
  • com.lagou.dao dao包 数据访问层,包含所有对数据库的相关操作的类
  • com.lagou.entity 实体包 保存根据数据库表 对应创建的JavaBean类
  • com.lagou.utils 工具包
  • 导入所需Jar包

  • 导入配置文件及工具类

3.JavaBean类创建
  • 在Java一对多的数据关系中,需要遵循以下设计原则:
  1. Java类的名称 = 实体表的名称
  2. Java类的属性 = 实体表的字段
  3. Java类的一个对象 = 表的一行记录
  4. 外键关系 = 引用配置
  • 一个用户拥有多个订单,所以 用户是一的一方, 订单是多的一方
    在这里插入图片描述
    在这里插入图片描述
4.编写DAO类并进行测试
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值