zoukankan      html  css  js  c++  java
  • 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; 

  • 相关阅读:
    iOS开发之WIFI,3G/4G两种网络同时使用技巧
    UIScreen的scale属性
    iOS开发中的Self-Manager 模式
    iOS UICollectionView简单使用
    Size Classes with Xcode 6
    SizeClass介绍
    AutoLayout处理UITableView动态高度
    在Scrollview中使用AutoLayout
    hashmap与hashtable的本质区别
    MySQL的5大引擎及优劣之分
  • 原文地址:https://www.cnblogs.com/lijiews/p/lj201401221643.html
Copyright © 2011-2022 走看看