`

JDBC 学习笔记(四)—— 自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表

阅读更多

 

 

本文查阅方法:
    1、查阅目录 —— 查阅本文目录,确定想要查阅的目录标题
    2、快捷“查找” —— 在当前浏览器页面,按键 “Ctrl+F” 按键组合,开启浏览器的查找功能,
             在查找搜索框中 输入需要查阅的 目录标题,便可以直接到达 标题内容 的位置。
    3、学习小结 —— 文中的学习小结内容,是笔者在学习之后总结出的,开发时可直接参考其进行应用开发的内容, 进一步加快了本文的查阅 速度。(水平有限,仅供参考。)
 

 


 

 

 

本文目录

 

      学习小结

 

      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、数据库端——表关系间的级联操作

 

 

 

相关学习

 

JDBC 学习笔记(一)—— 基础知识 + 分页技术

      链接地址:http://even2012.iteye.com/blog/1886946

 

JDBC 学习笔记(二)—— 大数据+存储过程+批处理+事务

      链接地址:http://even2012.iteye.com/blog/1886950

 

JDBC 学习笔记(三)—— 数据源(数据库连接池):DBCP数据源、C3P0 数据源以及自定义数据源技术

      链接地址:http://even2012.iteye.com/blog/1886953

 

JDBC 学习笔记(四)—— 自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表  

      链接地址:http://even2012.iteye.com/blog/1886956

 


 

 学习小结

 

 

 

 

 

 

 

 

 


 

 

 

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; 

 

 

 

 

 


 

 

 

 敬请评论

(1)若您觉得本文 有用处  —— 请留言评论,以坚定其他 IT童鞋 阅读本文的信心。

(2)若您觉得本文 没用处  —— 请留言评论,笔者将会改进不足,以便为大家整理更加好用的笔记。
 

 


 

 

 

 

 

  • 大小: 96 KB
  • 大小: 65.5 KB
  • 大小: 52.4 KB
分享到:
评论
1 楼 a331251021 2013-06-17  
这篇也很好~~楼主还是弄成附近方便点,可以弄成工程到CSDN下载那啊

相关推荐

    安卓Android源码——安卓Android快速框架+多线程下载框架的技术.rar

    本资源"安卓Android源码——安卓Android快速框架+多线程下载框架的技术"提供了深入理解Android平台下的应用程序开发,特别是涉及到Afinal和Gson这两个关键库的使用。下面我们将详细探讨这些知识点。 一、Android...

    Apache Dbutils JDBC 框架demo代码

    commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。因此dbutils成为很多不喜欢hibernate的公司...

    DBUtils操作数据库以及事物的管理

    ### DBUtils操作数据库及事务管理详解 #### 一、DBUtils简介 DBUtils是一个轻量级的Java数据库访问工具类库,它简化了JDBC的使用步骤,使得开发者能够更方便地进行数据库操作。相比于传统的JDBC编程方式,DBUtils...

    Apache-DBUtils封装JDBC

    使用了Apache Commons DbUtils库中的类和方法封装JDBC,使用了org.apache.commons.dbutils.QueryRunner、org.apache.commons.dbutils.handlers.BeanHandler和org.apache.commons.dbutils.handlers.BeanListHandler等...

    c3p0 jar+mysql 8.0.15+dbutils.rar

    `c3p0`、`MySQL 8.0.15`和`DBUtils`是三个重要的Java库,分别针对数据库连接池管理、数据库引擎以及数据库操作提供了便捷的工具。在这个`c3p0 jar+mysql 8.0.15+dbutils.rar`压缩包中,包含了这三个组件的集成,便于...

    jdbc+数据库连接池+dbutils

    DbUtils是一个简化JDBC操作的工具类库,它提供了更简洁的方式来执行SQL语句,自动释放资源等功能。 ##### DbUtils使用示例 1. **导入依赖** - 添加DbUtils的依赖。 ```xml &lt;groupId&gt;org.apache.commons ...

    jar:mysql5.0.8+dbcp1.2.2+dbutils1.2

    jar:mysql5.0.8+dbcp1.2.2+dbutils1.2,亲测可用。如果嫌弃包低,可用直接访问commons.apache官网http://commons.apache.org/选择下载即可。

    JDBC连接数据库DBUtils操作数据库两个jar包

    本篇将详细讲解如何使用JDBC连接MySQL数据库,并结合Apache的DBUtils库简化数据库操作。 首先,我们需要了解JDBC。JDBC是Java平台的一个标准接口,允许Java应用程序与各种类型的数据库进行通信。它定义了一组用于...

    Apache commons dbutils 1.4jar是JDBC的开源数据库工具包

    Apache Commons DBUtils 1.4 是一个开源的Java库,它是针对Java Database Connectivity (JDBC) API的一个实用工具集。这个库旨在简化数据库操作,使开发者能够更方便、更安全地处理数据库连接和数据操作。DBUtils的...

    Apache Dbutils +springmvc 框架demo代码

    commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。 springmvc与springmvc 整合demo

    c3p0+xml+jdbc.properties+DBUtils+mysql-connector

    标题 "c3p0+xml+jdbc.properties+DBUtils+mysql-connector" 提示我们讨论的是一个基于Java的数据库连接管理方案,它涉及到几个关键组件:C3P0连接池、XML配置、`jdbc.properties`配置文件以及MySQL的JDBC驱动。...

    JSP+Servlet+DBUtils

    使用JSP + Servlet + JDBC实现MVC 使用JSP + Servlet + DBUtils实现MVC ...5.使用DBUtils1.6操作数据库,使用原生方法操作数据库 TUserDao使用JDBC TUserDaoEx使用Dbutils 6.扩展方法JsonResult自定义方法

    apache dbutils中文说明

    Apache DBUtils是一个开源的Java库,它为Java程序员提供了便捷的方式来处理JDBC(Java Database Connectivity)操作。DBUtils的主要目标是简化JDBC编程,减少代码重复,并帮助避免常见的JDBC编程错误。它不是一个...

    dbutils的使用_事务处理_多表操作_oracle大数据处理

    总结来说,DBUtils作为Apache Commons家族的一个组件,简化了Java数据库编程工作,特别是在事务处理、多表操作和大数据量处理方面,它提供了便捷的接口和工具类,让数据库操作更加简单和高效。不过,使用DBUtils时也...

    Servlet+Druid+Mysql+dbutils+Thymeleaf完成的用户管理系统

    Apache的DbUtils是一个小巧且实用的Java数据库操作工具库,它简化了JDBC的使用,提供了更安全、便捷的数据库操作方式。在用户管理系统中,DbUtils可以帮助我们执行SQL语句,处理结果集,进行事务管理等,使得数据库...

    04-Apache-DBUtils驱动.rar

    Apache DBUtils是一个开源的Java库,它为Java应用程序提供了简单且有效的数据库连接管理。这个工具包简化了JDBC(Java Database Connectivity)的使用,通过提供一个健壮且易于使用的抽象层,使得数据库操作变得更加...

    Apache DBUtils使用总结

    Apache DBUtils 是一个轻量级的 Java 数据库连接(JDBC)工具,它提供了一些实用功能,简化了数据库操作。DBUtils 最主要的功能是对 JDBC 结果集进行封装,能够将查询结果直接转换为 JavaBean 对象,从而减轻开发...

    Apache Commons DbUtils 1.6 API

    Apache Commons DbUtils 1.6 API 是一个Java库,它为数据库操作提供了简化的、异常安全的工具。这个API设计的目的是为了简化JDBC(Java Database Connectivity)编程,减轻开发人员处理数据库连接、事务和结果集时的...

    采用Apache dbutils操作数据库

    Apache DBUtils是一个基于...通过以上步骤,我们可以轻松地使用Apache DBUtils来实现数据库操作,大大简化了传统的JDBC编程。同时,由于DBUtils库已经处理了很多底层的错误处理和资源管理,所以代码更加健壮和安全。

    commons-dbutils-1.4.jar

    在实际项目中,"commons-dbutils-1.4.jar"可以与Apache的另一个项目——Apache Commons DBCP(数据库连接池)配合使用,以实现数据库连接的池化管理,进一步提升系统性能。例如,可以通过BasicDataSource来配置和...

Global site tag (gtag.js) - Google Analytics