本文目錄:
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;