1. 程式人生 > >4天貫通JDBC技術

4天貫通JDBC技術

三、Statement與ResultSet

  1. 通過呼叫 Connection 物件的 createStatement 方法建立該物件
    • Statement st = conn.createStatement();
  2. 該物件用於執行靜態的 SQL 語句,並且返回執行結果
  3. Statement 介面中定義了下列方法用於執行 SQL 語句:
    • ResultSet excuteQuery(String sql)
    • int excuteUpdate(String sql)

//通用的INSSERT  UPDATE  DELETE方法(version 1.0)

public void update(String sql){

//1.獲取資料庫的連線

Connection conn = null;

Statement st = null;

try{

conn = JDBCUtils.getConnection();

//2.提供一個Statement物件,將sql傳遞給資料庫中執行

st = conn.createStatement();

st.execute(sql);

}catch(Exception e){

e.printStackTrace();

}finally{

//3.關閉Statement物件及連線

JDBCUtils.close(null, st, conn);

}

}

// 通用的查詢方法,返回一個物件(version 1.0)

public <T> T get(String sql, Class<T> clazz) {

Connection conn = null;

Statement st = null;

ResultSet rs = null;

T t = null;

try {

t = clazz.newInstance();

conn = JDBCUtils.getConnection();

st = conn.createStatement();

rs = st.executeQuery(sql);

/*

* 通過ResultSet呼叫getMetaData()返回一個結果集的元資料:ResultSetMetaData

*

* 1.getColumnCount():返回結果集的列數

* 2.getColumnLabel():返回列的別名

*/

ResultSetMetaData rsmd = rs.getMetaData();

int columnCount = rsmd.getColumnCount();

if (rs.next()) {

for (int i = 0; i < columnCount; i++) {

Object columnVal = rs.getObject(i + 1);// 相應列的值

//String columnName = rsmd.getColumnName(i + 1);

String columnName = rsmd.getColumnLabel(i + 1);

//使用PropertyUtils將指定物件t的指定屬性columnName設定為指定的值columnVal

PropertyUtils.setProperty(t, columnName, columnVal);

}

}

} catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.close(rs, st, conn);

}

return t;

}

//通用的返回多個物件的查詢操作(version 1.0)

public <T> List<T> getInstances(String sql,Class<T> clazz){

Connection conn = null;

Statement st = null;

ResultSet rs = null;

List<T> list = new ArrayList<T>();

try {

conn = JDBCUtils.getConnection();

st = conn.createStatement();

rs = st.executeQuery(sql);

/*

* 通過ResultSet呼叫getMetaData()返回一個結果集的元資料:ResultSetMetaData

*

* 1.getColumnCount():返回結果集的列數

* 2.getColumnLabel():返回列的別名

*/

ResultSetMetaData rsmd = rs.getMetaData();

int columnCount = rsmd.getColumnCount();

while (rs.next()) {

T t = clazz.newInstance();

for (int i = 0; i < columnCount; i++) {

Object columnVal = rs.getObject(i + 1);// 相應列的值

//String columnName = rsmd.getColumnName(i + 1);

String columnName = rsmd.getColumnLabel(i + 1);

//使用PropertyUtils將指定物件t的指定屬性columnName設定為指定的值columnVal

PropertyUtils.setProperty(t, columnName, columnVal);

}

list.add(t);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.close(rs, st, conn);

}

return list;

}

流程:

//總結:

兩種思想:

  • 面向介面程式設計的思想;
  • ORM思想:

* ORM:Object Relational Mapping

* 資料庫中的表與java中的一個類對應(如:customers表與Customer類對應)

* 資料庫中表的一個列與java類的一個屬性對應(如:表中的id列與Customer類的id屬性對應)

* 資料庫中表的一行(一條資料)與java類的一個物件對應

兩個技術:

  • 結果集的元資料:ResultSetMetaData;
  • PropertyUtils

1.結果集的元資料:ResultSetMetaData

//獲取:ResultSet.getMetaData();

//兩個方法:1)getColumnCount():獲取結果集中有多少列

            2)getColumnLabel():獲取結果集的相應列的列名,相當於是對應的表的列的別名。

--getColumnName():不用。

public void testResultSetMetaData(){

Connection conn = null;

Statement st = null;

ResultSet rs = null;

String sql = "select order_id id,order_name name,order_date date from `order`";

try{

conn = JDBCUtils.getConnection();

st = conn.createStatement();

rs = st.executeQuery(sql);

ResultSetMetaData rsmd = rs.getMetaData();

int columnCount = rsmd.getColumnCount();

System.out.println(columnCount);

while(rs.next()){

for(int i = 0;i < columnCount;i++){

System.out.print(rsmd.getColumnName(i + 1) + " ");

System.out.print(rsmd.getColumnLabel(i + 1) + " ");

System.out.println(rs.getObject(i + 1));

}

System.out.println();

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.close(rs, st, conn);

}

}

2.PropertyUtils工具類,使用它的setProperty(Object obj,String FieldName,Object FieldValue)

public void testPropertyUtils() throws Exception{

Order order = new Order();

System.out.println(order);

PropertyUtils.setProperty(order, "id", 1001);

PropertyUtils.setProperty(order, "name", "AA");

PropertyUtils.setProperty(order, "date", new Date(new java.util.Date().getTime()));

System.out.println(order);

}

四、PreparedStatement

PreparedStatement是Statement的子介面

①需要預編譯SQL語句:PreparedStatement ps = conn.preparedStatement(sql);

②填充佔位符:setObject(int index);//index從1開始

③execute()  /  executeUpdate()  ;   executeQuery(); 返回一個ResultSet

1.替換原來的Statement,實現增刪改和查的操作

     -->Statement的問題:①拼串  不方便,容易出錯 ②存在sql注入的問題,可以對資料庫進行惡意攻擊。

// 實現一個通用的UPDATE INSERT DELETE的操作的方法(version 2.0)

public void update(String sql, Object... args) {

Connection conn = null;

PreparedStatement ps = null;

try {

// 1.獲取連線

conn = JDBCUtils.getConnection();

// 2.返回PreparedSt物件,預編譯sql語句

ps = conn.prepareStatement(sql);

// 3.填充佔位符

for (int i = 0; i < args.length; i++) {

ps.setObject(i + 1, args[i]);

}

ps.execute();

} catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.close(null, ps, conn);

}

}

// 實現一個通用的查詢操作,返回一個物件(version 2.0)

public <T> T getInstance(String sql, Class<T> clazz, Object... args) {

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

try {

// 1.獲取連線

conn = JDBCUtils.getConnection();

// 2.預編譯sql語句,返回PreparedStatement物件

ps = conn.prepareStatement(sql);

// 3.填充佔位符

for (int i = 0; i < args.length; i++) {

ps.setObject(i + 1, args[i]);

}

// 4.執行並返回ResultSet的物件

rs = ps.executeQuery();

if (rs.next()) {

// 5.建立T的物件

T t = clazz.newInstance();

// 6.將結果集中的列值作為T的物件的屬性,給予賦值

ResultSetMetaData rsmd = rs.getMetaData();

int columnCount = rsmd.getColumnCount();

for (int i = 0; i < columnCount; i++) {

Object columnVal = rs.getObject(i + 1);

String columnLabel = rsmd.getColumnLabel(i + 1);

PropertyUtils.setProperty(t, columnLabel, columnVal);

}

return t;

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 7.關閉相應的操作

JDBCUtils.close(rs, ps, conn);

}

return null;

}

// 實現一個通用的查詢操作,返回一個物件的集合(version 2.0)

public <T> List<T> getForList(String sql,Class<T> clazz,Object ... args){

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

List<T> list = new ArrayList<T>();

try{

conn = JDBCUtils.getConnection();

ps = conn.prepareStatement(sql);

for(int i = 0;i < args.length;i++){

ps.setObject(i + 1, args[i]);

}

rs = ps.executeQuery();

ResultSetMetaData rsmd = rs.getMetaData();

int columnCount = rsmd.getColumnCount();

while(rs.next()){

T t = clazz.newInstance();

for(int i = 0;i < columnCount;i++){

Object columnVal = rs.getObject(i + 1);

String columnLabel = rsmd.getColumnLabel(i + 1);

PropertyUtils.setProperty(t, columnLabel, columnVal);

}

list.add(t);

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.close(rs, ps, conn);

}

return list;

}

//2.使用PreparedStatement的其他優點

1.實現大資料型別的資料的插入、修改、查詢的操作.

setBlob()   getBlob();

// 從資料表中將大資料型別的資料取出

@Test

public void testBlob3(){

Connection conn = null;

PreparedStatement ps = null;

String sql = "select id,name,email,birth,photo from customers where id = ?";

ResultSet rs = null;

InputStream is = null;

FileOutputStream fos = null;

try{

conn = JDBCUtils.getConnection();

ps = conn.prepareStatement(sql);

fos = new FileOutputStream("ym1.jpg");

ps.setInt(1, 21);

rs = ps.executeQuery();

if(rs.next()){

int id = rs.getInt("id");

String name = rs.getString("name");

Date birth = rs.getDate("birth");

String email = rs.getString("email");

Customer cust = new Customer(id,name,email,birth);

System.out.println(cust);

}

Blob photo = rs.getBlob(5);

is = photo.getBinaryStream();

byte[] b = new byte[1024];

int len;

while((len = is.read(b)) != -1){

fos.write(b, 0, len);

}

}catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.close(rs, ps, conn);

if(fos != null){

try {

fos.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(is != null){

try {

is.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

// 向資料表中修改現有的大資料型別的資料

@Test

public void testBlob2() {

Connection conn = null;

PreparedStatement ps = null;

String sql = "update customers set photo = ? where id = ?";

try {

conn = JDBCUtils.getConnection();

ps = conn.prepareStatement(sql);

ps.setBlob(1, new FileInputStream("ym.jpg"));

ps.setInt(2, 21);

ps.execute();

} catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.close(null, ps, conn);

}

}

// 向資料庫的表中寫入大資料型別的資料

@Test

public void testBlob1() {

Connection conn = null;

PreparedStatement ps = null;

String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";

try {

conn = JDBCUtils.getConnection();

ps = conn.prepareStatement(sql);

ps.setString(1, "楊冪1");

ps.setString(2, "[email protected]");

ps.setDate(3, new Date(new java.util.Date().getTime()));

ps.setBlob(4, new FileInputStream("1.jpg"));

ps.execute();

} catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.close(null, ps, conn);

}

}

2.使用PreparedStatement進行批量操作時,效率優於Statement.

//批量操作,主要指的是批量插入。

//oracle是支援批量插入的。

//如何實現最優?  ①使用PreparedStatement  ②addBatch()  executeBatch()  clearBatch()

public void test4() {

Connection conn = null;

PreparedStatement ps = null;

long start = System.currentTimeMillis();

String sql = "insert into dept values(?,?)";

try {

conn = JDBCUtils.getConnection();

ps = conn.prepareStatement(sql);

for (int i = 0; i < 100000; i++) {

ps.setInt(1, i + 1);

ps.setString(2, "dept_" + (i + 1) + "_name");

//1.“攢”SQL

ps.addBatch();

if( (i + 1) % 250 == 0){

//2.執行sql

ps.executeBatch();

//3.清空sql

ps.clearBatch();

}

}

} catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.close(null, ps, conn);

}

long end = System.currentTimeMillis();

System.out.println("花費時間:" + (end - start));//2427

}

本教程由尚矽谷教育大資料研究院出品,如需轉載請註明來源。