jdbc-day01

2024-09-02 04:52
文章标签 jdbc day01

本文主要是介绍jdbc-day01,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

_01Simple_JDBCDemo01

package com.jdbc._01Simple;import java.sql.*;/***  JDBC的第一个程序编写: 修改mydb库中的emp表中的7369这个员工的部门编号为30*   准备工作: 准备好项目,然后加载第三方jar包,即MYSQL的驱动程序。注意, add as Library*/public class JDBCDemo01 {public static void main(String[] args) throws ClassNotFoundException, SQLException {//第一步:加载驱动Class.forName("com.mysql.cj.jdbc.Driver");/*第二步:获取连接,(使用DriverManager 自动识别程序,并向数据库发送连接请求,如果成功,则返回连接会话)参数url: 连接数据库的路径地址 jdbc:mysql://ip:port/库名?serverTimezone=Asia/Shanghai&useTimezone=true参数user: 连接数据库的用户名  root参数password: 连接数据库的密码  111111*/Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai&useTimezone=true","root","111111");//第三步:通过连接会话对象,来获取可以发送sql语句的对象Statement stat = conn.createStatement();//第四步:使用Statement的方法来发送sql语句/*execute(String sql): 发送DDL的方法executeUpdate(String sql): 发送DML的方法,返回受影响的行数executeQuery(String sql): 发送DQL的方法,返回结果集Statement该对象发送的sql语句,每次都会解析、编译,效率低,所以使用PreparedStatement解析SQL: 校验SQL的语法格式是否正确编译SQL: 验证书写的表名,字段等是否正确,是否与数据库中一致,若存在,则编译通过*/// 修改mydb库中的emp表中的7369这个员工的部门编号为30int num = stat.executeUpdate("update emp set deptno= 30 where empno = 7369");//第五步:处理结果集System.out.println("受影响的条数"+num);//第六步:关闭资源stat.close();}
}

_01Simple_JDBCDemo02

package com.jdbc._01Simple;import java.sql.*;/*** 使用JDBC来完成第二个程序:查询emp表中的20号部门所有的员工,信息不使用**/public class JDBCDemo02 {public static void main(String[] args) throws ClassNotFoundException, SQLException {// 第一步 加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//第二步:获取连接,(使用DriverManager 自动识别程序,并向数据库发送连接请求,如果成功,则返回连接会话)Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai&useTimezone=true","root","111111");// 第三步:通过连接会话对象,来获取可以发送sql语句的对象,并发送sqlStatement stat = conn.createStatement();ResultSet sql = stat.executeQuery("select empno,ename,job,mgr,deptno,sal,comm,hiredate from emp where deptno = 20 ");//注意: DBMS执行之后的结果被发送到客户端,被封装到ResultSet对象中// 第四步:处理查询结果集   里面存储了N行记录,指针默认在第一行之前,因此想要获取每一行的数据,需要移动指针while(sql.next()){  //向下移动指针int empno = sql.getInt(1);String ename = sql.getString(2);String job = sql.getString(3);int mgr = sql.getInt(4);int deptno = sql.getInt(5);double sal = sql.getDouble("sal");double comm = sql.getDouble("comm");Date hiredate = sql.getDate("hiredate");System.out.println(empno + "\t" + ename + "\t" + job + "\t" + mgr + "\t" + deptno + "\t" + sal + "\t" + comm + "\t" + hiredate);}// 第五步:关闭资源conn.close();}
}

_01Simple_JDBCDemo03

package com.jdbc._01Simple;import java.sql.*;public class JDBCDemo03 {public static void main(String[] args) throws ClassNotFoundException, SQLException {Class.forName("com.mysql.cj.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai&useTimezone=true","root","111111");Statement stat = conn.createStatement();int sql = stat.executeUpdate("insert into emp values (10000,'superman','hero',7369,'2024-08-30',2000,500,40 )");System.out.println(sql);stat.close();}}

_01Simple_JDBCDemo04

package com.jdbc._01Simple;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;public class JDBCDemo04 {public static void main(String[] args) throws ClassNotFoundException, SQLException {Class.forName("com.mysql.cj.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai&useTimezone=true","root","111111");Statement stat = conn.createStatement();int sql = stat.executeUpdate("delete from emp where empno=10000");System.out.println(sql);conn.close();}
}

_02TestDBUtil_JDBCDemo01

package com.jdbc._02TestDBUtil;import com.jdbc.Util.DBUtil;import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;/*** 使用DBUtil 重构 _01Simple.JDBCdemo01中的代码*/public class JDBCDemo01 {public static void main(String[] args) throws SQLException {//调用DBUtil的连接对象,获取连接会话Connection conn = DBUtil.getConnection();Statement stat = conn.createStatement();int num = stat.executeUpdate("update emp set deptno= 30 where empno = 7369");System.out.println("受影响的条数" + num);DBUtil.closeConnection(conn);}
}

_02TestDBUtil_JDBCDemo02

package com.jdbc._02TestDBUtil;import com.jdbc.Util.DBUtil;import java.sql.*;/*** 使用JDBC来完成第二个程序:查询emp表中的20号部门所有的员工,信息不使用**/public class JDBCDemo02 {public static void main(String[] args) throws ClassNotFoundException, SQLException {Connection conn = DBUtil.getConnection();Statement stat = conn.createStatement();ResultSet sql = stat.executeQuery("select empno,ename,job,mgr,deptno,sal,comm,hiredate from emp where deptno = 20 ");while(sql.next()){  //向下移动指针int empno = sql.getInt(1);String ename = sql.getString(2);String job = sql.getString(3);int mgr = sql.getInt(4);int deptno = sql.getInt(5);double sal = sql.getDouble("sal");double comm = sql.getDouble("comm");Date hiredate = sql.getDate("hiredate");System.out.println(empno + "\t" + ename + "\t" + job + "\t" + mgr + "\t" + deptno + "\t" + sal + "\t" + comm + "\t" + hiredate);}DBUtil.closeConnection(conn);}
}

_03Batch_BatchTest

package com.jdbc._03Batch;import com.jdbc.Util.DBUtil;import java.sql.Connection;
import java.sql.Statement;/*** 为什么使用JDBC的批处理: 因为Statement发送的SQL语句,DBMS每次逗号解析,编译,性能较低** 批处理的方法:  可以提前将一部分SQL存储在缓存区中,然后一次性的将缓存区中的SQL刷到DBMS里* 这样可以大大减少了客户端与数据库的交互次数,从而变相的提高效率。**         testbatch*               id int primary key auto_increment,*               name varchar(20),*               ender char(1)*/public class BatchTest {public static void main(String[] args) {Connection conn =null;try {conn = DBUtil.getConnection();// 向数据库中插入1030条记录Statement stat = conn.createStatement();for (int i = 0; i < 1030; i++) {String[] genders= {"f","m"};String gender = genders[(int)(Math.random()*2)];String sql = "insert into testbatch values(null,'zhaoyun"+i+"','"+gender+"')";// 将SQL语句存储在缓存区中stat.addBatch(sql);// 缓存区储存50个,就冲刷一次if (i%50==0){stat.executeBatch();}}// 清空缓存区stat.clearBatch();} catch (Exception e){e.printStackTrace();}finally {DBUtil.closeConnection(conn);}}
}

_04SQLIniect_Account

package com.jdbc._04SQLInject;import java.sql.Date;
import java.util.Objects;/*** 定义一个java类型Account 与表的记录进行映射。   一个Account对象表示表中的一条记录信息*/
public class Account {private int id;private String accountId;private double balance;private String username;private String password;private String idcard;private Date opertime;private char gender;private Account(){}public Account(int id, String accountId, double balance, String username, String password, String idcard, Date opertime, char gender) {this.id = id;this.accountId = accountId;this.balance = balance;this.username = username;this.password = password;this.idcard = idcard;this.opertime = opertime;this.gender = gender;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getAccountId() {return accountId;}public void setAccountId(String accountId) {this.accountId = accountId;}public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getIdcard() {return idcard;}public void setIdcard(String idcard) {this.idcard = idcard;}public Date getOpertime() {return opertime;}public void setOpertime(Date opertime) {this.opertime = opertime;}public char getGender() {return gender;}public void setGender(char gender) {this.gender = gender;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Account account = (Account) o;return id == account.id && Double.compare(balance, account.balance) == 0 && gender == account.gender && Objects.equals(accountId, account.accountId) && Objects.equals(username, account.username) && Objects.equals(password, account.password) && Objects.equals(idcard, account.idcard) && Objects.equals(opertime, account.opertime);}@Overridepublic int hashCode() {return Objects.hash(id, accountId, balance, username, password, idcard, opertime, gender);}@Overridepublic String toString() {return "Account{" +"id=" + id +", accountId='" + accountId + '\'' +", balance=" + balance +", username='" + username + '\'' +", password='" + password + '\'' +", idcard='" + idcard + '\'' +", opertime=" + opertime +", gender=" + gender +'}';}
}

_04SQLIniect_AppClient

package com.jdbc._04SQLInject;import java.util.Scanner;/*** 使用Scanner来模拟登录案例的客户端界面*/
public class AppClient {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();//来一个服务端对象//AppServer server   = new AppServer();AppServer2 server = new AppServer2();//调用服务端的checkLogin方法检查Account account = server.checkLogin(username,password);if(account == null){System.out.println("用户名或密码不正确,登录失败");}else{System.out.println("登录成功,正在跳转......");}}
}

_04SQLIniect_AppServer

package com.jdbc._04SQLInject;import com.jdbc.Util.DBUtil;import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.Statement;/*** 定义一个服务端。*   提供一个用于检测用户名和密码是否正确的方法。*   如果正确,返回一个Account对象*   如果不正确,返回一个null*/
public class AppServer {/**** @param username   要验证的用户名* @param password   要验证的密码* @return*/public Account checkLogin(String username, String password) {Account account = null;Connection conn = null;try{//连接数据库conn = DBUtil.getConnection();Statement stat = conn.createStatement();//用户名和密码同时作为where里的条件,进行查询,如果能查询到数据,说明用户名和密码是正确的String sql = "select * from bank_account where user_name = '" + username + "' and user_pwd = '" + password + "'";//发送到数据库中执行ResultSet resultSet = stat.executeQuery(sql);if(resultSet.next()){int id = resultSet.getInt("id");String account_id = resultSet.getString("account_id");double balance = resultSet.getDouble("account_balance");String user_name = resultSet.getString("user_name");String user_pwd = resultSet.getString("user_pwd");String idcard = resultSet.getString("user_idcard");Date oper_time = resultSet.getDate("oper_time");String gender = resultSet.getString("gender");account = new Account(id,account_id,balance,user_name,user_pwd,idcard,oper_time,gender.charAt(0));}}catch (Exception e){e.printStackTrace();}finally {DBUtil.closeConnection(conn);}return account;}
}

_04SQLIniect_AppServer2

package com.jdbc._04SQLInject;import com.jdbc.Util.DBUtil;import java.sql.*;/*** 定义一个服务端。*   提供一个用于检测用户名和密码是否正确的方法。*   如果正确,返回一个Account对象*   如果不正确,返回一个null***   SQL注入:  黑客通过传值的方式,改变SQL的条件结构,比如由两个条件,变成了三个条件*             "....where username ='"+username+"' and password='"+password+"'**             password的值,传入了  111111' or '1'='1  因此就会变成**              "....where username ='"+username+"' and password='111111' or '1'='1'**              可以看出,多一个or连接  1=1恒成立的条件。**  也就是说Statement可以通过SQL注入的方法将条件的个数改变,换句话说,就是改变了SQL语句的整体结构。**  因此Sun公司有设计了一个Statement的子接口PreparedStatement。**  PrepatedStatement这个接口会先将SQL结构提前发送到DBMS中,并且DBMS会将该结构锁死。黑客再次通过SQL注入*  的方法传入了带有or连接的恒成立的条件,DBMS也只会将其当成一个参数,而不是条件。**  同一个SQL语句或者是相似的SQL语句,PreparedStatemnt只会解析一次。因此效率相对于Statement也高。**/
public class AppServer2 {/**** @param username   要验证的用户名* @param password   要验证的密码* @return*/public Account checkLogin(String username, String password) {Account account = null;Connection conn = null;try{//连接数据库conn = DBUtil.getConnection();/*** 调用prepareStatement(String sql)  先确定SQL的结构,发送到DBMS中* 使用?来表示占位,用于传参。*/String sql = "select * from bank_account where user_name = ? and user_pwd = ? ";PreparedStatement stat = conn.prepareStatement(sql);//提前发送完毕后,要继续给?赋值    ?从左到右的索引 是从1开始stat.setString(1, username);stat.setString(2, password);//再次将参数发送到数据库中执行ResultSet resultSet = stat.executeQuery();if(resultSet.next()){int id = resultSet.getInt("id");String account_id = resultSet.getString("account_id");double balance = resultSet.getDouble("account_balance");String user_name = resultSet.getString("user_name");String user_pwd = resultSet.getString("user_pwd");String idcard = resultSet.getString("user_idcard");Date oper_time = resultSet.getDate("oper_time");String gender = resultSet.getString("gender");account = new Account(id,account_id,balance,user_name,user_pwd,idcard,oper_time,gender.charAt(0));}}catch (Exception e){e.printStackTrace();}finally {DBUtil.closeConnection(conn);}return account;}
}

_05Transfer_BankTransferDemo

package com.jdbc._05Transfer;import com.jdbc.Util.DBUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** 演示银行转账业务:*     两个账号,一个金额*/
public class BankTransferDemo {public static void main(String[] args) throws Exception {boolean flag = transfer("6225113088436225","6225113088436226",10000);System.out.println("flag:"+flag);}/**** @param fromAccount  转出账号* @param toAccount    转入账号* @param money        要转出的金额* @return      成功 true   失败false*/public static boolean transfer(String fromAccount, String toAccount, int money) throws Exception {Connection conn = null;try {//第一大步:先校验参数是否合理if(money < 0){return false;}if(fromAccount == null || toAccount == null|| fromAccount.trim().length() == 0|| toAccount.trim().length() == 0){return false;}//验证两个账号是否真实有效,去数据库中验证conn = DBUtil.getConnection();String sql = "select * from bank_account where account_id=?";//先验证转出账号PreparedStatement ps = conn.prepareStatement(sql);ps.setString(1, fromAccount);ResultSet resultSet = ps.executeQuery();if(!resultSet.next()){System.out.println("转出账号不存在");//说明转出账号不存在return false;}//再验证转入账号PreparedStatement ps2 = conn.prepareStatement(sql);ps2.setString(1, toAccount);ResultSet resultSet1 = ps2.executeQuery();if(!resultSet1.next()){System.out.println("转入账号不存在");//说明转入账号不存在return false;}//第二大步: 上述验证都通过了,就可以转账了//因为转账设计两个update语句,因此应该将这两个update语句当做一个事务来对待//所以,在第一个update 之前,开启一个事务conn.setAutoCommit(false);//获取转出账号的余额double fromBalance = resultSet.getDouble("account_balance");if (fromBalance<money){System.out.println("余额不足");return false;}//余额充足,可以转出String Sql2 = "update bank_account set account_balance=? where account_id=?";PreparedStatement prep = conn.prepareStatement(Sql2);prep.setDouble(1, fromBalance-money);prep.setString(2, fromAccount);prep.executeUpdate();//写一个异常,来模拟程序正好执行到这里,银行断电String str = null;System.out.println(str.length());/*造成的结果: 出账没问题,已经扣除相应的金额,但是入账除了问题,没有执行入账,因此入账失败程序员不应该让这样的事情发生,因此引入了一个关于数据库的概念: 事务事务的简单理解: 就是做一件事,这件事是一个整体,做就完全做完;不做就完全不做,不管进行到什么环节,都认为没有开始特点:ACIDA:原子性:一个事务,是一个整体,不可切割C:一致性:一个事务,做这件事之前和之后的数据之后是一样的I:隔离性:一个事务,只能进行一个操作,不能被其他事务干扰(类似线程同步)D:持久性:一个事务,如果完成了,就必须持久化到磁盘上TCL(事务控制语言): 提供三个关键字,保证这些特性:commit: 提交,进行持久化保存rollback: 回滚,撤销,将数据恢复到上一步savepoint: 设置一个保存点,如果出错,可以回滚到这个点,而不是从一开始什么时候设计到事务的概念?只有当使用DML语言(insert into;update;delete)时,才会触发事务- 默认情况下,mysql的一个DML语句,就是一个完整的事务,会自动触发commit操作- 如果你的事务涉及到多个DML时,应该取消mysql的默认机制,自己来控制事务的提交和回滚*///转入double toBalance = resultSet1.getDouble("account_balance");PreparedStatement prep2 = conn.prepareStatement(Sql2);prep2.setDouble(1, toBalance+money);prep2.setString(2, toAccount);prep2.executeUpdate();//能执行到此,说明转账业务成功进行 就应该手动提交该事务conn.commit();return true;}catch (Exception e) {e.printStackTrace();//如果出现异常,或者断电的情况,我们要将事务回滚到最初的状态try {conn.rollback();} catch (SQLException ex) {throw new RuntimeException(ex);}}finally {DBUtil.closeConnection(conn);}return false;}
}

Util_DBUtil

package com.jdbc.Util;import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;/*** 自定义一个连接、关闭数据库的工具类型。* 提供一个连接方法:  getConnection()* 提供一个关闭方法:  closeConnection(Connection conn)*/public class DBUtil {private static String driverClass;private static String url;private static String user;private static String password;static {try {//使用IO流读取jdbc.properties配置文件//getResourceAsStream的形参是相对路径,从当前类所在的包中寻找InputStream inputStream = DBUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");// 创建Properties对象Properties prop = new Properties();//调用集合对象的load方法,读取流中信息prop.load(inputStream);// 从对象身上获取相关的键值对,注意传入的key是文件中等号前的名driverClass = prop.getProperty("driverClass");url = prop.getProperty("url");user = prop.getProperty("username");password = prop.getProperty("password");} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) {//调用连接数据库的方法Connection connection = DBUtil.getConnection();System.out.println(connection);//调用关闭数据库的方法closeConnection(connection);}// 连接数据库public static Connection getConnection() {Connection conn = null;try {Class.forName(driverClass);conn = DriverManager.getConnection(url, user, password);} catch (Exception e) {e.printStackTrace();}return conn;}// 关闭连接public static void closeConnection(Connection conn) {if (conn != null) {try {conn.close();} catch (Exception e) {e.printStackTrace();}}}
}

jdbc.properties

driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai&useTimezone=true
username=root
password=111111

这篇关于jdbc-day01的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129049

相关文章

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

Hibernate框架中,使用JDBC语法

/*** 调用存储过程* * @param PRONAME* @return*/public CallableStatement citePro(final String PRONAME){Session session = getCurrentSession();CallableStatement pro = session.doReturningWork(new ReturningWork<C

jdbc连接数据库使用sid和service_name的区别 ?

问题描述: ORA-12505, TNS:listener does not currently know of SID given in connect descriptor The Connection descriptor used by the client was: 10.12.162.84:1521:xxxx  oracle数据的tnsnames.ora中配置的是:SERVICE

Java项目中,配置打印 JDBC 日志的几种方法

在 IDEA 项目中,如果你想打印 JDBC 日志,可以通过配置日志框架(如 Logback 或 Log4j)来实现。Spring Boot 使用的默认日志框架是 Logback,你可以通过在 application.yml 文件中配置日志级别来打印 JDBC 日志。 方法 1: 使用 application.yml 配置 JDBC 日志 logging:level:# 显示 SQL 语句co

基于shard-jdbc中间件,实现数据分库分表

一、水平分割 1、水平分库 1)、概念: 以字段为依据,按照一定策略,将一个库中的数据拆分到多个库中。 2)、结果 每个库的结构都一样;数据都不一样; 所有库的并集是全量数据; 2、水平分表 1)、概念 以字段为依据,按照一定策略,将一个表中的数据拆分到多个表中。 2)、结果 每个表的结构都一样;数据都不一样; 所有表的并集是全量数据; 二、Shard-jdbc 中间件 1、架构图 2、特点

基于Shard-Jdbc分库分表,数据库扩容方案

一、数据库扩容 1、业务场景 互联网项目中有很多“数据量大,业务复杂度高,需要分库分表”的业务场景。 这样分层的架构 (1)上层是业务层biz,实现业务逻辑封装; (2)中间是服务层service,封装数据访问; (3)下层是数据层db,存储业务数据; 2、扩容场景和问题 当数据量持续新增,面临着这样一些需求,两台数据库无法容纳,需要数据库扩容,这里选择2台—扩容到3台的模式,如下图

Java笔试面试题AI答之JDBC(3)

文章目录 13. 编写JDBC连Oracle的程序?14. 简述JDBC的主要组件有哪些 ?15. JDBC中如何防止SQL注入攻击?1. 使用预处理语句(PreparedStatement)2. 避免在SQL查询中直接拼接用户输入的数据总结 16. JDBC的脏读是什么?哪种数据库隔离级别能防止脏读?脏读(Dirty Read)哪种数据库隔离级别能防止脏读? 17. 简述JDBC ex

javaweb-day01-7(XML 解析-案例)

1、以如下格式的exam.xml文件为例 exam.xml <?xml version="1.0" encoding="UTF-8" standalone="no"?><exam><student examid="222" idcard="111"><name>张三</name><location>沈阳</location><grade>89.00</grade></student><st

javaweb-day01-6(XML 解析 - Jaxp的DOM方式解析)

Jaxp解析开发包     JAXP 开发包是J2SE的一部分,它由javax.xml、org.w3c.dom 、org.xml.sax 包及其子包组成  在 javax.xml.parsers 包中,定义了几个工厂类,程序员调用这些工厂类,可以得到对xml文档进行解析的DOM 或SAX 的解析器对象。   DOM解析方式: 步骤: 1.        调用javax.xml.

javaweb-day01-5(XML 解析-概述)

XML 解析:   (create  read  update  delete)   XML 解析方式有两种:DOM 和SAX   DOM(Document  Object  Model)基于树和节点的文档对象模型。w3c组织推荐的处理xml文档的一种方式。      *优点:crud方便,操作速度也特别快。       *缺点:耗内存,易导致内存溢出,不适合操作大的xml文档。