【第41天】DOM4j的使用,JDBC的使用

1 DOM4j的使用

       一种第三方专门用来使用Java代码来读取XML文件和创建XML文件的小技术,用于较为简单易用,被许多框架使用,取代了Java自己的解析XML的技术。

       在Java中使用DOM4j前,需要将dom4j.jar的包导入工程中。

  • 什么是jar包?
    jar包(Java ARchive[档案、把…归档],Java归档)用于聚合大量的Java类文件、相关的元数据和资源(文本、图片等)文件,供使用者调用。相当于硬件连接电脑后需要安装的驱动。JVM虚拟机要使用、外挂一些其他厂商软件的程序或已写好的程序时,需要jar包作为驱动。

  • 什么是API?
    API(Application Programe Interface,应用程序接口)是制造或者发布厂商官方提供的一组接口(规范),一套工具,而不仅仅是一个文档,供用户通过API来实现自己的需求。

1.1 读XML

       现有一个XML文档,需要使用DOM4j由Java程序打印到控制台。使用DOM4j来读取一个现成的XML文件,将内部的数据全部取出。

       首先获取解析器SAXReader,再使用定义文档来绑定解析器,由文档再调用根元素,由根元素再向下依次调用各级子元素。获取元素后需要使用集合存放。如需获取集合中的属性,需要使用元素来调用,同样适用集合存放。

  • 需要读取的XML文件:exec.xml
<?xml version="1.0" encoding="UTF-8"?>
<myroot>
	<country cid="001" name="CHINA PR">
		<province name="北京">
			<area>朝阳区</area>
		</province>
		<province name="上海">
			<area>黄浦区</area>
		</province>
		<province name="山东">
			<city name="济南">
				<area>历下区</area>
			</city>
		</province>
		<province name="湖南">
			<city name="长沙">
				<area>岳麓区</area>
			</city>
		</province>
	</country>
</myroot>
  • 编写Java程序
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.List;

public class ReadTest {
    public static void main(String[] args) {
        try {
//          S1.引入dom4j提供的解析器,这个解析器就类似一台扫描仪
//          Simple API XML,一个简单的解析XML的API
            SAXReader saxReader = new SAXReader();
//          S2.获取被扫描的XML文档,DOM模型已经成型
            Document document = saxReader.read(new File("exec.xml"));
            
//          S3.获取根元素
            Element root = document.getRootElement();
            System.out.println("根元素的名字是:" + root.getName());
            
//          S4.获取一级子元素
            List<Element> firstEles = root.elements();
            for(Element firstEle : firstEles){
                System.out.println("一级子元素的名字是:" + firstEle.getName());
//                获取一级子元素中的属性
                List<Attribute> firstAttrs = firstEle.attributes();
                for(Attribute attr : firstAttrs){
                    System.out.println("一级子元素中的属性名是:" + attr.getName());
                    System.out.println("一级子元素中的属性值是:" + attr.getValue());
                }


//              S5.获取二级子元素
                List<Element> secondEles = firstEle.elements();
                for(Element secondEle : secondEles){
                    System.out.println("二级子元素的名字是:" + secondEle.getName());
                    List<Attribute> secondAttrs = secondEle.attributes();
                    for(Attribute attr : secondAttrs){
                        System.out.println("二级子元素中的属性名是:" + attr.getName());
                        System.out.println("二级子元素中的属性值是:" + attr.getValue());
                    }

//                 S6.获取三级子元素
                   List<Element> thirdEles = secondEle.elements();
                    for(Element thirdEle : thirdEles){
//                      S7—1.如果三级元素中不再有嵌套元素,按照给出的XML,
//                      可以直接获取标签内容                        
                        if(!"".equals(thirdEle.getText().trim()))  System.out.println("三级子元素中嵌套的值是:" + thirdEle.getText());
//                      S7-2.如果三级元素中有嵌套元素,获取四级子元素
                        else {
                            List<Attribute> thirdAttrs = thirdEle.attributes();
                            for(Attribute attr : thirdAttrs){
                                System.out.println("三级子元素中的属性名是:" + attr.getName());
                                System.out.println("三级子元素中的属性值是:" + attr.getValue());
                                List<Element> forthList = thirdEle.elements();
                                for(Element forthEle : forthList){
                                    System.out.println("四级子元素中嵌套的值是:" + forthEle.getText());
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

1.2 写XML

       现有一个写入了DOM模型对象的Java程序,需要使用DOM4j将Java程序写入XML文档。

package com.test;


import com.test.entity.WriteEntity;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class WriteTest {
    public static void main(String[] args) {
        try {
//          S1.创建文档对象模型,此时模型为空
            Document document = DocumentHelper.createDocument();
//          S2.组装根元素
            /**
             * <myroot>
             *
             * </myroot>
             * */
            Element rootEle = document.addElement("myroot");
//          S3.组装一级子元素
            /**
             * <myroot>
             *     <country>
             *
             *     </country>
             * </myroot>
             * */
            Element firstEle = rootEle.addElement("contry");
//          组装一级子元素的属性
            /**
             * <myroot>
             *     <country cid="001" name="CHINA PR">
             *
             *     </country>
             * </myroot>
             * */
            firstEle.addAttribute("cid", "001");
            firstEle.addAttribute("name", "CHINA PR");

//             提取目标XML文档中变化的部分,搞一个实体类,减少代码量
            WriteEntity we1 = new WriteEntity("北京", "", "朝阳区");
            WriteEntity we2 = new WriteEntity("上海", "", "黄浦区");
            WriteEntity we3 = new WriteEntity("山东", "济南", "历下区");
            WriteEntity we4 = new WriteEntity("湖南", "长沙", "岳麓区");
            List<WriteEntity> weList = new ArrayList<>();
            Collections.addAll(weList, we1, we2, we3, we4);

//          S4.将重复的部分循环添加
            for(WriteEntity we : weList){
//              组装二级子元素
                /**
                 * <myroot>
                 *     <country cid="001" name="CHINA PR">
                 *          <province name="">
                 *
                 *          </province>
                 *     </country>
                 * </myroot>
                 * */
                Element secondEle = firstEle.addElement("province");
                secondEle.addAttribute("name", we.getProvinceName());

//                若三级子元素中有城市,再添加四级子元素
                if(!"".equals(we.getCityName())){
                    /**
                     * <myroot>
                     *     <country cid="001" name="CHINA PR">
                     *          <province name="">
                     *              <city name="">
                     *                  <area>***</area>
                     *              </city>
                     *          </province>
                     *     </country>
                     * </myroot>
                     * */
                    Element thirdEle = secondEle.addElement("city");
                    thirdEle.addAttribute("name", we.getCityName());
                    Element forthEle = thirdEle.addElement("area");
                    forthEle.setText(we.getArea());
                }
//                若没有城市,直接是区,只添加到三级子元素
                else{
                    /**
                     * <myroot>
                     *     <country cid="001" name="CHINA PR">
                     *          <province name="">
                     *                  <area name="">***</area>
                     *              </city>
                     *          </province>
                     *     </country>
                     * </myroot>
                     * */
                    Element thirdEle = secondEle.addElement("area");
                    thirdEle.setText(we.getArea());
                }
            }

//          S5.拿取字节输出流,表示输出到哪个路径下叫什么
            OutputStream os = new FileOutputStream("exec_out.xml");
//          S6.设置带换行的输出格式并指定编码(pretty,优雅的,也就是说比不优雅的多了个换行,让XML文档更好看)
            OutputFormat format = OutputFormat.createPrettyPrint();
            format.setEncoding("utf-8");
//          S7.输出到哪里/格式是什么,将前面定义好的引入,DOM4j自定义的字符输出流
            XMLWriter xw = new XMLWriter(os, format);
//          S8.将组装好的模型输出
            xw.write(document);
//          S9.关闭流
            xw.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

实体类
WriteEntity.java

package com.test.entity;

public class WriteEntity {

    private String provinceName;
    private String cityName;
    private String area;

    public WriteEntity() {}

    public WriteEntity(String provinceName, String cityName, String area) {
        this.provinceName = provinceName;
        this.cityName = cityName;
        this.area = area;
    }

    public String getProvinceName() {
        return provinceName;
    }

    public void setProvinceName(String provinceName) {
        this.provinceName = provinceName;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }
}

效果图:
在这里插入图片描述

2 JDBC的使用

       JDBC(Java DataBase Connectivity,Java数据库连接),由C语言的ODBC发展而来,是一种使用面向对象的Java程序操作关系型数据库的语言 ,也是最早的ORM(Object Relation Mapping,对象关系映射)工具。

       JDBC库提供了一个底层API,用来支持独立于任何特定SQL实现的基本SQL功能。提供数据库访问的基本功能。 它是将各种数据库访问的公共概念抽取出来组成的类和接口。JDBC API包括两个包:java.sql(称之为JDBC内核API)和javax.sql(称之为JDBC标准扩展)。它们合在一起,包含了用Java开发数据库应用程序所需的类。

       JDBC使得从Java程序发送SQL语句到数据库变得比较容易,并且适合所有SQL方言。只需要获知要连接数据库的驱动包名、链接写法就可以使用Java来操作数据库。 也就是说为一种数据库如Oracle写好了Java应用程序后,没有必要再为MS SQL Server再重新写一遍。而是可以针对各种数据库系统都使用同一个Java应用程序。使用JDBC API访问数据库时,我们要针对不同的数据库采用不同的驱动程序,驱动程序实际上是适合特定的数据库JDBC接口的具体实现, 它们一般具有建立一个与数据源(数据库)的连接、发送SQL语句到数据源、取回结果集三种功能。

  • 常用数据库驱动和链接

Oracle
驱动:oracle.jdbc.driver.OracleDriver
URL:jdbc:oracle:thin:@<machine_name><:port>:dbname
注:machine_name:数据库所在的机器的名称;
port:端口号,默认是1521
thin:Oracle的子协议,也可以是oci
dbname:数据源(库)名
例:jdbc:oracle:thin:@localhost:1521:orcl

MySQL
驱动:com.mysql.jdbc.Driver
URL:jdbc:mysql://<machine_name><:port>/dbname
例:jdbc:mysql://localhost:3306/db_test
jdbc:mysql:///db_test(三斜线也表示本地)
注:machine_name:数据库所在的机器的名称;
port:端口号,默认3306

SQL server
驱动:com.microsoft.jdbc.sqlserver.SQLServerDriver
URL:jdbc:microsoft:sqlserver://<machine_name><:port>;DatabaseName=
注:machine_name:数据库所在的机器的名称;
port:端口号,默认是1433

在这里插入图片描述

  • 与Mybatis、Hibernate之间的关系:
    全手动:JDBC
    半自动:Mybatis
    全自动:Hibernate

2.1 使用ORM工具时JDBC的操作步骤

2.1.1 S1.创建关系表(关系型数据库中的表都称为关系表)
create table student(
  id int primary key auto_increment,
  name varchar(10) not null,
  salary int not null,
  birthday date not null
)
2.1.2 S2.创建实体类

       一般将实体类放置在***.***.po或***.***.bean或***.***.entity包中。

注意:

  • 与关系表重名(实体类首字母大写)
  • 变量对应字段名
  • 必须书写空参构造方法
  • 酌情书写带参构造方法
  • 酌情覆盖toString()(如果需要打印属性)
package com.test.po;

import java.util.Date;

public class Student {
    private Integer id;
    private String name;
    private Integer salary;
    private Date birthday;

    public Student() {
    }

    public Student(Integer id, String name, Integer salary, Date birthday) {
        this.id = id;
        this.name = name;
        this.salary = salary;
        this.birthday = birthday;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSalary() {
        return salary;
    }

    public void setSalary(Integer salary) {
        this.salary = salary;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                ", birthday=" + birthday +
                '}';
    }
}
2.1.3 S3.创建工厂类

       工厂类是设计模式------工厂模式的一种表现方式,通过创建工厂类可获取一个将Java代码与数据库连接起来的连接,而在没有引入数据库连接池之前,一个工厂类只有一个连接供使用,所以在连接使用完毕后一定要关闭。

       一般工厂类放置在***.***.factory包中。

package com.test.factory;

import java.sql.Connection;
import java.sql.DriverManager;

public class Factory {

    //S1.加载不同关系型数据库厂商提供的驱动
    //使用反射来进行驱动(类)的加载
    //安装了这些驱动之后
    //可以使用几乎相同的Java代码来操作不同语法的关系型数据库
    //驱动程序仅仅安装一次,通常放置在静态初始化块中
    static{
        try {
            //通过工厂获取连接
            Class.forName("com.mysql.jdbc.Driver");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //S2.通过此方法来获取连接,
    //方法设置为静态的原因是,
    //方法不需要创建对象就可以被调用,
    //另外方法在类创建时就可以被加载进来,不需在调用时再次创建,提高效率
    public static Connection getConnection(){
        try {
            //连接数据源(database)
            return DriverManager.getConnection("jdbc:mysql:///db_test", 
            "数据库用户名(MySQL一般是root)", "数据库密码");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    //S3:此方法用来释放资源
    //一般释放标准顺序为关闭结果集-->关闭执行器-->关闭连接
    public static void close(ResultSet rs
            , Statement st
            , Connection con){
        try{
            if(rs!=null)
                rs.close();
        }catch(Exception ex){
            ex.printStackTrace();
        }finally{
            try{
                if(st!=null)
                    st.close();
            }catch(Exception ex){
                ex.printStackTrace();
            }finally{
                try{
                    if(con!=null)
                        con.close();
                }catch(Exception ex){
                    ex.printStackTrace();
                }
            }
        }
    }
}
2.1.4 S4.测试是否连通
package com.test;

import com.test.factory.Factory;

import java.sql.Connection;

public class TestConnection {
    public static void main(String[] args) {
        try {
            Connection connection = Factory.getConnection();
//            常用的代替if-else的方法
//            在if中添加返回语句,else语句放在if的外面
            if(connection == null){
                System.out.println("Connection fail.");
                return;
            }
            System.out.println("Connection success.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.2 测试连通后可以执行的操作

2.2.1 获取执行器(Statement)、使用结果集(ResultSet)接收查询数据

       获取连接之后可以拿取执行器,执行器的作用是用来执行SQL语句,常用的两种执行器Statement、PreparedStatement。 两种执行器都可以根据SQL语句的不同类别调用不同的方法。这里先以Statement执行器来举例。

2.2.1.1 boolean execute()

       执行DQL语句返回true,执行DML语句返回false,但DML语句依然可以运行。因逻辑有些奇怪,使用的场合不多。

package com.test;

import com.test.factory.Factory;

import java.sql.Connection;
import java.sql.Statement;

public class TestConnection {
    public static void main(String[] args) {
        try {

            Connection connection = Factory.getConnection();

//            获取执行器
            Statement statement = connection.createStatement();

//            定义要被执行的DML、DQL语句,
//            如果语句写错,会报sql syntax error错误
            String dql1 = "select * from student";
            String dml1 = "insert into student values(null, 'zs', 1000, '1991-05-05')";
            String dml2 = "update student set name='zs111' where name='zs'";
            String dml3 = "delete from student where name='zs111'";

            boolean exec_dql = statement.execute(dql1);
            System.out.println("exec_dql------->" + exec_dql);

            boolean exec_dml1 = statement.execute(dml1);
            System.out.println("exec_dml1------->" + exec_dml1);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

效果图:
在这里插入图片描述
成功插入一条数据
在这里插入图片描述

2.2.1.2 int executeUpdate()

       用来执行DML语句,返回值是一个整数,表示受影响的行数。执行DQL语句立刻报错。(延续上面的代码继续执行)

在executeUpdate()方法中执行DQL语法的报错:
在这里插入图片描述

            String dql1 = "select * from student";
            String dml1 = "insert into student values(null, 'zs', 1000, '1991-05-05')";
            //更新所有符合要求的数据
            String dml2 = "update student set name='zs111' where name='zs'";
            //删除所有符合要求的数据
            String dml3 = "delete from student where name='zs111'";

            System.out.println("已添加了" + statement.executeUpdate(dml1) + "条新数据");
            System.out.println("已修改了" + statement.executeUpdate(dml2) + "条数据");
            System.out.println("已删除了" + statement.executeUpdate(dml3) + "条数据");             

效果图:
在这里插入图片描述

数据库已不存在数据
在这里插入图片描述

2.2.1.3 ResultSet executeQuery()

       执行DQL语句,返回一个结果集。执行DML语句立刻报错。返回的结果集类型是java.sql.ResultSet。返回的数据全部封装在结果集中,通过解析可以拿取返回的数据。
       在进行数据的拿取之前首先要判断是否存在有效数据,不能根据结果集是否为null,来判断是否存在有效数据,因为结果集永远不可能为null,至少有一行表头。

(student表添加了一个passwd字段)
在这里插入图片描述

       通过.next()是否返回true来判断指针能否下移,如果可以下移,则返回true表示有有效数据;当返回false时,则指针无法移动了,没有有效数据。可以通过使用所指行的get数据类型(列数)来返回数据,还可以使用get数据类型(列名)返回数据。

           String dql1 = "select * from student";
           ResultSet rs = statement.executeQuery(dql1);
//         可以通过使用所指行的get数据类型(列数)来返回数据,
//         也可以使用get数据类型(列名)返回数据。
//         结果集中的事件类型,因为传入时已格式化,所以打印时直接输出即可。
           while(rs.next()){
               System.out.println("学号:" + rs.getInt(1)
                       + "\t姓名:" + rs.getString("name")
                       + "\t密码:" + rs.getString(3)
                       + "\t薪资:" + rs.getInt("salary")
                       + "\t生日:" + rs.getDate(5));
           }
2.2.1.4 int[] executeBatch()

       批处理SQL语句的方法,注意不能处理DQL语句,且需要关闭MySQL自动提交事务的功能。MySQL事务默认自动提交,但是效率太低。
       批处理且手动提交像一把自动步枪,把弹夹中压入子弹后可以连发,而不需要打一发上一次子弹,前者明显效率更高。
       大批量处理数据时,使用批处理且关闭自动事务提交,使用手动提交事务,效率最高。像下面的例子:

package com.test;

import com.test.factory.Factory;

import java.sql.Connection;
import java.sql.Statement;

public class TestBatch {
    public static void main(String[] args) throws Exception{
        String sql1 = "insert into student values(null, 'Eric1', '12345',  3000, '1990-06-03')";
        String sql2 = "insert into student values(null, 'Ruby', '123456',  4000, '1993-06-08')";
        String sql3 = "insert into student values(null, 'Cindy', '1234567',  2500, '1990-07-09')";
        String sql4 = "delete from student where id > 5";
//        获取连接
        Connection connection = Factory.getConnection();
//        关闭mysql设置的自动提交事务功能,MySQL写完执行就自动提交了,这一点跟Oracle不同
//        批处理中若出错中断,自动提交出错后会造成前后修改/未修改状态不一致,所以需要先将自动提交取消
        connection.setAutoCommit(false);
        Statement statement = connection.createStatement();
        statement.addBatch(sql1);
        statement.addBatch(sql2);
        statement.addBatch(sql3);
        statement.addBatch(sql4);
        int[] count = statement.executeBatch();
//        需要自行提交事务
        connection.commit();
        for(int a : count){
            System.out.println("更改的记录数是" + a);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值