JDBC 學習筆記(四)—— 自定義JDBC框架+Apache—DBUtils框架+事務管理+操作多表


本文目錄:

      1、自定義JDBC框架 ——數據庫元數據:DataBaseMetaData 

      2、自定義JDBC框架 ——數據庫元數據:DataBaseMetaData 

      3、自定義JDBC框架 ——結果集元數據: ResultSetMetaData 

      4、使用元數據簡化JDBC代碼 

            (1) 萬能更新 

            (2) 萬能查詢 

      5、Apache—DBUtils框架簡介 

      6、DbUtils類 介紹 

      7、QueryRunner類 介紹 

      8、QueryRunner類的主要方法 

      9、ResultSetHandler接口 介紹 

      10、ResultSetHandler 接口的實現類 

      11、JDBC應用的事務管理(ThreadLocal類)  

      12、JDBC應用的事務管理——采用跨層跨層傳遞方法參數 

      13、JDBC應用的事務管理—— ThreadLocal 綁定連接 

      14、使用JDBC操作多個表

      15、使用JDBC操作多個表—— “一對多”關系  

      16、使用JDBC操作多個表—— 多對多關系 

      17、數據庫端——表關系間的級聯操作

 

1、自定義JDBC框架 ——數據庫元數據:DataBaseMetaData 

元數據:數據庫、表、列的定義信息。 

DataBaseMetaData   connection.getDatabaseMetaData()     

獲得代表DataBaseMetaData 對象元數據的DataBaseMetaData 對象。 

    DataBaseMetaData對象中的方法: 

        (1) getURL():返回一個String類對象,代表數據庫的URL。 

        (2) getUserName():返回連接當前數據庫管理系統的用戶名。 

        (3) getDatabaseProductName():返回數據庫的產品名稱。 

        (4) getDatabaseProductVersion():返回數據庫的版本號。 

        (5) getDriverName():返回驅動驅動程序的名稱。 

        (6) getDriverVersion():返回驅動程序的版本號。 

        (7) isReadOnly():返回一個boolean值,指示數據庫是否只允許讀操作。 

Demo樣例: 獲取數據庫的元數據  

  public void test1() throws SQLException{ 

        Connection conn = JdbcUtils_C3P0.getConnection(); 

        DatabaseMetaData meta = conn.getMetaData(); 

        System.out.println(meta.getDatabaseProductName()); 

        System.out.println(meta.getDatabaseMajorVersion()); 

        System.out.println(meta.getDatabaseMinorVersion()); 

  } 

 

2、自定義JDBC框架 ——數據庫元數據:DataBaseMetaData 

ParameterMetaData   PreparedStatement . getParameterMetaData() 

獲得代表PreparedStatement元數據的ParameterMetaData對象。 

例如:SQL語句 “ Select * from user where name=? And password=?  ” 中的兩個“ ?” 問號。 

ParameterMetaData對象 中的方法: 

        (1) getParameterCount()    --獲得指定參數的個數 

        (2) getParameterType(int param)    -- 獲得指定參數的sql類型(Mysql數據庫不支持該方法,會報異常。) 

Demo樣例:參數元數據 

      public void test2() throws SQLException{ 

            Connection conn = JdbcUtils_C3P0.getConnection(); 

            String sql = "insert into user(id,name) values(?,?)";  

            PreparedStatement st = conn.prepareStatement(sql); 

            ParameterMetaData meta = st.getParameterMetaData();       

            System.out.println(meta.getParameterCount());

            System.out.println(meta.getParameterType(1)); 

      }

 

3、自定義JDBC框架 ——結果集元數據: ResultSetMetaData 

ResultSetMetaData   ResultSet. getMetaData() 

獲得代表ResultSet對象元數據的ResultSetMetaData對象。 

    ResultSetMetaData對象中的方法 

            (1) getColumnCount()    -- 返回resultset對象的列數 

            (2) getColumnName(int column)    -- 獲得指定列的名稱 

            (3) getColumnTypeName(int column)    -- 獲得指定列的類型 

Demo樣例: 結果集元數據 

      public void test3() throws SQLException{ 

            Connection conn = JdbcUtils_C3P0.getConnection(); 

            String sql = "select * from account"; 

            PreparedStatement st = conn.prepareStatement(sql); 

            ResultSet rs = st.executeQuery();      

            ResultSetMetaData  meta = rs.getMetaData(); 

            System.out.println(meta.getColumnCount()); 

            System.out.println(meta.getColumnName(1)); 

            System.out.println(meta.getColumnName(2)); 

            System.out.println(meta.getColumnName(3));     

      }

 

4、使用元數據簡化JDBC代碼 

業務背景:系統中所有實體對象都涉及到基本的CRUD操作: 

        (1) 萬能更新 

        所有實體的CUD操作代碼基本相同,僅僅發送給數據庫的SQL語句不同而已,因此可以把CUD操作的所有相同代碼抽取到工具類的一個update方法中,並定義參數接收變化的SQL語句。 

Demo樣例1:萬能更新的方法內容部分

 1 public static void update(String sql,Object params[]) throws SQLException{
 2         Connection conn = null;
 3         PreparedStatement st = null
 4         ResultSet rs = null;
 5         try{
 6               conn = getConnection();
 7               st = conn.prepareStatement(sql);
 8               for(int i=0;i<params.length;i++){
 9                     st.setObject(i+1,params[i]);
10               }
11               st.executeUpdate();
12         }finally{
13               release(conn, st, rs);
14         }
15   }

Demo樣例2:萬能更新方法的調用代碼

 1 public class CustomerDaoImpl implements CustomerDao {
 2           public void add(Customer c){
 3                 try{
 4                       String sql = "insert into customer(id,name,gender,birthday,cellphone,email,preference,type,description) values(?,?,?,?,?,?,?,?,?)";
 5                       Object params[] = {c.getId(),c.getName(),c.getGender(),c.getBirthday(),c.getCellphone(),c.getEmail(),c.getPreference(),c.getType(),c.getDescription()};
 6                       JdbcUtils.update(sql, params);
 7                 }catch (Exception e) {
 8                       throw new DaoException(e);
 9                 }
10           }
11           public void update(Customer c){   //id
12                 try{
13                       String sql = "update customer set name=?,gender=?,birthday=?,cellphone=?,email=?,preference=?,type=?,description=?  where id=?";
14                       Object params[] = {c.getName(),c.getGender(),c.getBirthday(),c.getCellphone(),c.getEmail(),c.getPreference(),c.getType(),c.getDescription(),c.getId()};
15                       JdbcUtils.update(sql, params);
16                 }catch (Exception e) {
17                       throw new DaoException(e);
18                 } 
19           }
20           public void delete(String id){
21                 try{
22                       String sql = "delete from customer where id=?";
23                       Object params[] = {id};
24                       JdbcUtils.update(sql, params);
25                 }catch (Exception e) {
26                       throw new DaoException(e);
27                 } 
28           } 
29

   (2) 萬能查詢 

        實體的R操作,除SQL語句不同之外,根據操作的實體不同,對ResultSet的映射也各不相同,因此可義一個query方法,除以參數形式接收變化的SQL語句外,可以使用策略模式由qurey方法的調用者決定如何把ResultSet中的數據映射到實體對象中。 

         備注:關於自定義萬能查詢的代碼,涉及到自定義處理器等代碼,上面所述的數據庫元數據的各種知識也都應用到其中,故有些復雜,不便學習。有萬能查詢需求的請學習Apache—DBUtils框架 中的查詢方法部分,相對來說只要會調用即可,學習成本會小一些。

 

5、Apache—DBUtils框架簡介 

        commons-dbutils 是 Apache 組織提供的一個開源 JDBC工具類庫,它是對JDBC的簡單封裝,學習成本極低,並且使用dbutils能極大簡化jdbc編碼的工作量,同時也不會影響程序的性能。因此dbutils成為很多不喜歡hibernate的公司的首選。 

        工具類:    org.apache.commons.dbutils.DbUtils。    

        API介紹: 

           (1)  org.apache.commons.dbutils.QueryRunner  

           (2)  org.apache.commons.dbutils.ResultSetHandler  

 

6、DbUtils類 介紹 

        DbUtils :提供如關閉連接、裝載JDBC驅動程序等常規工作的工具類,里面的所有方法都是靜態的。主要方法如下: 

        (1) public static void close(…) throws java.sql.SQLException: DbUtils類提供了三個重載的關閉方法。這些方法檢查所提供的參數是不是NULL,如果不是的話,它們就關閉Connection、Statement和ResultSet。 

        (2) public static void closeQuietly(…): 這一類方法不僅能在Connection、Statement和ResultSet為NULL情況下避免關閉,還能隱藏一些在程序中拋出的SQLException。

        (3) public static void commitAndCloseQuietly(Connection conn): 用來提交連接,然后關閉連接,並且在關閉連接時不拋出SQL異常。  

        (4) public static boolean loadDriver(java.lang.String driverClassName):這一方裝載並注冊JDBC驅動程序,如果成功就返回true。使用該方法,你不需要捕捉這個異常ClassNotFoundException。

 

7、QueryRunner類 介紹 

        該類簡單化了SQL查詢,它與ResultSetHandler組合在一起使用可以完成大部分的數據庫操作,能夠大大減少編碼量。 

        QueryRunner類提供了兩個構造方法: 

            (1) 默認的構造方法: 

                    QueryRunner()  

            (2) 需要一個 javax.sql.DataSource 來作參數的構造方法。

                    QueryRunner(DataSource ds)   

 

8、QueryRunner類的主要方法 

        (1) public Object query(Connection conn, String sql, Object[] params, ResultSetHandler rsh) throws SQLException:執行一個查詢操作,在這個查詢中,對象數組中的每個元素值被用來作為查詢語句的置換參數。該方法會自行處理 PreparedStatement 和 ResultSet 的創建和關閉。 

        (2) public Object query(String sql, Object[] params, ResultSetHandler rsh) throws SQLException: 幾乎與第一種方法一樣;唯一的不同在於它不將數據庫連接提供給方法,並且它是從提供給構造方法的數據源(DataSource) 或使用的setDataSource 方法中重新獲得 Connection。     

        (3) public Object query(Connection conn, String sql, ResultSetHandler rsh) throws SQLException : 執行一個不需要置換參數的查詢操作。     

        (4) public int update(Connection conn, String sql, Object[] params) throws SQLException:用來執行一個更新(插入、更新或刪除)操作。      

        (5) public int update(Connection conn, String sql) throws SQLException:用來執行一個不需要置換參數的更新操作。 

Demo樣例:使用dbutils完成數據庫的crud 

 1 public class Demo1 { 
 2   /*
 3    create database day17;
 4    use day17;
 5    create table users(
 6     id int primary key,
 7     name varchar(40),
 8     password varchar(40),
 9     email varchar(60),
10     birthday date
11   );
12    */ 
13    
14   @Test
15   public void insert() throws SQLException{
16     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
17     String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";
18     Object params[] = {2,"bbb","123","aa@sina.com",new Date()};
19     runner.update(sql, params);
20   }
21 
22   @Test
23   public void update() throws SQLException{
24     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
25     String sql = "update users set email=? where id=?";
26     Object params[] = {"aaaaaa@sina.com",1};
27     runner.update(sql, params);
28   } 
29 
30   @Test
31   public void delete() throws SQLException{
32     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
33     String sql = "delete from users where id=?";
34     runner.update(sql, 1);
35   }
36 
37   @Test
38   public void find() throws SQLException{
39     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
40     String sql = "select * from users where id=?";
41     User user = (User) runner.query(sql, 1, new BeanHandler(User.class));
42     System.out.println(user.getEmail());
43   }
44 
45   @Test
46   public void getAll() throws Exception{
47     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
48     String sql = "select * from users";
49     List list = (List) runner.query(sql, new BeanListHandler(User.class));
50     System.out.println(list);
51   }
52 
53   @Test
54   public void batch() throws SQLException{
55     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
56     String sql =  "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";
57     Object params[][] = new Object[3][5];
58     for(int i=0;i<params.length;i++){  //3
59       params[i] = new Object[]{i+1,"aa"+i,"123",i + "@sina.com",new Date()};
60     }
61     runner.batch(sql, params);
62   }
63 }

9、ResultSetHandler接口 介紹 

        該接口用於處理 java.sql.ResultSet,將數據按要求轉換為另一種形式。 

        ResultSetHandler 接口提供了一個單獨的方法:Object handle (java.sql.ResultSet .rs)。   

 

10、ResultSetHandler 接口的實現類 

        (1) ArrayHandler( ):把結果集中的第一行數據轉成對象數組。 

        (2) ArrayListHandler( ):把結果集中的每一行數據都轉成一個數組,再存放到List中。 

        (3) BeanHandler(Class type) :將結果集中的第一行數據封裝到一個對應的JavaBean實例中。 

        (4) BeanListHandler(Class type) :將結果集中的每一行數據都封裝到一個對應的JavaBean實例中,存放到List里。 

        (5) ColumnListHandler(int columnIndex / String columnName):將結果集中某一列的數據存放到List中。 

        (6) KeyedHandler( int columnIndex / String columnName ):將結果集中的每一行數據都封裝到一個Map里,再把這些map再存到一個map里,並將其columnName的值作為指定的key。 

        (7) MapHandler( ):將結果集中的第一行數據封裝到一個Map里,key是列名,value就是對應的值。 

        (8) MapListHandler( ):將結果集中的每一行數據都封裝到一個Map里,然后再存放到List 

        (9)  ScalarHandler( ):將結果集中的某一列 裝入到一個對象中。 

Demo樣例:測試dbutils的各個結果集處理器

 1 public class Demo2 {   
 2   @Test
 3   public void test1() throws SQLException{
 4     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
 5     String sql = "select * from users where id=?";
 6     Object result[] = (Object[]) runner.query(sql,1, new ArrayHandler());
 7     System.out.println(result[0]);
 8     System.out.println(result[1]);
 9   }  
10 
11   @Test
12   public void test2() throws SQLException{
13     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
14     String sql = "select * from users";
15     List list = (List) runner.query(sql, new ArrayListHandler());
16     System.out.println(list);
17   }
18 
19   @Test
20   public void test3() throws SQLException{
21     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
22     String sql = "select * from users";
23     List list = (List) runner.query(sql, new ColumnListHandler1("name"));
24     System.out.println(list);
25   }  
26 
27   @Test
28   public void test4() throws SQLException{
29     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
30     String sql = "select * from users";
31     Map<Integer,Map<String,Object>> map = (Map) runner.query(sql, new KeyedHandler("id"));
32     for(Map.Entry<Integer,Map<String,Object>> me : map.entrySet()){
33       int id = me.getKey();
34       for(Map.Entry<String, Object> entry : me.getValue().entrySet()){
35         String name = entry.getKey();
36         Object value = entry.getValue();
37         System.out.println(name + "=" + value);
38       }
39     }
40   }
41 
42   @Test  //獲取總記錄數。
43   public void test5() throws SQLException{
44     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
45     String sql = "select count(*) from users";
46     /* 方式一:
47     Object result[] = (Object[]) runner.query(sql, new ArrayHandler());
48     long totalrecord = (Long)result[0];
49     int num = (int)totalrecord;
50     System.out.println(num);
51     int totalrecord = ((Long)result[0]).intValue();
52     */
53     
54     //方式二:
55     int totalrecord = ((Long)runner.query(sql, new ScalarHandler(1))).intValue();
56     System.out.println(totalrecord);
57   }
58 }
59 //自定義
60 class ColumnListHandler1 implements ResultSetHandler{ 
61   private String columnName;
62   public ColumnListHandler1(String columnName){
63     this.columnName = columnName;
64   }
65   public Object handle(ResultSet rs) throws SQLException {
66     List list = new ArrayList();
67     while(rs.next()){
68       list.add(rs.getObject(columnName));
69     }
70     return list;
71   }
72 }

11、JDBC應用的事務管理(ThreadLocal類)  

JDBC 應用的事務管理——Service層和Dao層事務的傳遞。 

    方式一:跨層傳遞方法參數——在Service層創建開啟事務的連接,並傳遞到Dao層,最后在Service層提交事務; 

    方式二:ThreadLocal 綁定連接——使用ThreadLocal進行事務管理——ThreadLocal可以實現在線程范圍內實現數據共享。 

    方式三:使用Spring進行事務管理。 

 

12、JDBC應用的事務管理——采用跨層跨層傳遞方法參數 

思想:在Service層創建開啟事務的連接,並傳遞到Dao層,最后在Service層提交事務;

Demo樣例1:Service層(Dao層中只要在方法中參數中接收該 連接參數 就好了)

 1 public class BusinessService {  
 2   /*  
 3   create table account(
 4     id int primary key auto_increment,
 5     name varchar(40),
 6     money float
 7   )character set utf8 collate utf8_general_ci;
 8   
 9   insert into account(name,money) values('aaa',1000);
10   insert into account(name,money) values('bbb',1000);
11   insert into account(name,money) values('ccc',1000); 
12   */  
13 
14   public void transfer1(int sourceid,int targetid,double money) throws SQLException{
15     Connection conn = null;
16     try{
17       // 獲取連接並開啟事務。
18       conn = JdbcUtils.getConnection();
19       conn.setAutoCommit(false);
20       // 將開啟事務的連接傳遞到各層。
21       AccountDao dao = new AccountDao(conn);
22       Account a = dao.find(sourceid);   //select
23       Account b = dao.find(targetid);   //select
24       a.setMoney(a.getMoney()-money); 
25       b.setMoney(b.getMoney()+money);
26       dao.update(a); //update     
27       dao.update(b);//update
28       // 提交事務。
29       conn.commit();
30     }finally{
31       // 關閉連接。
32       if(conn!=null) conn.close();
33     }
34   }
35

13、JDBC應用的事務管理—— ThreadLocal 綁定連接 

思想:在Service層將開啟事務的連接綁定到ThreadLocal中,在當前線程所途徑的其他各層從ThreadLocal中獲取連接並進行操作,最后線程返回至Service層時,再提交事務,移除綁定的鏈接

 

Demo樣例1:將 使用ThreadLocal 綁定連接 的代碼封裝成工具類。

 1 public class JdbcUtils {
 2   private static DataSource ds;  //為保證各層的類所使用的ThreadLocal是同一個,建議將其設定成靜態的,但是一定要記得使用后要移出綁定在上面的對象。
 3   private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();  //其實就是一個Map集合 
 4   static{
 5     try{
 6       Properties prop = new Properties();
 7       InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
 8       prop.load(in);
 9       BasicDataSourceFactory factory = new BasicDataSourceFactory();
10       ds = factory.createDataSource(prop);
11     }catch (Exception e) {
12       throw new ExceptionInInitializerError(e);
13     }
14   }
15 
16   public static DataSource getDataSource(){
17     return ds;
18   }
19   //備注:該獲取連接的方法,僅當使用ThreadLocal來管理事務連接的情況,因為向靜態對象ThreadLocal中綁定了對象,所以當我們不需要管理事務的普通獲取連接的方法,就不要用此方法。應該用普通的獲取連接的方法。  
20   
21   public static Connection getConnection() throws SQLException{
22     try{
23       //得到當前線程上綁定的連接
24       Connection conn = tl.get();
25       if(conn==null){  //代表線程上沒有綁定連接
26         conn = ds.getConnection();
27         tl.set(conn);
28       }
29       return conn;
30     }catch (Exception e) {
31       throw new RuntimeException(e);
32     }
33   } 
34   
35   public static void startTransaction(){
36     try{
37       //得到當前線程上綁定連接開啟事務
38       Connection conn = tl.get();
39       if(conn==null){  //代表線程上沒有綁定連接
40         conn = ds.getConnection();
41         tl.set(conn);
42       }
43       conn.setAutoCommit(false);
44     }catch (Exception e) {
45       throw new RuntimeException(e);
46     }
47   } 
48 
49   public static void commitTransaction(){
50     try{
51       Connection conn = tl.get();
52       if(conn!=null){
53         conn.commit();
54       }
55     }catch (Exception e) {
56       throw new RuntimeException(e);
57     }
58   }
59 
60   public static void closeConnection(){
61     try{
62       Connection conn = tl.get();
63       if(conn!=null){
64         conn.close();
65       }
66     }catch (Exception e) {
67       throw new RuntimeException(e);
68     }finally{
69       tl.remove();   //千萬注意,解除當前線程上綁定的鏈接(從threadlocal容器中移除對應當前線程的鏈接)
70     }
71   }
72 }

Demo樣例2: 采用 ThreadLocal 綁定連接 來管理事務的 Service層的代碼。

 1 public class BusinessService {  
 2   /*  
 3   create table account(
 4     id int primary key auto_increment,
 5     name varchar(40),
 6     money float
 7   )character set utf8 collate utf8_general_ci;
 8 
 9   insert into account(name,money) values('aaa',1000);
10   insert into account(name,money) values('bbb',1000);
11   insert into account(name,money) values('ccc',1000); 
12   */  
13   
14   //用上ThreadLocal的事務管理
15   public void transfer2(int sourceid,int targetid,double money) throws SQLException{
16     try{
17       JdbcUtils.startTransaction();
18       AccountDao dao = new AccountDao();
19       Account a = dao.find(sourceid);   //select
20       Account b = dao.find(targetid);   //select
21       a.setMoney(a.getMoney()-money);  
22       b.setMoney(b.getMoney()+money); 
23       dao.update(a); //update
24       dao.update(b);//update
25       JdbcUtils.commitTransaction();
26     }finally{
27       JdbcUtils.closeConnection();
28     }
29   }
30 }

14、使用JDBC操作多個表 

        (1) 使用JDBC操作多表的步驟 

                (a)  明確對象的屬性,及之間的關聯關系。 

                (b)  明確表關系, 創建數據庫及表; 

                (c)  編碼Dao層的代碼(重點是增刪改查時涉及到的級聯操作。) 

                (d)  編碼Service層的代碼(重點是 復雜對象  的級聯操作。)      

        (2)  O-R Mapping 映射的注意事項 

                (a) 不管java的對象存在何種關系,反映到關系型數據庫中,都是使用外鍵表示紀錄(即對象)的關聯關系。

                 (b) 設計java對象如涉及到多個對象相互引用,要盡量避免使用一對多,或多對多關系,而應使用多對一描述對象之間的關系(或使用延遲加載的方式)。以避免查詢出了所有“一對多”中 “多”的數據,容易造成內存溢出 

                (c) 特殊情況下(比如訂單--訂單項)必須設計成“一對多”關系時,當“多”的一方數據較少時,可以使用級聯查詢,但若是“多”的一方數據量較大時,則建議使用 “分頁方式”查詢。     

       (3)  “一對多”多表關聯關系的設計方法: 

                (a) 先將每張表各自的基本屬性信息列好; 

                (b) 再將“一對多” 多的一方中設定外鍵列(並添加外鍵約束,以維護兩表之間的關系)。      

       (4) 常用O-R Mapping映射工具 

                (a) Hibernate 

                (b) Ibatis 

                (c) Commons DbUtils(只是對JDBC簡單封裝)      

 

15、使用JDBC操作多個表—— 一對多關系 (例如:部門和員工)

Demo樣例1:Dao層的代碼

 1 public class DepartmentDao { 
 2   /*
 3     多表設計原則
 4     1、現將各表各自的基本屬性信息列好;
 5     2、再將“一對多” 多的一方中設定外鍵列(並添加外鍵約束,以維護兩表之間的關系)。
 6     create table department
 7     (
 8       id varchar(40) primary key,
 9       name varchar(40)
10     ); 
11 
12     create table employee
13     (
14       id varchar(40) primary key,
15       name varchar(40),
16       salary double,
17 
18       department_id varchar(40),
19       constraint department_id_FK foreign key(department_id) references department(id)
20     );
21     
22     alter table employee drop foreign key department_id_FK;
23     alter table employee add constraint department_id_FK foreign key(department_id) references department(id) on delete set null;
24     alter table employee drop foreign key department_id_FK;
25     alter table employee add constraint department_id_FK foreign key(department_id) references department(id) on delete cascade; 
26    */
27 
28   public void add(Department d) throws SQLException{ 
29     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
30     //1.把department對象的數據插入到department表
31     String sql = "insert into department(id,name) values(?,?)";
32     Object params[] = {d.getId(),d.getName()};
33     runner.update(sql, params);
34     //2.把department對象中維護的所有員工插入到員工表
35     Set<Employee> set = d.getEmployees();
36     for(Employee e : set){
37       sql = "insert into employee(id,name,salary,department_id) values(?,?,?,?)";
38       params = new Object[]{e.getId(),e.getName(),e.getSalary(),d.getId()};
39       runner.update(sql, params);
40     }
41     //3.更新員工表的外鍵列,說明員工的部門(本例中的ID可以實現給定,固就不需要進行更新外鍵列操作;但若是涉及到獲取 自動生成主鍵 的案例時,則需要 涉及到更新外鍵操作)。
42   }
43 
44   //該方法查詢出了所有“一對多”中 “多”的數據,容易造成內存溢出。當“多”的一方數據較少時,可以使用該級聯查詢,但若是“多”的一方數據量較大時,則建議使用 “分頁方式”查詢。
45   public Department find(String id) throws SQLException{
46     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
47     //1.找部門表,查出部門的基本信息
48     String sql = "select * from department where id=?";
49     Department d = (Department) runner.query(sql, id, new BeanHandler(Department.class));
50     //2.找員工表,找出部門下面所有員工
51     sql = "select * from employee where department_id=?";
52     List list = (List) runner.query(sql, id, new BeanListHandler(Employee.class));
53     d.getEmployees().addAll(list);       //注:set集合的addAll()是將所有的值逐個取出來,再逐一存入到Set集合中;而set集合的add()方法則是替換一Set集合的引用。
54     return d;
55   }
56 
57   //111
58   public void delete(String id) throws SQLException{
59     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
60     String sql= "delete from department where id=?";
61     runner.update(sql, id);
62   }
63 }

Demo樣例2:Service層的代碼 

 1 public class BService { 
 2  
 3   @Test
 4   public void add() throws SQLException{ 
 5     Department d = new Department();
 6     d.setId("111");
 7     d.setName("開發部");
 8     Employee e1 = new Employee();
 9     e1.setId("1");
10     e1.setName("aa");
11     e1.setSalary(10000); 
12     Employee e2 = new Employee();
13     e2.setId("2");
14     e2.setName("bb");
15     e2.setSalary(10000);
16     d.getEmployees().add(e1); 
17     d.getEmployees().add(e2);  
18     DepartmentDao dao = new DepartmentDao(); 
19     dao.add(d); 
20   } 
21  
22   @Test 
23   public void find() throws SQLException{ 
24     DepartmentDao dao = new DepartmentDao(); 
25     Department d = dao.find("111"); 
26     System.out.println(d); 
27   }
28   
29   @Test 
30   public void delete() throws SQLException{
31     DepartmentDao dao = new DepartmentDao(); 
32     dao.delete("111"); 
33   } 
34

16、使用JDBC操作多個表—— 多對多關系 (老師和學生)

Demo樣例1:Dao層的代碼

 1 public class TeacherDao {  
 2   /* 
 3   create table teacher 
 4   (
 5     id varchar(40) primary key,
 6     name varchar(40), 
 7     salary double 
 8   ) ; 
 9  
10   create table student 
11   ( 
12     id varchar(40) primary key, 
13     name varchar(40) 
14   );
15   
16    create table teacher_student 
17    ( 
18      teacher_id varchar(40), 
19      student_id varchar(40), 
20      primary key(teacher_id,student_id), 
21      constraint teacher_id_FK foreign key(teacher_id) references teacher(id),  
22      constraint student_id_FK foreign key(student_id) references student(id) 
23    ); 
24  
25    alter table teacher_student drop foreign key teacher_id_FK; 
26    alter table teacher_student add constraint teacher_id_FK foreign key(teacher_id) references teacher(id) on delete cascade;   
27  
28    alter table teacher_student drop foreign key student_id_FK; 
29    alter table teacher_student add constraint student_id_FK foreign key(student_id) references student(id) on delete cascade; 
30   */
31   
32   public void add(Teacher t) throws SQLException { 
33     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource()); 
34     //1`.取出老師存老師表 
35     String sql = "insert into teacher(id,name,salary) values(?,?,?)"; 
36     Object params[] = {t.getId(),t.getName(),t.getSalary()}; 
37     runner.update(sql, params);
38     //2.取出老師所有學生的數據,存學生表 
39     Set<Student> set = t.getStudents(); 
40     for(Student s : set){ 
41       sql = "insert into student(id,name) values(?,?)"; 
42       params = new Object[]{s.getId(),s.getName()}; 
43       runner.update(sql, params);
44       //3.更新中間表,說明老師和學生的關系 
45       sql = "insert into teacher_student(teacher_id,student_id) values(?,?)"; 
46       params = new Object[]{t.getId(),s.getId()}; 
47       runner.update(sql, params); 
48     } 
49   }
50  
51   public Teacher find(String id) throws SQLException{
52     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
53     //1.找老師表,找出老師的基本信息 
54     String sql = "select * from teacher where id=?"; 
55     Teacher t = (Teacher) runner.query(sql, id, new BeanHandler(Teacher.class)); 
56     //2.找出老師的所有學生    () 
57     //sql = "select s.* from teacher_student ts,student s where ts.teacher_id=? and ts.student_id=s.id"; 
58     sql = "select s.* from teacher_student ts,student s where ts.teacher_id=? and ts.student_id=s.id"; 
59     List list = (List) runner.query(sql, id, new BeanListHandler(Student.class));
60     t.getStudents().addAll(list);
61     return t; 
62   }
63  
64   public void delete(String id){
65     QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource()); 
66     String sql = "delete from teacher where id=?"; 
67   } 
68 }

Demo樣例2:Service層的代碼 

 1 public class BService {
 2  @Test
 3  public void addTeacher() throws SQLException{
 4   Teacher t = new Teacher();
 5   t.setId("1");
 6   t.setName("老張");
 7   t.setSalary(100000);
 8   Student s1 = new Student();
 9   s1.setId("1");
10   s1.setName("aa");
11   Student s2 = new Student();
12   s2.setId("2");
13   s2.setName("bb"); 
14   t.getStudents().add(s1); 
15   t.getStudents().add(s2); 
16   TeacherDao dao = new TeacherDao();
17   dao.add(t); 
18  } 
19  
20  @Test
21  public void findTeacher() throws SQLException{ 
22   TeacherDao dao = new TeacherDao(); 
23   Teacher t = dao.find("1"); 
24   System.out.println(t); 
25  }
26 }

17、數據庫端——表關系間的級聯操作 

表關系間的級聯操作: 

    REFERENCES tbl_name [(index_col_name,...)] 

               [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] 

               [ON DELETE reference_option]  (級聯刪除)  

               [ON UPDATE reference_option]  (級聯修改)

reference_option的可選值: 

    RESTRICT | CASCADE(刪除) | SET NULL(置空) | NO ACTION  

Demo:給表添加外鍵約束——包含級聯刪除(置空)的關系 

   alter table employee add constraint department_id_FK foreign key(department_id) references department(id) on delete set null ;  

   alter table employee add constraint department_id_FK foreign key(department_id) references department(id) on delete set null; 

   alter table employee add constraint department_id_FK foreign key(department_id) references department(id) on delete cascade; 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM