好了,換了個新屏幕,原來的電腦屏幕,過年的時候擦玻璃,玻璃掉下來給砸的裂開了(玻璃1點事情都沒有),新屏幕感覺就是爽,也不枉我花了280大洋買的LG的完善屏。戰役力立馬感覺飆升20%。閑話就不多說了,繼續進化JDBC。
將JDBC的連接完成后,我們要做甚么呢?增刪改查唄!
好,那就先來1個原始的起源,然后我們逐步進化。
獲得連接對象后,我們是這樣想的,我們要將我們的sql語句通過這個連接發送到數據庫,然后讓數據庫將結果返回給我們。
通過查看API,發現了Connection接口中createStatement() 這個方法,具體的作用呢,“Creates a Statement object for sending SQL statements to the database.”創建1個Statement對象能發送SQL命令到數據庫中,這個方法返回1個Statement對象。好了,可以將sql statement發送到數據庫中了,我們想的的履行,然后就結果返回給我們。繼續查看API, Statement接口中execute(String sql) ,executeQuery(String sql) ,executeUpdate(String sql) 有這么3個方法參數都是String 的sql。好了就要它了。先來試試第1個execute(String sql)
@Test
public void testJdbcInsert() throws Exception{
Connection conn = JDBCUtils.getConnection();
Statement statm = conn.createStatement();
String sql = "insert into customers values(21, 'yushen1', 'yushem@123.com', '1998⑶⑵', null)";
boolean b = statm.execute(sql);
System.out.println(b);
statm.close();
conn.close();
}
我將異常拋出去了,固然這里不是很公道,但是這都是不重點。重點是履行成功了(通過查看數據庫發現的確插入了),但是這里的返回值是false,咦,不公道啊,明明成功了,怎樣會是false?查看API,別的不看,我們直接看它的返回值,“true if the first result is a ResultSet object; false if it is an update count or there are no results ”,原來如此,如果是結果是1個ResultSet對象它就返回true,如果是沒有結果集或是1個count,返回false。聯系學過的sql,我們知道select查詢后的結果是1張數據表,而別的DML操作后,僅僅是對表進行了修改,得到的是1個類似這樣的結果“1 row(s) affected”。而這時候候問題就來了,我們怎樣知道得到的1個結果集還是1個count,這樣就不利于后續的操作了。進化吧!
原始的問題我們已明白了,我們的解決辦法就是將修改(增刪改)操作和查詢操作分開,看看上面的3個方法,秒懂了,是否是。先來處理簡單的,修改,由于它的返回值是1個受影響的行數,我們通過判斷這個行數是不是為0,就可以判斷修改是不是履行成功。
// update
@Test
public void testJdbcUpdate(){
Connection conn = null;
Statement statm = null;
try {
conn = JDBCUtils.getConnection();
statm = conn.createStatement();
String sql = "update customers set name = 'woshiyushen' where id = 21";
int rows = statm.executeUpdate(sql);
if( rows > 0){
System.out.println("success!");
} else {
System.out.println("failed");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(statm, conn);
}
}
暫且我們將修改進化到這里,后續將其進化。將其封裝成1個方法,放到我的工具類中。
// statement : insert,update,delete
public static int update(String sql) {
Connection conn = null;
Statement statm = null;
int rows = 0;
try {
conn = getConnection();
statm = conn.createStatement();
rows = statm.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(statm, conn);
}
return rows;
}
先來查1個
@Test
public void testOrderSelect1() {
// get connection
Connection conn = null;
// create Statement object
Statement statm = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
statm = conn.createStatement();
// executeQuery, and return a ResultSet object
String sql = "select order_id, order_name, order_date from `order`";
rs = statm.executeQuery(sql);
// read the rs
while (rs.next()) {
int orderId = rs.getInt("order_id");
String orderName = rs.getString("order_name");
Date orderDate = rs.getDate("order_date");
// put the resultset to a class
Order order = new Order(orderId, orderName, orderDate);
System.out.println(order);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// close conn
JDBCUtils.close(rs, statm, conn);
}
}
我自己英語水平也不是很高,可能存在很多的語法問題,大家將就的看,我也會不斷的學習改進。這里直接將結果集的處理也寫出來了,這里又觸及到1個思想:ORM(Object Relational Mapping):對象關系映照,拿我自己的話來理解就是,1張表對應1個類,1列對應1個屬性,1行對應1個數據,仔細想一想,是否是這樣的,可能我們1開始想將讀出來的數據存到數組,集合中,但是用1個對象來存是否是更好1點?在說說ResultSet,API中是這樣說的,“A table of data representing a database result set”包括1個數據庫結果集的數據表,得到的是可以認為是1張表,它提供1個光標,通過next()方法,將光標下移,光標所指代表1行。然后我們從這1行中取出數據,存到對象中。
那末問題又來了,這里我們只能針對具體的某1張表,由于你不肯定它中列的個數,列的名稱。為了提供1種通用的,可移植性高的程序,進化吧!
我們想提供1種通用的解決辦法,就好比2.1JDBC的進化2―增刪改1中我們將其封裝成方法,只通過1些參數就可以就獲得對象。想要獲得這個對象,而我們不知道具體是哪一個對象,只能在運行時才能肯定具體獲得甚么對象……反射!反射!!!對!那我們來寫這個通用的查詢方法。
public <T> T get(String sql, Class<T> clazz) {
T t = null;
// 1.get the connection
Connection conn = null;
// 2.on the base of conn, create Statement object
Statement statm = null;
// 3.excute sql command, and get the ResultSet object
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
statm = conn.createStatement();
rs = statm.executeQuery(sql);
// get the ResultSetMetaData object
ResultSetMetaData rsmd = rs.getMetaData();
// 4.read the data from Result object, and write to a generic object
while (rs.next()) {
// 4.1through reflect get the T object t...
t = clazz.newInstance();
// 4.2 read the rs'data to t
// 4.21 get the columnCount througth the ResultSetMetaData
int columnCount = rsmd.getColumnCount();
// 4.22 get the every columnName and columnVal
for (int i = 1; i <= columnCount; i++) {
// 4.23 get the columnName
String columnName = rsmd.getColumnLabel(i);
// 4.24 get the columnVal from rs
Object cloumnVal = rs.getObject(columnName);
// 4.25 set the columnName and columnVal to t througth
// generic
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, cloumnVal);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 5.close the connection
JDBCUtils.close(rs, statm, conn);
}
// 6. return the t
return t;
}
這里需要兩個參數,sql就不用多提了,要說的是第2個參數 Class<T> clazz
我們需要通過反射來獲得具體類的實例,這里需要我們根據查詢的結果建立相應的實體類表,然后通過反射的方式,來為具體的為某個屬性賦值。
而得到列數,需要通過ResultSetMetaData才能獲得。
到這里的時候,你腦海里是否是會有這樣1個層次:
描寫類的類(通過反射獲得的Class)
描寫數據的數據(元數據,如ResultSetMetaData)
思惟發散1下:還有1個描寫注解的注解(元注解),固然這里沒有用到…
往下1個層次:
具體的類
具體的對象
具體的注解
這略微的進化1下。
既然我們說,可以通過屬性來為其設置值,我們那末我們也能夠同getXXX()和setXXX()為屬性賦值。而Apache為我們提供了這樣的類庫(commons-beanutils⑴.8.0.jar,commons-logging⑴.1.1.jar,我會隨后上傳,大家注意看我評論,進行下載使用)。
public <T> List<T> getAll(String sql, Class<T> clazz) {
List<T> list = new ArrayList<T>();
Connection conn = null;
Statement statm = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
statm = conn.createStatement();
rs = statm.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
while (rs.next()) {
T t = clazz.newInstance();
int cloumnCount = rsmd.getColumnCount();
for (int i = 1; i <= cloumnCount; i++) {
String cloumnName = rsmd.getColumnLabel(i);
Object cloumnVal = rs.getObject(cloumnName);
PropertyUtils.setProperty(t, cloumnName, cloumnVal);
}
list.add(t);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(rs, statm, conn);
}
return list;
}
這里是獲得多行,返回多個對象,用List來寄存。
做了兩個測試:
@Test
public void test1() {
String sql = "SELECT order_id orderId, order_name OrderName, order_date orderDate FROM `order` WHERE order_id > 1";
List<Order> orders = getAll(sql, Order.class);
for (Order order : orders) {
System.out.println(order);
}
}
@Test
public void test() {
String sql = "SELECT order_id orderId, order_name OrderName, order_date orderDate FROM `order` WHERE order_id = 1";
Order order = get(sql, Order.class);
System.out.println(order);
}
提示1下,別名的使用,數據庫和Java程序命名規范可能有所不同,所以為了保證對應的列名和屬性名相同,我們就要用到別名。(getColumnLabel() 優先返回別名)
另附1些練習:
1.創建數據庫表 examstudent,表結構以下:
2.向數據庫表中添加1些數據
3.插入1個新的 student 信息
請輸入考生的詳細信息
Type:
IDCard:
ExamCard:
StudentName:
Location:
Grade:
信息錄入成功!
4.根據輸入的身份證號和準考證號來查詢學生的基本信息
5.根據考生號刪除學生
ok,今天就進化到這里吧。明天繼續。LG的屏的確挺不錯的!
上一篇 VS2012添加單元測試