好了,換了個(gè)新屏幕,原來(lái)的電腦屏幕,過(guò)年的時(shí)候擦玻璃,玻璃掉下來(lái)給砸的裂開(kāi)了(玻璃1點(diǎn)事情都沒(méi)有),新屏幕感覺(jué)就是爽,也不枉我花了280大洋買的LG的完善屏。戰(zhàn)役力立馬感覺(jué)飆升20%。閑話就不多說(shuō)了,繼續(xù)進(jìn)化JDBC。
將JDBC的連接完成后,我們要做甚么呢?增刪改查唄!
好,那就先來(lái)1個(gè)原始的起源,然后我們逐步進(jìn)化。
獲得連接對(duì)象后,我們是這樣想的,我們要將我們的sql語(yǔ)句通過(guò)這個(gè)連接發(fā)送到數(shù)據(jù)庫(kù),然后讓數(shù)據(jù)庫(kù)將結(jié)果返回給我們。
通過(guò)查看API,發(fā)現(xiàn)了Connection接口中createStatement() 這個(gè)方法,具體的作用呢,“Creates a Statement object for sending SQL statements to the database.”創(chuàng)建1個(gè)Statement對(duì)象能發(fā)送SQL命令到數(shù)據(jù)庫(kù)中,這個(gè)方法返回1個(gè)Statement對(duì)象。好了,可以將sql statement發(fā)送到數(shù)據(jù)庫(kù)中了,我們想的的履行,然后就結(jié)果返回給我們。繼續(xù)查看API, Statement接口中execute(String sql) ,executeQuery(String sql) ,executeUpdate(String sql) 有這么3個(gè)方法參數(shù)都是String 的sql。好了就要它了。先來(lái)試試第1個(gè)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();
}
我將異常拋出去了,固然這里不是很公道,但是這都是不重點(diǎn)。重點(diǎn)是履行成功了(通過(guò)查看數(shù)據(jù)庫(kù)發(fā)現(xiàn)的確插入了),但是這里的返回值是false,咦,不公道啊,明明成功了,怎樣會(huì)是false?查看API,別的不看,我們直接看它的返回值,“true if the first result is a ResultSet object; false if it is an update count or there are no results ”,原來(lái)如此,如果是結(jié)果是1個(gè)ResultSet對(duì)象它就返回true,如果是沒(méi)有結(jié)果集或是1個(gè)count,返回false。聯(lián)系學(xué)過(guò)的sql,我們知道select查詢后的結(jié)果是1張數(shù)據(jù)表,而別的DML操作后,僅僅是對(duì)表進(jìn)行了修改,得到的是1個(gè)類似這樣的結(jié)果“1 row(s) affected”。而這時(shí)候候問(wèn)題就來(lái)了,我們?cè)鯓又赖玫降?個(gè)結(jié)果集還是1個(gè)count,這樣就不利于后續(xù)的操作了。進(jìn)化吧!
原始的問(wèn)題我們已明白了,我們的解決辦法就是將修改(增刪改)操作和查詢操作分開(kāi),看看上面的3個(gè)方法,秒懂了,是否是。先來(lái)處理簡(jiǎn)單的,修改,由于它的返回值是1個(gè)受影響的行數(shù),我們通過(guò)判斷這個(gè)行數(shù)是不是為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);
}
}
暫且我們將修改進(jìn)化到這里,后續(xù)將其進(jìn)化。將其封裝成1個(gè)方法,放到我的工具類中。
// 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;
}
先來(lái)查1個(gè)
@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);
}
}
我自己英語(yǔ)水平也不是很高,可能存在很多的語(yǔ)法問(wèn)題,大家將就的看,我也會(huì)不斷的學(xué)習(xí)改進(jìn)。這里直接將結(jié)果集的處理也寫(xiě)出來(lái)了,這里又觸及到1個(gè)思想:ORM(Object Relational Mapping):對(duì)象關(guān)系映照,拿我自己的話來(lái)理解就是,1張表對(duì)應(yīng)1個(gè)類,1列對(duì)應(yīng)1個(gè)屬性,1行對(duì)應(yīng)1個(gè)數(shù)據(jù),仔細(xì)想一想,是否是這樣的,可能我們1開(kāi)始想將讀出來(lái)的數(shù)據(jù)存到數(shù)組,集合中,但是用1個(gè)對(duì)象來(lái)存是否是更好1點(diǎn)?在說(shuō)說(shuō)ResultSet,API中是這樣說(shuō)的,“A table of data representing a database result set”包括1個(gè)數(shù)據(jù)庫(kù)結(jié)果集的數(shù)據(jù)表,得到的是可以認(rèn)為是1張表,它提供1個(gè)光標(biāo),通過(guò)next()方法,將光標(biāo)下移,光標(biāo)所指代表1行。然后我們從這1行中取出數(shù)據(jù),存到對(duì)象中。
那末問(wèn)題又來(lái)了,這里我們只能針對(duì)具體的某1張表,由于你不肯定它中列的個(gè)數(shù),列的名稱。為了提供1種通用的,可移植性高的程序,進(jìn)化吧!
我們想提供1種通用的解決辦法,就好比2.1JDBC的進(jìn)化2―增刪改1中我們將其封裝成方法,只通過(guò)1些參數(shù)就可以就獲得對(duì)象。想要獲得這個(gè)對(duì)象,而我們不知道具體是哪一個(gè)對(duì)象,只能在運(yùn)行時(shí)才能肯定具體獲得甚么對(duì)象……反射!反射!!!對(duì)!那我們來(lái)寫(xiě)這個(gè)通用的查詢方法。
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;
}
這里需要兩個(gè)參數(shù),sql就不用多提了,要說(shuō)的是第2個(gè)參數(shù) Class<T> clazz
我們需要通過(guò)反射來(lái)獲得具體類的實(shí)例,這里需要我們根據(jù)查詢的結(jié)果建立相應(yīng)的實(shí)體類表,然后通過(guò)反射的方式,來(lái)為具體的為某個(gè)屬性賦值。
而得到列數(shù),需要通過(guò)ResultSetMetaData才能獲得。
到這里的時(shí)候,你腦海里是否是會(huì)有這樣1個(gè)層次:
描寫(xiě)類的類(通過(guò)反射獲得的Class)
描寫(xiě)數(shù)據(jù)的數(shù)據(jù)(元數(shù)據(jù),如ResultSetMetaData)
思惟發(fā)散1下:還有1個(gè)描寫(xiě)注解的注解(元注解),固然這里沒(méi)有用到…
往下1個(gè)層次:
具體的類
具體的對(duì)象
具體的注解
這略微的進(jìn)化1下。
既然我們說(shuō),可以通過(guò)屬性來(lái)為其設(shè)置值,我們那末我們也能夠同getXXX()和setXXX()為屬性賦值。而Apache為我們提供了這樣的類庫(kù)(commons-beanutils⑴.8.0.jar,commons-logging⑴.1.1.jar,我會(huì)隨后上傳,大家注意看我評(píng)論,進(jìn)行下載使用)。
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;
}
這里是獲得多行,返回多個(gè)對(duì)象,用List來(lái)寄存。
做了兩個(gè)測(cè)試:
@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下,別名的使用,數(shù)據(jù)庫(kù)和Java程序命名規(guī)范可能有所不同,所以為了保證對(duì)應(yīng)的列名和屬性名相同,我們就要用到別名。(getColumnLabel() 優(yōu)先返回別名)
另附1些練習(xí):
1.創(chuàng)建數(shù)據(jù)庫(kù)表 examstudent,表結(jié)構(gòu)以下:
2.向數(shù)據(jù)庫(kù)表中添加1些數(shù)據(jù)
3.插入1個(gè)新的 student 信息
請(qǐng)輸入考生的詳細(xì)信息
Type:
IDCard:
ExamCard:
StudentName:
Location:
Grade:
信息錄入成功!
4.根據(jù)輸入的身份證號(hào)和準(zhǔn)考證號(hào)來(lái)查詢學(xué)生的基本信息
5.根據(jù)考生號(hào)刪除學(xué)生
ok,今天就進(jìn)化到這里吧。明天繼續(xù)。LG的屏的確挺不錯(cuò)的!