Spring征服資料庫
一.spring的資料訪問哲學
1. Srping的目標之一就是允許我們在開發應用程式的時候,能夠遵循面向物件( Object Oriented,OO )原則中的"針對介面式程式設計";
- 講道理現在市面上的所有專案都離不開介面,針對介面是面向物件的重要特徵之一,而spring的最終目標就是簡化這一特徵的使用方法(比如耦合).
- 只暴露介面,從而體現出該實現的目標!
- Spring為多種框架提供了jdbc支援;
- Spring本身就具有多個模組,他是模組化的框架,就好像java的虛擬機器一樣,在什麼地方,用什麼方法;
二.配置資料來源
1.不管使用什麼模板,以及不管使用什麼型別的資料庫,資料來源是必須的(廢話),一般有三種方式;- 通過jdbc驅動程式定義的資料來源(最基本的jdbc,註冊驅動->獲取連線->獲取操作物件->操作結果集->釋放資源);
- 通過JNDL查詢資料來源(這個配置在伺服器上面的比如TOMCAT),( 留待 )
- 通過連線池獲取資料來源(c3p0,druid..)
三.jdbcTemplate (其實並不難,我指的是裡面原始碼,很好理解,前提是理解回撥和遞迴原則)
1.回撥,它最難理解的地方之一
類A呼叫類B的方法B_1,然後A繼續去執行自己的東西,B_1自己執行完了就告訴A,然後類A得到類B_1的執行結果,去做些不可描述的事情
小王在打遊戲,叫小紅去做飯,小紅做了一會飯做好了,小王還在打遊戲(這個時候小王可以決定吃飯,也可以繼續打遊戲,也可以邊吃飯便打遊戲(多執行緒非同步))
- 這之中的實現步驟,小王要實現一個介面,小紅做好了飯就呼叫這個介面去告訴小王傳遞飯好了的資訊,然而這個故事的主人公是小王,小紅只是個配角,
在建立小王的同時就要將小紅當做引數送給小王;
//回撥介面 public interface CB { public void talk(String word); }
//警察叔叔類 public class Police implements CB { private Thief tf ;//因為警察叔叔需要賊(要問問題),所以才有的賊(賊要回答問題),主業務需求,誕生附屬子實現!!!! public Police(Thief tf) {//將賊物件傳遞給警察叔叔, this.tf = tf; } //回撥方法,用來向當前類傳遞資訊 @Override public void talk(String word) { System.out.println("毛賊說:" + word); } /** * 警察發問 */ public void talkcrap() { System.out.println("你錯了嗎"); tf.worng(this);//警察進行詢問,這個賊是傳入進來的,將當前類物件傳遞個賊,賊和警察是1對1關係(當然也可以實現1對多,使用LIist<賊物件>) } }
public class Thief { public void worng(CB cb) {//回撥介面傳遞資訊 cb.talk("警察叔叔我錯了");//這個地方傳遞的引數,當前行呼叫了介面的talk方法 } }
回撥很繞,我解釋不太清除,這個例子是自己想出來的,網上有很多大佬的解釋,多敲幾遍,多除錯幾遍程式碼,就能看懂裡面的邏輯所在了;
- 附上我修改過1對多例子
//回撥介面 public interface CallBack { //這裡才是回撥,要呼叫這個方法,才能夠傳遞資訊!!!!! public void tellAnswer(int answer); } //學生介面 public interface Student { //這裡放入一個物件,要放入主要物件,就是當前類依賴於的物件:主業務物件 public void resovleQuestion(CallBack callBack); }
//老師類 public class Teacher implements CallBack { private List<Student> stus;//tom,lusy,rose public Teacher(List<Student> stus) { System.out.println("teacher物件建立,學生數量"+stus.size()); this.stus = stus; } @Override public void tellAnswer(int answer) { System.out.println(Thread.currentThread().getName()+"你的答案是" + answer); } public void askQuestion() { Thread.currentThread().setName("老師執行緒"); System.out.println("你們寫了多長時間的作業?"); long end = 0; //啟動所有執行緒,回答所有問題 for (int i = 0; i < stus.size(); i++) { new Thread((Runnable) stus.get(i)).start(); } try { System.out.println(Thread.currentThread().getName()+"開始休眠15秒,等待所有人的問題回答完"); Thread.sleep(15000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("老師執行緒休眠結束"+System.currentTimeMillis()); for (int i = 0; i < stus.size(); i++) { stus.get(i).resovleQuestion(this); } //當前類實現了回撥介面,所以講當前類物件傳入進去 // //long end = System.currentTimeMillis(); //System.out.println("回答問題的時間:"+(end-start)); } }
學生的實現類只需繼承Student介面即可,其中使用了執行緒暫停來模擬思考題目的過程;sleep();
2. org.springframework.jdbc.core.RowMapper
將ResultSet封裝成javaBeen型別,他是一個函式式介面
//將ResultSet封裝成User型別 public class RowMapperDemo implements RowMapper<User>{ @Override public User mapRow(ResultSet resultSet, int i) throws SQLException { User user = new User(); user.setName(resultSet.getString("name")); user.setPassword(resultSet.getString("password")); return user; } }
- execute方法: 可以用於執行任何SQL語句,一般用於執行update,delete,insert
- update方法及batchUpdate方法: update方法用於執行新增、修改、刪除等語句;batchUpdate方法用於執行批處理相關語句;
- call方法: 用於執行儲存過程、函式相關語句。
4. 最重要的還是回撥
//RowMapper介面將ResultSet裡面的資料對映到JavaBeen中->封裝資料 //queryforList(),執行SQL,將資料返回為List<Map<String(列名),Object(行資料))>> List<User> list = jt.query(sql, (rs ,i)-> new User(rs.getString("name"),rs.getString("password"))); new RowMapper<User>() { @Override public User mapRow(ResultSet resultSet, int i) throws SQLException { User user = new User(); user.setPassword(resultSet.getString("password")); user.setName(resultSet.getString("name")); return user; } };
5. public <T> List<T> query(String sql, RowMapper<T> rowMapper):將執行的結果通過rowMapper介面對映為實體類物件
public List<Student> getStudents() { return jt.query("select * from student", (rs, i) -> new Student(rs.getString("stuno"), rs.getString("name"), rs.getInt("age"), rs.getString("address"))); //該lambda表示式相當於 new RowMapper<Student>() { @Override public Student mapRow(ResultSet resultSet, int i) throws SQLException { return new Student(rs.getString("stuno"),rs.getString("name"), rs.getInt("age"), rs.getString("address")); } }; }
6. public <T> T queryForObject(String sql, Class<T> requiredType)
一般用於單列查詢,主要用來執行返回 聚合函式 的查詢
jt.queryForObject("select count(*) from student where stuno ='"+stuno+"'", Integer.class); //返回Integer型別
7. int update (String sql, @Nullable Object... args)
一般用來執行 更新,刪除,增加操作,萬用字元使用方式如下
return jt.update("insert into student values(?,?,?,?)", new Object[]{stu.getStuno(), stu.getName(), stu.getAge(), stu.getAddress()}); //這兩種方式是一樣的效果,簡略了程式碼 return jt.update("insert into student values(?,?,?,?)",stu.getStuno(), stu.getName(), stu.getAge(), stu.getAddress());
8. execute語句,這種語句一般用來建立資料庫,建立表那些,用於那種不復雜(不使用萬用字元"?")的語句
jt.execute("DELETE FROM student WHERE stuno = '" + stuno + "'"); 不好使用萬用字元,這條sql半寫死的,主要還是用來執行建立資料庫,建立表的語句 jt.update("DELETE FROM student WHERE stuno = ?",stuno); 這兩條語句的作用是一樣的
9.我uml圖畫的不是很好,是在網上邊學邊畫的,有問題請不吝賜教QAQ