学习体会 没有JDBC的时候,如果现在要开发一套系统,使用Java连接MySQL数据库,那么这时候Java程序员需要了解MySQL驱动API,如果使用Java连接Oracle数据库,那么这个时候Java程序员需要了解Oracle数据库驱动API。 SUN公司提供一套统一的规范(接口)。然后各个数据库生产商提供这套接口的实现。这套接口规范就是JDBC的规范。 file:///C:/Users/lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg 这个方法可以完成驱动的注册,但是实际开发中一般不会使用这个方法完成驱动的注册!!! 原因: 如果需要注册驱动,就会使用DriverManager.registerDriver(newDriver());,但是查看源代码发现,在代码中有一段静态代码块,静态代码块已经调用了注册驱动的方法。 file:///C:/Users/lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg 这个方法就是用来获得与数据库连接的方法:这个方法中有三个参数 file:///C:/Users/lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg file:///C:/Users/lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image008.jpg file:///C:/Users/lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg Statement :执行SQL CallableStatement :执行数据库中存储过程 PreparedStatement :执行SQL.对SQL进行预处理。解决SQL注入漏洞。 DBC程序执行结束后,将与数据库进行交互的对象释放掉,通常是ResultSet,Statement,Connection。 这几个对象中尤其是Connection对象是非常稀有的。这个对象一定要做到尽量晚创建,尽早释放掉。 if(rs !=null){ try { rs.close(); }catch (SQLException e) { e.printStackTrace(); } rs = null; } if(statement!=null){ try { statement.close(); }catch (SQLException e) { e.printStackTrace(); } statement = null; } if(conn !=null){ try { conn.close(); }catch (SQLException e) { e.printStackTrace(); } conn = null; } 因为传统JDBC的开发,注册驱动,获得连接,释放资源这些代码都是重复编写的。所以可以将重复的代码提取到一个类中来完成。 /** * JDBC的工具类 * @author jt * */ public class JDBCUtils { private static final String driverClassName; private static final String url; private static final String username; private static final String password; static{ driverClassName="com.mysql.jdbc.Driver"; url="jdbc:mysql:///web_test3"; username="root"; password="abc"; } /** * 注册驱动的方法 */ public static void loadDriver(){ try { Class.forName(driverClassName); } catch (ClassNotFoundException e){ e.printStackTrace(); } } /** * 获得连接的方法 */ public static Connection getConnection(){ Connection conn = null; try{ // 将驱动一并注册: loadDriver(); // 获得连接 conn = DriverManager.getConnection(url,username, password); }catch(Exception e){ e.printStackTrace(); } return conn; } /** * 释放资源的方法 */ public static void release(Statement stmt,Connectionconn){ if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null; } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } public static void release(ResultSet rs,Statement stmt,Connectionconn){ // 资源释放: if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null; } if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null; } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } } @Test /** * 查询操作:使用工具类 */ public void demo1(){ Connection conn = null; Statement stmt = null; ResultSet rs = null; try{ // 获得连接: conn = JDBCUtils.getConnection(); // 创建执行SQL语句的对象: stmt = conn.createStatement(); // 编写SQL: String sql = "select* from user"; // 执行查询: rs = stmt.executeQuery(sql); // 遍历结果集: while(rs.next()){ System.out.println(rs.getInt("id")+""+rs.getString("username")+""+rs.getString("password")); } }catch(Exception e){ e.printStackTrace(); }finally{ // 释放资源: JDBCUtils.release(rs, stmt,conn); } } 在早期互联网上SQL注入漏洞普遍存在。有一个网站,用户需要进行注册,用户注册以后根据用户名和密码完成登录。假设现在用户名已经被其他人知道了,但是其他人不知道你的密码,也可以登录到网站上进行相应的操作。 需要采用PreparedStatement对象解决SQL注入漏洞。这个对象将SQL预先进行编译,使用?作为占位符。?所代表内容是SQL所固定。再次传入变量(包含SQL的关键字)。这个时候也不会识别这些关键字。 public class UserDao { public boolean login(String username,Stringpassword){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; // 定义一个变量: boolean flag = false; try{ // 获得连接: conn = JDBCUtils.getConnection(); // 编写SQL语句: String sql = "select* from user where username = ? and password = ?"; // 预编译SQL pstmt = conn.prepareStatement(sql); // 设置参数: pstmt.setString(1, username); pstmt.setString(2, password); // 执行SQL语句: rs = pstmt.executeQuery(); if(rs.next()){ // 说明根据用户名和密码可以查询到这条记录 flag = true; } }catch(Exception e){ e.printStackTrace(); }finally{ JDBCUtils.release(rs, pstmt, conn); } return flag; } 之前进行JDBC的操作的时候,都是一条SQL语句执行。现在如果使用批处理,可以将一批SQL一起执行。 @Test /** * 批处理基本操作 */ public void demo1(){ Connection conn = null; Statement stmt = null; try{ // 获得连接: conn = JDBCUtils.getConnection(); // 创建执行批处理对象: stmt = conn.createStatement(); // 编写一批SQL语句: String sql1 = "createdatabase test1"; String sql2 = "usetest1"; String sql3 = "createtable user(id int primary key auto_increment,name varchar(20))"; String sql4 = "insertinto user values (null,'aaa')"; String sql5 = "insertinto user values (null,'bbb')"; String sql6 = "insertinto user values (null,'ccc')"; String sql7 = "updateuser set name = 'mmm' where id = 2"; String sql8 = "deletefrom user where id = 1"; // 添加到批处理 stmt.addBatch(sql1); stmt.addBatch(sql2); stmt.addBatch(sql3); stmt.addBatch(sql4); stmt.addBatch(sql5); stmt.addBatch(sql6); stmt.addBatch(sql7); stmt.addBatch(sql8); // 执行批处理: stmt.executeBatch(); }catch(Exception e){ e.printStackTrace(); }finally{ JDBCUtils.release(stmt, conn); } } @Test /** * 批量插入记录: * * 默认情况下MySQL批处理没有开启的,需要在url后面拼接一个参数即可。 */ public void demo2(){ // 记录开始时间: long begin = System.currentTimeMillis(); Connection conn = null; PreparedStatement pstmt = null; try{ // 获得连接: conn = JDBCUtils.getConnection(); // 编写SQL语句: String sql = "insertinto user values (null,?)"; // 预编译SQL: pstmt = conn.prepareStatement(sql); for(int i=1;i<=10000;i++){ pstmt.setString(1, "name"+i); // 添加到批处理 pstmt.addBatch(); // 注意问题: // 执行批处理 if(i % 1000 == 0){ // 执行批处理: pstmt.executeBatch(); // 清空批处理: pstmt.clearBatch(); } } }catch(Exception e){ e.printStackTrace(); }finally{ JDBCUtils.release(pstmt, conn); } long end = System.currentTimeMillis(); System.out.println((end-begin)); } file:///C:/Users/lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg file:///C:/Users/lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg /** * 获得元素的内容:查询的操作. */ publicvoid demo1() throws Exception{ // 创建解析器 SAXReaderreader = new SAXReader(); // 解析XML的文档 Documentdocument = reader.read("xml/demo1.xml"); // 获得跟节点 Elementroot = document.getRootElement(); System.out.println(root.getName()); // 查找跟节点下的子节点. element() elements(); ElementpElement = root.element("person"); // 查找的是第一个person元素 //root.elements("person").get(1); // 查找的是第二个person元素 ElementnElement = pElement.element("name"); ElementaElement = pElement.element("age"); ElementsElement = pElement.element("sex"); System.out.println(nElement.getText()); System.out.println(aElement.getText()); System.out.println(sElement.getText()); } Ø XPath: * dom4j支持XPath的jar包. * jaxen-1.1-beta-6.jar * dom4j的XPath支持的API: * Listdocument.selectNodes(String xPath); * Nodedocument.selectSingleNode(String xPath); * 代码: @Test /** * DOM4J的XPath的写法: */ publicvoid demo2() throws Exception{ // 创建解析器: SAXReaderreader = new SAXReader(); // 解析XML返回Document对象. Documentdocument = reader.read("xml/demo1.xml"); /*List<Node>list = document.selectNodes("//name"); for(Node node : list) { Elementelement = (Element) node; System.out.println(element.getText()); }*/ List<Node>list = document.selectNodes("//person['@id']"); for(Node node : list) { Elementelement = (Element) node; System.out.println(element.attributeValue("id")); } } 名称空间:一个XML只能引入一个DTD约束文档.使用了Schema约束XML文档,一个XML可以引入多个Schame的约束!!! 如果再多个Schema文档中定义了相同的属性名称 该怎么办? * 名称空间类似于java中的package.通过名称空间区分 标签或属性来自于哪个文档的!!!通常名称空间唯一的不重复的即可.一般情况下使用一个URL地址表示一个名称空间. xmlns :xml name sapace .代表当前的文档应用的名称空间. targetNameSpace :目标名称空间. elementFormDefault : --> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itheima.com/ee25" elementFormDefault="qualified"> <!-- 复杂标签 --> <elementname="persons"> <!--复杂类型 --> <complexType> <sequencemaxOccurs="unbounded" minOccurs="1"> <elementname="person"> <complexType> <sequence> <!--简单标签 --> <elementname="name" type="string"></element> <elementname="age" type="int"></element> <elementname="sex" type="string"></element> </sequence> <attributename="id" type="string" use="required"/> </complexType> </element> </sequence> </complexType> </element> </schema>
|