自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表

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:万能更新的方法内容部分

 

    public static void update(String sql,Object params[]) throws SQLException{

 

        Connection conn = null;

 

        PreparedStatement st = null;

 

        ResultSet rs = null;

 

        try{

 

              conn = getConnection();

 

              st = conn.prepareStatement(sql);

 

              for(int i=0;i<params.length;i++){

 

                    st.setObject(i+1,params[i]);

 

              }

 

              st.executeUpdate();

 

        }finally{

 

              release(conn, st, rs);

 

        }

 

  }

 

 

 

Demo样例2:万能更新方法的调用代码

 

    public class CustomerDaoImpl implements CustomerDao { 

 

          public void add(Customer c){

 

                try{

 

                      String sql = "insert into customer(id,name,gender,birthday,cellphone,email,preference,type,description) values(?,?,?,?,?,?,?,?,?)";

 

                      Object params[] = {c.getId(),c.getName(),c.getGender(),c.getBirthday(),c.getCellphone(),c.getEmail(),c.getPreference(),c.getType(),c.getDescription()};

 

                      JdbcUtils.update(sql, params);

 

                }catch (Exception e) {

 

                      throw new DaoException(e);

 

                }

 

          }

 

     

 

          public void update(Customer c){   //id

 

                try{

 

                      String sql = "update customer set name=?,gender=?,birthday=?,cellphone=?,email=?,preference=?,type=?,description=?  where id=?";

 

                      Object params[] = {c.getName(),c.getGender(),c.getBirthday(),c.getCellphone(),c.getEmail(),c.getPreference(),c.getType(),c.getDescription(),c.getId()};

 

                      JdbcUtils.update(sql, params);

 

                }catch (Exception e) {

 

                      throw new DaoException(e);

 

                } 

 

          }

 

     

 

          public void delete(String id){

 

                try{

 

                      String sql = "delete from customer where id=?";

 

                      Object params[] = {id};

 

                      JdbcUtils.update(sql, params);

 

                }catch (Exception e) {

 

                      throw new DaoException(e);

 

                } 

 

          } 

 

    }

 

  

 

        (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 

 

public class Demo1 { 

 

  /*

 

   create database day17;

 

   use day17;

 

   create table users(

 

    id int primary key,

 

    name varchar(40),

 

    password varchar(40),

 

    email varchar(60),

 

    birthday date

 

  );

 

   */ 

 

  @Test

 

  public void insert() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";

 

    Object params[] = {2,"bbb","123","aa@sina.com",new Date()};

 

    runner.update(sql, params);

 

  }

 

 

 

  @Test

 

  public void update() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "update users set email=? where id=?";

 

    Object params[] = {"aaaaaa@sina.com",1};

 

    runner.update(sql, params);

 

  }

 

 

 

  @Test

 

  public void delete() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "delete from users where id=?";

 

    runner.update(sql, 1);

 

  }

 

 

 

  @Test

 

  public void find() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "select * from users where id=?";

 

    User user = (User) runner.query(sql, 1, new BeanHandler(User.class));

 

    System.out.println(user.getEmail());

 

  }

 

 

 

 

 

  @Test

 

  public void getAll() throws Exception{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "select * from users";

 

    List list = (List) runner.query(sql, new BeanListHandler(User.class));

 

    System.out.println(list);

 

  }

 

 

 

  @Test

 

  public void batch() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql =  "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";

 

    Object params[][] = new Object[3][5];

 

    for(int i=0;i<params.length;i++){  //3

 

      params[i] = new Object[]{i+1,"aa"+i,"123",i + "@sina.com",new Date()};

 

    }

 

    runner.batch(sql, params);

 

  }

 

}

 

 

 

 


 

  

 

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的各个结果集处理器

 

public class Demo2 {   

 

  @Test

 

  public void test1() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "select * from users where id=?";

 

    Object result[] = (Object[]) runner.query(sql,1, new ArrayHandler());

 

    System.out.println(result[0]);

 

    System.out.println(result[1]);

 

  }  

 

 

 

  @Test

 

  public void test2() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "select * from users";

 

    List list = (List) runner.query(sql, new ArrayListHandler());

 

    System.out.println(list);

 

  }

 

 

 

  @Test

 

  public void test3() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "select * from users";

 

    List list = (List) runner.query(sql, new ColumnListHandler1("name"));

 

    System.out.println(list);

 

  }  

 

 

 

  @Test

 

  public void test4() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "select * from users";

 

    Map<Integer,Map<String,Object>> map = (Map) runner.query(sql, new KeyedHandler("id"));

 

    for(Map.Entry<Integer,Map<String,Object>> me : map.entrySet()){

 

      int id = me.getKey();

 

      for(Map.Entry<String, Object> entry : me.getValue().entrySet()){

 

        String name = entry.getKey();

 

        Object value = entry.getValue();

 

        System.out.println(name + "=" + value);

 

      }

 

    }

 

  }

 

 

 

  @Test  //获取总记录数。

 

  public void test5() throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "select count(*) from users";

 

    /* 方式一:

 

    Object result[] = (Object[]) runner.query(sql, new ArrayHandler());

 

    long totalrecord = (Long)result[0];

 

    int num = (int)totalrecord;

 

    System.out.println(num);

 

    int totalrecord = ((Long)result[0]).intValue();

 

    */

 

 

 

    //方式二:

 

    int totalrecord = ((Long)runner.query(sql, new ScalarHandler(1))).intValue();

 

    System.out.println(totalrecord);

 

  }

 

}

 

 

 

//自定义

 

class ColumnListHandler1 implements ResultSetHandler{ 

 

  private String columnName;

 

  public ColumnListHandler1(String columnName){

 

    this.columnName = columnName;

 

  }

 

  public Object handle(ResultSet rs) throws SQLException {

 

    List list = new ArrayList();

 

    while(rs.next()){

 

      list.add(rs.getObject(columnName));

 

    }

 

    return list;

 

  }

 

}

 

 

 


 

  

 

11、JDBC应用的事务管理(ThreadLocal类) 

 

JDBC 应用的事务管理——Service层和Dao层事务的传递。

 

    方式一:跨层传递方法参数——在Service层创建开启事务的连接,并传递到Dao层,最后在Service层提交事务;

 

    方式二:ThreadLocal 绑定连接——使用ThreadLocal进行事务管理——ThreadLocal可以实现在线程范围内实现数据共享。

 

     方式三:使用Spring进行事务管理;(在Spring 博文中讲解。)

 

     

 

                    

 

 

 


 

 

 

12、JDBC应用的事务管理——采用跨层跨层传递方法参数

 

思想:在Service层创建开启事务的连接,并传递到Dao层,最后在Service层提交事务;

 

 

 

Demo样例1:Service层(Dao层中只要在方法中参数中接收该 连接参数 就好了)

 

public class BusinessService {  

 

  /*  

 

  create table account(

 

    id int primary key auto_increment,

 

    name varchar(40),

 

    money float

 

  )character set utf8 collate utf8_general_ci;

 

 

 

  insert into account(name,money) values('aaa',1000);

 

  insert into account(name,money) values('bbb',1000);

 

  insert into account(name,money) values('ccc',1000); 

 

  */  

 

 

 

  public void transfer1(int sourceid,int targetid,double money) throws SQLException{

 

 

 

    Connection conn = null;

 

    try{

 

      // 获取连接并开启事务。

 

      conn = JdbcUtils.getConnection();

 

      conn.setAutoCommit(false);

 

 

 

      // 将开启事务的连接传递到各层。

 

      AccountDao dao = new AccountDao(conn);

 

 

 

      Account a = dao.find(sourceid);   //select

 

      Account b = dao.find(targetid);   //select

 

 

 

      a.setMoney(a.getMoney()-money);  

 

      b.setMoney(b.getMoney()+money);   

 

 

 

      dao.update(a); //update      

 

      dao.update(b);//update

 

 

 

      // 提交事务。

 

      conn.commit();

 

    }finally{

 

      // 关闭连接。

 

      if(conn!=null) conn.close();

 

    }

 

  }

 

 

 

 

 

 

 


 

 

 

 

 

13、JDBC应用的事务管理—— ThreadLocal 绑定连接

 

思想:在Service层将开启事务的连接绑定到ThreadLocal中,在当前线程所途径的其他各层从ThreadLocal中获取连接并进行操作,最后线程返回至Service层时,再提交事务,移除绑定的链接。

 

 

 

 

Demo样例1:将 使用ThreadLocal 绑定连接 的代码封装成工具类。

 

public class JdbcUtils {

 

  private static DataSource ds;

 

 

 

  // 为保证各层的类所使用的ThreadLocal是同一个,建议将其设定成静态的,但是一定要记得使用后要移出绑定在上面的对象。

 

  private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();  // 其实就是一个Map集合

 

 

 

  static{

 

    try{

 

      Properties prop = new Properties();

 

      InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");

 

      prop.load(in);

 

      BasicDataSourceFactory factory = new BasicDataSourceFactory();

 

      ds = factory.createDataSource(prop);

 

    }catch (Exception e) {

 

      throw new ExceptionInInitializerError(e);

 

    }

 

  }

 

 

 

  public static DataSource getDataSource(){

 

    return ds;

 

  }

 

 

 

  // 备注:该获取连接的方法,仅当使用ThreadLocal来管理事务连接的情况,因为向静态对象ThreadLocal中绑定了对象,所以当我们不需要管理事务的普通获取连接的方法,就不要用此方法。应该用普通的获取连接的方法。

 

  public static Connection getConnection() throws SQLException{

 

    try{

 

      //得到当前线程上绑定的连接

 

      Connection conn = tl.get();

 

      if(conn==null){  //代表线程上没有绑定连接

 

        conn = ds.getConnection();

 

        tl.set(conn);

 

      }

 

      return conn;

 

    }catch (Exception e) {

 

      throw new RuntimeException(e);

 

    }

 

  } 

 

 

 

  public static void startTransaction(){

 

    try{

 

      //得到当前线程上绑定连接开启事务

 

      Connection conn = tl.get();

 

      if(conn==null){  //代表线程上没有绑定连接

 

        conn = ds.getConnection();

 

        tl.set(conn);

 

      }

 

      conn.setAutoCommit(false);

 

    }catch (Exception e) {

 

      throw new RuntimeException(e);

 

    }

 

  } 

 

 

 

  public static void commitTransaction(){

 

    try{

 

      Connection conn = tl.get();

 

      if(conn!=null){

 

        conn.commit();

 

      }

 

    }catch (Exception e) {

 

      throw new RuntimeException(e);

 

    }

 

  }

 

 

 

  public static void closeConnection(){

 

    try{

 

      Connection conn = tl.get();

 

      if(conn!=null){

 

        conn.close();

 

      }

 

    }catch (Exception e) {

 

      throw new RuntimeException(e);

 

    }finally{

 

      tl.remove();   //千万注意,解除当前线程上绑定的链接(从threadlocal容器中移除对应当前线程的链接)

 

    }

 

  }

 

}

 

 

 

Demo样例2: 采用 ThreadLocal 绑定连接 来管理事务的 Service层的代码。

 

public class BusinessService {  

 

  /*  

 

  create table account(

 

    id int primary key auto_increment,

 

    name varchar(40),

 

    money float

 

  )character set utf8 collate utf8_general_ci;

 

 

 

  insert into account(name,money) values('aaa',1000);

 

  insert into account(name,money) values('bbb',1000);

 

  insert into account(name,money) values('ccc',1000); 

 

  */  

 

  //用上ThreadLocal的事务管理

 

  public void transfer2(int sourceid,int targetid,double money) throws SQLException{

 

 

 

    try{

 

      JdbcUtils.startTransaction();

 

      AccountDao dao = new AccountDao();

 

      Account a = dao.find(sourceid);   //select

 

      Account b = dao.find(targetid);   //select

 

      a.setMoney(a.getMoney()-money);  

 

      b.setMoney(b.getMoney()+money);   

 

      dao.update(a); //update

 

      dao.update(b);//update

 

      JdbcUtils.commitTransaction();

 

    }finally{

 

      JdbcUtils.closeConnection();

 

    }

 

  }

 

}

 

 


 

  

 

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层的代码

 

public class DepartmentDao { 

 

  /*

 

    多表设计原则

 

    1、现将各表各自的基本属性信息列好;

 

    2、再将“一对多” 多的一方中设定外键列(并添加外键约束,以维护两表之间的关系)。

 

 

 

    create table department

 

    (

 

      id varchar(40) primary key,

 

      name varchar(40)

 

    ); 

 

    create table employee

 

    (

 

      id varchar(40) primary key,

 

      name varchar(40),

 

      salary double,

 

      department_id varchar(40),

 

      constraint department_id_FK foreign key(department_id) references department(id)

 

    );

 

 

 

    alter table employee drop foreign key department_id_FK;

 

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

 

 

 

    alter table employee drop foreign key department_id_FK;

 

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

 

   */

 

 

 

  public void add(Department d) throws SQLException{ 

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

 

 

    //1.把department对象的数据插入到department表

 

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

 

    Object params[] = {d.getId(),d.getName()};

 

    runner.update(sql, params);

 

 

 

    //2.把department对象中维护的所有员工插入到员工表

 

    Set<Employee> set = d.getEmployees();

 

    for(Employee e : set){

 

      sql = "insert into employee(id,name,salary,department_id) values(?,?,?,?)";

 

      params = new Object[]{e.getId(),e.getName(),e.getSalary(),d.getId()};

 

      runner.update(sql, params);

 

    }

 

 

 

    //3.更新员工表的外键列,说明员工的部门(本例中的ID可以实现给定,固就不需要进行更新外键列操作;但若是涉及到获取 自动生成主键 的案例时,则需要 涉及到更新外键操作)。

 

    

 

  }

 

 

 

 

 

  //该方法查询出了所有“一对多”中 “多”的数据,容易造成内存溢出。当“多”的一方数据较少时,可以使用该级联查询,但若是“多”的一方数据量较大时,则建议使用 “分页方式”查询。

 

  public Department find(String id) throws SQLException{

 

 

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

 

 

    //1.找部门表,查出部门的基本信息

 

    String sql = "select * from department where id=?";

 

    Department d = (Department) runner.query(sql, id, new BeanHandler(Department.class));

 

 

 

    //2.找员工表,找出部门下面所有员工

 

    sql = "select * from employee where department_id=?";

 

    List list = (List) runner.query(sql, id, new BeanListHandler(Employee.class));

 

 

 

    d.getEmployees().addAll(list);    // 注:set集合的addAll() 是将所有的值逐个取出来,再逐一存入到Set集合中;而set集合的add()方法则是替换一Set集合的引用。

 

 

 

    return d;

 

  }

 

  //111

 

  public void delete(String id) throws SQLException{

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql= "delete from department where id=?";

 

    runner.update(sql, id);

 

  }

 

}

 

 

 

Demo样例2:Service层的代码 

 

public class BService { 

 

@Test

 

  public void add() throws SQLException{ 

 

    Department d = new Department();

 

    d.setId("111");

 

    d.setName("开发部");

 

 

 

    Employee e1 = new Employee();

 

    e1.setId("1");

 

    e1.setName("aa");

 

    e1.setSalary(10000); 

 

 

 

    Employee e2 = new Employee();

 

    e2.setId("2");

 

    e2.setName("bb");

 

    e2.setSalary(10000);

 

  

 

    d.getEmployees().add(e1);

 

    d.getEmployees().add(e2); 

 

 

 

    DepartmentDao dao = new DepartmentDao();

 

    dao.add(d);

 

  }

 

 

 

  @Test

 

  public void find() throws SQLException{

 

    DepartmentDao dao = new DepartmentDao();

 

    Department d = dao.find("111");

 

    System.out.println(d);

 

  }

 

 

 

  @Test

 

  public void delete() throws SQLException{

 

    DepartmentDao dao = new DepartmentDao();

 

    dao.delete("111");

 

  }

 

 }

 

 

 


 

 

 

16、使用JDBC操作多个表—— 多对多关系 (老师和学生)

 



 

 

 

 

Demo样例1:Dao层的代码

 

public class TeacherDao { 

 

  /*

 

  create table teacher

 

  (

 

    id varchar(40) primary key,

 

    name varchar(40),

 

    salary double

 

  ) ;

 

 

 

  create table student

 

  (

 

    id varchar(40) primary key,

 

    name varchar(40)

 

  );

 

 

 

   create table teacher_student

 

   (

 

     teacher_id varchar(40),

 

     student_id varchar(40),

 

     primary key(teacher_id,student_id),

 

     constraint teacher_id_FK foreign key(teacher_id) references teacher(id), 

 

     constraint student_id_FK foreign key(student_id) references student(id)

 

   );

 

 

 

   alter table teacher_student drop foreign key teacher_id_FK;

 

   alter table teacher_student add constraint teacher_id_FK foreign key(teacher_id) references teacher(id) on delete cascade;  

 

 

 

   alter table teacher_student drop foreign key student_id_FK;

 

   alter table teacher_student add constraint student_id_FK foreign key(student_id) references student(id) on delete cascade;

 

  */

 

 

 

  public void add(Teacher t) throws SQLException {

 

 

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

 

 

    //1`.取出老师存老师表

 

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

 

    Object params[] = {t.getId(),t.getName(),t.getSalary()};

 

    runner.update(sql, params);

 

 

 

 

 

    //2.取出老师所有学生的数据,存学生表

 

    Set<Student> set = t.getStudents();

 

    for(Student s : set){

 

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

 

      params = new Object[]{s.getId(),s.getName()};

 

      runner.update(sql, params);

 

 

 

      //3.更新中间表,说明老师和学生的关系

 

      sql = "insert into teacher_student(teacher_id,student_id) values(?,?)";

 

      params = new Object[]{t.getId(),s.getId()};

 

      runner.update(sql, params);

 

    }

 

  }

 

 

 

  public Teacher find(String id) throws SQLException{

 

 

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

 

 

    //1.找老师表,找出老师的基本信息

 

    String sql = "select * from teacher where id=?";

 

    Teacher t = (Teacher) runner.query(sql, id, new BeanHandler(Teacher.class));

 

 

 

    //2.找出老师的所有学生    ()

 

    //sql = "select s.* from teacher_student ts,student s where ts.teacher_id=? and ts.student_id=s.id";

 

    sql = "select s.* from teacher_student ts,student s where ts.teacher_id=? and ts.student_id=s.id";

 

    List list = (List) runner.query(sql, id, new BeanListHandler(Student.class));

 

 

 

 

 

    t.getStudents().addAll(list);

 

    return t;

 

  }

 

 

 

  public void delete(String id){

 

    QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

 

    String sql = "delete from teacher where id=?";

 

 

 

  }

 

}

 

 

 

Demo样例2:Service层的代码 

 

public class BService {

 

@Test

 

 public void addTeacher() throws SQLException{

 

 

 

  Teacher t = new Teacher();

 

  t.setId("1");

 

  t.setName("老张");

 

  t.setSalary(100000);

 

 

 

  Student s1 = new Student();

 

  s1.setId("1");

 

  s1.setName("aa");

 

 

 

  Student s2 = new Student();

 

  s2.setId("2");

 

  s2.setName("bb");

 

 

 

  t.getStudents().add(s1);

 

  t.getStudents().add(s2); 

 

 

 

  TeacherDao dao = new TeacherDao();

 

  dao.add(t);

 

 }

 

 

 

 @Test

 

 public void findTeacher() throws SQLException{

 

  TeacherDao dao = new TeacherDao();

 

  Teacher t = dao.find("1");

 

  System.out.println(t);

 

 }

 

 

 

}

 

 

 

 


 

  

 

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; 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值