前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDBC——DAO设计

JDBC——DAO设计

作者头像
木瓜煲鸡脚
发布2019-08-06 14:47:48
5710
发布2019-08-06 14:47:48
举报
文章被收录于专栏:Jasper小笔记Jasper小笔记

DAO设计

  1. 什么是DAO
  2. 编写DAO接口
  3. DAO接口实现
  4. 编写其他工具类

什么是DAO

里面包含用来操作数据库各种方法,操作数据库时只需要调用其中的方法

编写DAO接口

首先一个表对应一个类,一个对象对应一条记录

这样就可以以面向对象的思想来操作数据库

代码语言:javascript
复制
/* 类中的三个属性就对应表中的三列字段 */
public class Student {
  private int id;
  private String name;
  private int age;
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  @Override
  public String toString() {
    return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
  }
  
}

操作student的dao接口,包含需要的各种操作

比如添加一条学生记录:

代码语言:javascript
复制
Student stu = new Student();
stu.setId(1);
stu.setName("张三");
stu.setAge("19");
/* 
   创建完一个对象 ,
   然后想把它添加到表中
*/
IStudentDao dao = new StuDaoImp();
dao.add(stu);// 这样就可以完成插入操作了

DAO接口

代码语言:javascript
复制
public interface IStudentDao {
  /**
   * 保存一个学生
   */
  public void add(Student stu);
  /**
   * 删除学生
   */
  public void delete(int id);
  /**
   * 更新一个学生信息
   */
  public void update(int id,Student stu);
  /**
   * 获取指定学生
   */
  public Student get(int id);
  /**
   * 获取所有的学生
   */
  public List<Student> getAll();
  /**
   * 获取学生的总数
   */
  Integer getCount();
}

DAO接口的实现

代码语言:javascript
复制
public class StuDaoImp implements DAO {

  @Override
  public void add(Student stu) {
    String sql = "insert into student values(?,?,?)";
    Connection con = null;
    PreparedStatement prepareStatement = null;
    try {
      Class.forName("com.mysql.cj.jdbc.Driver");
      String url = "jdbc:mysql://localhost:3306/mydb?serverTimeZone=Asia/Shanghai";
      String user = "root";
      String psw = "123456"
      con = DriverManage.getConnection(url,user,psw);
      prepareStatement = con.prepareStatement(sql);
      prepareStatement.setInt(1,stu.getInt);
      prepareStatement.setString(2,stu.getName);
      prepareStatement.setInt(3,stu.getAge);
      prepareStatement.execute();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      try{
       if(prepareStatement!=null){
          prepareStatement.close();
       }
    }catch(SQLException e){
       e.printStackTrace();
    }
     
  }
/* 
   由于每个操作方法中都会有设置预编译语句的操作
   这些逻辑是重复的,不同的只是每个方法sql不同
   即可以写一个RunSQL类
   当中的方法是专门处理这些的固定模板
   故只需要用相同的方法传入不同的sql语句和不同的参数
   之前要写20行的代码,下面就只需要两行
*/
  @Override
  public void update(int id,Student stu) {
    String sql = "update student set name = ?,age = ? where id = ?";
    RunSQL.update(sql, stu.getName(), stu.getAge(), id);
  }

  @Override
  public void delete(int id) {
    String sql = "delete from student where id = ?";
    RunSQL.update(sql, id);
  }

  @Override
  public List<Student> get(int id) {
    String sql = "select * from student where id = ?";
    return RunSQL.query(sql, id);
  }

  @Override
  public List<Student> getAll() {
    String sql = "select * from student";
    return RunSQL.query(sql);
  }
}

上面使用的工具类

模板工具类:

RunSQL用来执行语句的模板

代码语言:javascript
复制
public class RunSQL {
  /* 此类只是负责执行语句逻辑的模板,
   每次执行语句需要加载驱动,创建连接,还有关闭资源
   也就是说下面两个方法都需要去写重复的这些无关步骤而且很长
   故可以封装一个类专门管连接和关闭,下面用的Database类就是
 */
  public static void update(String sql,Object...x) {
    Connection con = null;
    PreparedStatement prepareStatement = null;
    try {
      con = Database.getConnection();// 获取连接对象
      /*
       Class.forName("com.mysql.cj.jdbc.Driver");
       String url = "jdbc:mysql://localhost:3306/mydb?serverTimeZone=Asia/Shanghai";
       String user = "root";
       String psw = "123456"
       con = DriverManage.getConnection(url,user,psw);
      */
      prepareStatement = con.prepareStatement(sql);
      for(int i = 0;i < x.length; i++) {
        prepareStatement.setObject(i+1,x[i]);      
      }
      prepareStatement.execute();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      Database.close(con, prepareStatement, null);// 关闭资源
    }
    
  }
  public static List query(String sql,Object...x) {
    Connection con = null;
    PreparedStatement sta = null;
    ResultSet re = null;
    List stulist = new ArrayList();
    try {
      con = Database.getConnection();// 获取连接,由专门的类来执行减少大量的重复
      sta = con.prepareStatement(sql);
      for(int i = 0; i < x.length; i++) {
        sta.setObject(i+1,x[i]);
      }    
        re = sta.executeQuery();   
      while(re.next()){
        Student stu = new Student();
        stu.setInt(re.getInt("id"));
        stu.setString(re.getString("name"));
        stu.setInt(re.getInt("age"));
        stulist.add(stu);
      }
      return stulist;
    }catch (Exception e) {
      e.printStackTrace();
    }finally {
      Database.close(con, sta, re);// 同样还有关闭
    }
    
    return null;
  }
}

配置文件用来存储连接需要的信息,用连接池来读取它创建有限个连接对象

代码语言:javascript
复制
/* 创建propertise文件存储数据库连接信息(user,password,url) */

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai
username=root
password=123456

Database类用来得到连接对象,还有关闭资源。这些工作调用这个类的方法就可以。免得每次的操作都要写上创建连接,和一连串的关闭。通过连接池来创建优化了运行不用以重新新建的方式

代码语言:javascript
复制
public class Database {
  public static DataSource ds = null;
  static {
    try {
      Properties properties = new Properties();
      FileInputStream in = new FileInputStream("source/db.propertise");
      properties.load(in);
      ds = DruidDataSourceFactory.createDataSource(properties);    
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  public static Connection getConnection() {
    try {
      return ds.getConnection();
    }catch(Exception e) {
      e.printStackTrace();
    }
    return null;
  }
  
  public static void close(Connection con,Statement sta,ResultSet re) {
    if(re != null) {
      try {
        re.close();
      }catch (Exception e) {
        e.printStackTrace();
      }
    }
    if(sta != null) {
      try {
        sta.close();
      }catch (Exception e) {
        e.printStackTrace();
      }
    }
    if(con != null) {
      try {
        con.close();
      }catch (Exception e) {
      e.printStackTrace();
      }
    }    
  }
}

总结

虽然通过上述构造了一些DAO还有一些工具类,但是有一个大的问题,在RunSQL的query方法中“去遍历结果集把每条记录变成一个一个对象再存到列表当中”这个过程当中是我们知道Student类中或者表中就是这三个属性。我们新建student对象并给其属性设值,这都是写好了。如果来个课程表写个课程的domain类它里面是另外三个属性(课程,姓名 ,学号)。这样就用不了RunSQL

代码语言:javascript
复制
 while(re.next()){
        Student stu = new Student();
        stu.setInt(re.getInt("id"));
        stu.setString(re.getString("name"));
        stu.setInt(re.getInt("age"));
        stulist.add(stu);
}

要做到通用,首先

执行语句之后得到的结果集,并不知道有几列也不知道字段名

先创建一个Object对象(不知道是哪个domain,即哪个domain都可以用)

给这个未知对象设置属性:

怎么知道它这个结果集的列名

只有知道列字段名才能得到这个字段的值re.getObject("字段名")

才能给这个对象对应的属性设值obj.setObject(re.getObject)

在写设计domain类时,每个属性名与对列名相同

那么问题就转化为怎么获取一个domain类的属性名

这样的话就可以用内省的方式解决

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT那个小笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档