4天貫通JDBC技術
三、Statement與ResultSet
- 通過呼叫 Connection 物件的 createStatement 方法建立該物件
- Statement st = conn.createStatement();
- 該物件用於執行靜態的 SQL 語句,並且返回執行結果
- 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
}
本教程由尚矽谷教育大資料研究院出品,如需轉載請註明來源。