初学JDBC的一些总结(二)
一、简单介绍PreparedStatement 和Statement的区别:
PreparedStatement是用来执行SQL查询语句的API之一,Java提供了 Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句。
- Statement 用于通用查询
- PreparedStatement 用于执行参数化查询
- CallableStatement则是用于存储过程。
通过调用connection.preparedStatement(sql)方法可以获得PreparedStatment对象。数据库系统会对sql语句进行预编译处理(如果JDBC驱动支持的话),预处理语句将被预先编译好,这条预编译的sql查询语句能在将来的查询中重用,这样一来,它比Statement对象生成的查询速度更快。
PreparedStatement提供了诸多好处,企业级应用开发中强烈推荐使用PreparedStatement来做SQL查询,下面列出PreparedStatement的几点优势。
1、PreparedStatement可以写动态参数化的查询
2、PreparedStatement比 Statement 更快:使用 PreparedStatement 最重要的一点好处是它拥有更佳的性能优势,SQL语句会预编译在数据库系统中。执行计划同样会被缓存起来,它允许数据库做参数化查询。使用预处理语句比普通的查询更快,因为它做的工作更少(数据库对SQL语句的分析,编译,优化已经在第一次查询前完成了)。为了减少数据库的负载,生产环境中德JDBC代码你应该总是使用PreparedStatement 。值得注意的一点是:为了获得性能上的优势,应该使用参数化sql查询而不是字符串追加的方式。
3、PreparedStatement可以防止SQL注入式攻击:在使用参数化查询的情况下,数据库系统(eg:MySQL)不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,因此就算参数中含有破坏性的指令,也不会被数据库所运行。
二、关于PreparedStatement接口,需要重点记住的是:
- PreparedStatement查询默认返回FORWARD_ONLY的ResultSet,你只能往一个方向移动结果集的游标。当然你还可以设定为其他类型的值如:”CONCUR_READ_ONLY”。
- 不支持预编译SQL查询的JDBC驱动,在调用connection.prepareStatement(sql)的时候,它不会把SQL查询语句发送给数据库做预处理,而是等到执行查询动作的时候(调用executeQuery()方法时)才把查询语句发送个数据库,这种情况和使用Statement是一样的。
- 占位符的索引位置从1开始而不是0,如果填入0会导致*java.sql.SQLException invalid column index*异常。所以如果PreparedStatement有两个占位符,那么第一个参数的索引时1,第二个参数的索引是2.
三、使用 PreparedStatement 接口实现增,删,改操作
1、添加图书信息
1 package com.java1234.jdbc.chap04.sec02; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 6 import com.java1234.jdbc.model.Book; 7 import com.java1234.jdbc.util.DbUtil; 8 9 public class Demo1 { 10 11 private static DbUtil dbUtil=new DbUtil(); 12 13 /** 14 * 添加图书 15 * @param book 16 * @return 17 * @throws Exception 18 */ 19 private static int addBook(Book book)throws Exception{ 20 Connection con=dbUtil.getCon(); // 获取连接 21 String sql="insert into t_book values(null,?,?,?,?)"; 22 PreparedStatement pstmt=con.prepareStatement(sql); 23 pstmt.setString(1, book.getBookName()); // 给第一个坑设置值 24 pstmt.setFloat(2, book.getPrice()); // 给第二个坑设置值 25 pstmt.setString(3, book.getAuthor()); // 给第三个坑设置值 26 pstmt.setInt(4, book.getBookTypeId()); // 给第四个坑设置值 27 int result=pstmt.executeUpdate(); 28 dbUtil.close(pstmt, con); 29 return result; 30 } 31 32 public static void main(String[] args) throws Exception{ 33 Book book=new Book("Java叉叉2", 1, "叉叉", 1); 34 int result=addBook(book); 35 if(result==1){ 36 System.out.println("添加成功!"); 37 }else{ 38 System.out.println("添加失败!"); 39 } 40 } 41 }
2、更新图书信息
1 package com.java1234.jdbc.chap04.sec03; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 6 import com.java1234.jdbc.model.Book; 7 import com.java1234.jdbc.util.DbUtil; 8 9 public class Demo1 { 10 11 private static DbUtil dbUtil=new DbUtil(); 12 13 /** 14 * 更新图书 15 * @param book 16 * @return 17 * @throws Exception 18 */ 19 private static int updateBook(Book book)throws Exception{ 20 Connection con=dbUtil.getCon(); 21 String sql="update t_book set bookName=?,price=?,author=?,bookTypeId=? where id=?"; 22 PreparedStatement pstmt=con.prepareStatement(sql); 23 pstmt.setString(1, book.getBookName()); 24 pstmt.setFloat(2, book.getPrice()); 25 pstmt.setString(3, book.getAuthor()); 26 pstmt.setInt(4, book.getBookTypeId()); 27 pstmt.setInt(5, book.getId()); 28 int result=pstmt.executeUpdate(); 29 dbUtil.close(pstmt, con); 30 return result; 31 } 32 33 public static void main(String[] args) throws Exception{ 34 Book book=new Book(12,"K2", 2, "K", 2); 35 int result=updateBook(book); 36 if(result==1){ 37 System.out.println("更新成功!"); 38 }else{ 39 System.out.println("更新失败!"); 40 } 41 } 42 }
3、删除图书信息
1 package com.java1234.jdbc.chap04.sec04; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 6 import com.java1234.jdbc.util.DbUtil; 7 8 public class Demo1 { 9 10 private static DbUtil dbUtil=new DbUtil(); 11 12 /** 13 * 删除图书 14 * @param id 15 * @return 16 * @throws Exception 17 */ 18 private static int deleteBook(int id)throws Exception{ 19 Connection con=dbUtil.getCon(); 20 String sql="delete from t_book where id=?"; 21 PreparedStatement pstmt=con.prepareStatement(sql); 22 pstmt.setInt(1, id); 23 int result=pstmt.executeUpdate(); 24 dbUtil.close(pstmt, con); 25 return result; 26 } 27 28 public static void main(String[] args)throws Exception { 29 int result=deleteBook(12); 30 if(result==1){ 31 System.out.println("删除成功!"); 32 }else{ 33 System.out.println("删除失败!"); 34 } 35 } 36 }
总结:使用PreparedStatement对象来执行SQL语句的查询,我们在写SQL语句的时候需要注意使用占位符表示待查寻信息字段信息必须要区分英文和中文占位符的区别。
PreparedStatement对象的一些主要方法:
executeQuery():在此
PreparedStatement
对象中执行 SQL 查询,并返回该查询生成的ResultSet
对象。executeUpdate()
: 在此PreparedStatement
对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言(Data Manipulation Language,DML)语句,比如INSERT
、UPDATE
或DELETE
语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。getMetaData()
:获取包含有关ResultSet
对象列信息的ResultSetMetaData
对象,ResultSet
对象将在执行此PreparedStatement
对象时返回。setAsciiStream(int parameterIndex, InputStream x,long length)
:将指定参数设置为给定输入流。(主要用于处理CLOB)setBinaryStream(int parameterIndex, InputStream x, long length)
:将指定参数设置为给定输入流,该输入流将具有指定字节数。(主要用于处理BLOB)setXxx(int parameterIndex, Xxx x)
:将指定参数设置为给定 Javaxxx(java基本数据类型)
值。
四、使用结果集ResultSet返回一个二维表的信息:
当我们查询数据库时,返回的是一个二维的结果集,我们这时候需要使用 ResultSet 来遍历结果集,获取每一行的数据。
boolean next(): 将光标从当前位置向前移一行。开始时候的光标在第一行的前边,并不指向第一行。
String getString(int columnIndex) 以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指定列的值。
String getString(String columnLabel) 以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指定列的值
1 package com.java1234.jdbc.chap05.sec02; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.util.ArrayList; 7 import java.util.List; 8 9 import com.java1234.jdbc.model.Book; 10 import com.java1234.jdbc.util.DbUtil; 11 12 public class Demo1 { 13 14 private static DbUtil dbUtil = new DbUtil(); 15 16 /** 17 * 遍历查询结果,这里是按照列的编号进行输出的。 18 * @throws Exception 19 */ 20 private static void listBook() throws Exception { 21 Connection con = dbUtil.getCon(); // 获取连接 22 String sql = "select * from t_book"; 23 PreparedStatement pstmt = con.prepareStatement(sql); 24 ResultSet rs = pstmt.executeQuery(); // 返回结果集ResultSet 25 while (rs.next()) { 26 int id = rs.getInt(1); // 获取第一个列的值 编号id 27 String bookName = rs.getString(2); // 获取第二个列的值 图书名称 bookName 28 float price = rs.getFloat(3); // 获取第三列的值 图书价格 price 29 String author = rs.getString(4); // 获取第四列的值 图书作者 author 30 int bookTypeId = rs.getInt(5); // 获取第五列的值 图书类别id 31 System.out.println("图书编号:" + id + " 图书名称:" + bookName + " 图书价格:" 32 + price + " 图书作者:" + author + " 图书类别id:" + bookTypeId); 33 System.out 34 .println("======================================================================="); 35 36 } 37 } 38 39 /** 40 * 遍历查询结果,这里是按照列的数据类型进行输出的 41 * @throws Exception 42 */ 43 private static void listBook2() throws Exception { 44 Connection con = dbUtil.getCon(); // 获取连接 45 String sql = "select * from t_book"; 46 PreparedStatement pstmt = con.prepareStatement(sql); 47 ResultSet rs = pstmt.executeQuery(); // 返回结果集ResultSet 48 while (rs.next()) { 49 int id = rs.getInt("id"); // 获取第一个列的值 编号id 50 String bookName = rs.getString("bookName"); // 获取第二个列的值 图书名称 bookName 51 float price = rs.getFloat("price"); // 获取第三列的值 图书价格 price 52 String author = rs.getString("author"); // 获取第四列的值 图书作者 author 53 int bookTypeId = rs.getInt("bookTypeId"); // 获取第五列的值 图书类别id 54 System.out.println("图书编号:" + id + " 图书名称:" + bookName + " 图书价格:" 55 + price + " 图书作者:" + author + " 图书类别id:" + bookTypeId); 56 System.out 57 .println("======================================================================="); 58 59 } 60 } 61 //这里为了体现面向对象的思想,把每次查询到的信息都封装成一个Book对象,并装进ArrayList链表中 62 private static List<Book> listBook3()throws Exception{ 63 List<Book> bookList=new ArrayList<Book>(); 64 Connection con = dbUtil.getCon(); // 获取连接 65 String sql = "select * from t_book"; 66 PreparedStatement pstmt = con.prepareStatement(sql); 67 ResultSet rs = pstmt.executeQuery(); // 返回结果集ResultSet 68 while (rs.next()) { 69 int id = rs.getInt("id"); // 获取第一个列的值 编号id 70 String bookName = rs.getString("bookName"); // 获取第二个列的值 图书名称 bookName 71 float price = rs.getFloat("price"); // 获取第三列的值 图书价格 price 72 String author = rs.getString("author"); // 获取第四列的值 图书作者 author 73 int bookTypeId = rs.getInt("bookTypeId"); // 获取第五列的值 图书类别id 74 Book book=new Book(id, bookName, price, author, bookTypeId); 75 bookList.add(book); 76 } 77 return bookList; 78 } 79 80 public static void main(String[] args) throws Exception { 81 // listBook(); 82 // listBook2(); 83 List<Book> bookList=listBook3(); 84 for (Book book : bookList) { 85 System.out.println(book); 86 } 87 } 88 }
五、利用JDBC进行大数据的处理:
大数据对象处理主要有 CLOB(character large object)和 BLOB(binary large object)两种类型的字段;在 CLOB中可以存储大字符数据对象,比如长篇小说;在 BLOB 中可以存放二进制大数据对象,比如图片,电影,音乐。
1、处理 CLOB 数据
1 package com.java1234.jdbc.chap06.sec01; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.InputStream; 6 import java.sql.Clob; 7 import java.sql.Connection; 8 import java.sql.PreparedStatement; 9 import java.sql.ResultSet; 10 11 import com.java1234.jdbc.model.Book; 12 import com.java1234.jdbc.util.DbUtil; 13 14 public class Demo1 { 15 16 private static DbUtil dbUtil=new DbUtil(); 17 18 /** 19 * 添加图书 20 * @param book 21 * @return 22 * @throws Exception 23 */ 24 private static int addBook(Book book)throws Exception{ 25 Connection con=dbUtil.getCon(); // 获取连接 26 String sql="insert into t_book values(null,?,?,?,?,?)"; 27 PreparedStatement pstmt=con.prepareStatement(sql); 28 pstmt.setString(1, book.getBookName()); // 给第一个坑设置值 29 pstmt.setFloat(2, book.getPrice()); // 给第二个坑设置值 30 pstmt.setString(3, book.getAuthor()); // 给第三个坑设置值 31 pstmt.setInt(4, book.getBookTypeId()); // 给第四个坑设置值 32 File context=book.getContext(); // 获取文件 33 InputStream inputStream=new FileInputStream(context); 34 pstmt.setAsciiStream(5, inputStream,context.length()); // 给第五个坑设置值 35 int result=pstmt.executeUpdate(); 36 dbUtil.close(pstmt, con); 37 return result; 38 } 39 /** 40 * 按照编号获取图书信息 41 * @param book 42 * @return 43 * @throws Exception 44 */ 45 public static void getBook(int id)throws Exception{ 46 Connection con=dbUtil.getCon(); 47 String sql="select * from t_book where id=?"; 48 PreparedStatement pstmt=con.prepareStatement(sql); 49 pstmt.setInt(1, id); 50 ResultSet rs=pstmt.executeQuery(); 51 if(rs.next()){ 52 //getString(参数名称):参数名称都是数据库中设置的每一列的表格名称 53 String bookName=rs.getString("bookName"); 54 float price=rs.getFloat("price"); 55 String author=rs.getString("author"); 56 int bookTypeId=rs.getInt("bookTypeId"); 57 Clob c=rs.getClob("context"); 58 String context=c.getSubString(1, (int)c.length()); 59 System.out.println("图书名称:"+bookName); 60 System.out.println("图书价格:"+price); 61 System.out.println("图书作者:"+author); 62 System.out.println("图书类型ID:"+bookTypeId); 63 System.out.println("图书内容:"+context); 64 } 65 dbUtil.close(pstmt, con); 66 } 67 68 public static void main(String[] args)throws Exception { 69 /*File context=new File("c:/helloWorld.txt"); 70 Book book=new Book("helloWorld", 100, "小锋", 1,context); 71 int result=addBook(book); 72 if(result==1){ 73 System.out.println("添加成功!"); 74 }else{ 75 System.out.println("添加失败!"); 76 }*/ 77 getBook(16); 78 } 79 }
2、处理BLOB数据
1 package com.java1234.jdbc.chap06.sec02; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileOutputStream; 6 import java.io.InputStream; 7 import java.sql.Blob; 8 import java.sql.Clob; 9 import java.sql.Connection; 10 import java.sql.PreparedStatement; 11 import java.sql.ResultSet; 12 13 import com.java1234.jdbc.model.Book; 14 import com.java1234.jdbc.util.DbUtil; 15 16 public class Demo1 { 17 18 private static DbUtil dbUtil=new DbUtil(); 19 20 /** 21 * 添加图书(还包括给每一本书添加一个插图) 22 * @param book 23 * @return 24 * @throws Exception 25 */ 26 private static int addBook(Book book)throws Exception{ 27 Connection con=dbUtil.getCon(); // 获取连接 28 String sql="insert into t_book values(null,?,?,?,?,?,?)"; 29 PreparedStatement pstmt=con.prepareStatement(sql); 30 pstmt.setString(1, book.getBookName()); // 给第一个坑设置值 31 pstmt.setFloat(2, book.getPrice()); // 给第二个坑设置值 32 pstmt.setString(3, book.getAuthor()); // 给第三个坑设置值 33 pstmt.setInt(4, book.getBookTypeId()); // 给第四个坑设置值 34 File context=book.getContext(); // 获取文件 35 InputStream inputStream=new FileInputStream(context); 36 pstmt.setAsciiStream(5, inputStream,context.length()); // 给第五个坑设置值 37 38 File pic=book.getPic(); // 获取图片文件 39 InputStream inputStream2=new FileInputStream(pic); 40 pstmt.setBinaryStream(6, inputStream2, pic.length()); // 给第六个坑设置值 41 int result=pstmt.executeUpdate(); 42 dbUtil.close(pstmt, con); 43 return result; 44 } 45 46 47 /** 48 * 按照编号获取图书信息(还包括每本书的插图也放到一个指定的文件中) 49 * @param book 50 * @return 51 * @throws Exception 52 */ 53 public static void getBook(int id)throws Exception{ 54 Connection con=dbUtil.getCon(); 55 String sql="select * from t_book where id=?"; 56 PreparedStatement pstmt=con.prepareStatement(sql); 57 pstmt.setInt(1, id); 58 ResultSet rs=pstmt.executeQuery(); 59 if(rs.next()){ 60 String bookName=rs.getString("bookName"); 61 float price=rs.getFloat("price"); 62 String author=rs.getString("author"); 63 int bookTypeId=rs.getInt("bookTypeId"); 64 65 //获取文本文件 66 Clob c=rs.getClob("context"); 67 String context=c.getSubString(1, (int)c.length()); 68 69 //获取图片 70 Blob b=rs.getBlob("pic"); 71 //图片不能直接输出到控制台,所以只能把图片放到一个指定的位置 72 FileOutputStream out=new FileOutputStream(new File("d:/pic2.jpg")); 73 out.write(b.getBytes(1, (int)b.length())); 74 out.close(); 75 System.out.println("图书名称:"+bookName); 76 System.out.println("图书价格:"+price); 77 System.out.println("图书作者:"+author); 78 System.out.println("图书类型ID:"+bookTypeId); 79 System.out.println("图书内容:"+context); 80 } 81 dbUtil.close(pstmt, con); 82 } 83 84 85 86 public static void main(String[] args)throws Exception { 87 //这是为了测试图书信息添加 88 /*File context=new File("c:/helloWorld.txt"); 89 File pic=new File("c:/pic1.jpg"); 90 Book book=new Book("helloWorld", 100, "小锋", 1,context,pic); 91 int result=addBook(book); 92 if(result==1){ 93 System.out.println("添加成功!"); 94 }else{ 95 System.out.println("添加失败!"); 96 }*/ 97 //这是为了测试按照图书标号查找图书 98 getBook(18); 99 } 100 }
备注:这里所有的代码都是基于一个Book图书的模型进行的。
What You Want,Time Will Give You!!!