ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JDBC应用

2022-08-28 13:00:51  阅读:223  来源: 互联网

标签:JDBC public Connection 应用 sql null id conn


JDBC应用

记录JDBC的学习笔记,为后期使用JDBC建立一个简单的速查页面,省去中间的推导等

池: Druid

DBUtil: Apache Commons DbUtils

也作为八股文的速查

数据库连接的基本步骤

以 Druid 连接池包为例,读取 /src/druid.properties 并建立 DataSource

  1. 准备配置文件

    与硬编码解耦合

    1. 配置文件(properties为例) -- 通常包含四个基本信息
      url, username, password, driverClassName

      (不同连接池工具的命名方式不一致,以Druid为例)

      url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&rewriteBatchedStatements=true
      driverClassName=com.mysql.cj.jdbc.Driver
      username=root
      password=root
      initialSize=10
      maxActive=10
      
  2. 读取配置文件

    1. 通常使用 Properties + InputStream
      (以 /src/druid.properties为例)

      private static DataSource source = null;
      /* 工具类的静态代码块,在类加载时读取配置并生成 DataSource */
      static {
          try {
              Properties pros = new Properties();
              /* 这里是一种读取方式 */
              InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
              pros.load(is);
              // DruidDataSourceFactory 读取配置并返回 DataSource对象
              source = DruidDataSourceFactory.createDataSource(pros);
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
      /* 工具类提供获取 DataSource 的方法 */
      public static DataSource getSource() {
          return source;
      }
      
  3. 获取连接 Connection

    public static Connection getConnection() throws SQLException {
        return source.getConnection();
    }
    
  4. 关闭资源
    Connection, Statement, ResultSet

    /* 重载closeResource */
    public static void closeResource(Connection conn, Statement ps) {
        closeResource(conn, ps, null);
    }
    /* 重载closeResource */
    public static void closeResource(Connection conn, Statement ps, ResultSet rs) {
        // 关闭资源
        try {
            if (ps != null)  ps.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null) conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (rs != null) rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    

ORM 编写 对象类和 DAO

ORM

Object Relational Mapping,简称ORM,以将数据库表中查询记录封装为类对象(称为Bean),便于编程语言操作。

例如表如下

Field Type Null Key Default Extra
id int NO PRI NULL auto_increment
name varchar(15) YES NULL
email varchar(20) YES NULL
birth date YES NULL
photo mediumblob YES NULL

Bean

Bean中变量命的命名与SQL中有区别,并且表中请不要使用SQL已有的字段如 order 命名,例如(命名不一致的应使用别名)

select first_name as firstName from yourtable;

SQL Col Name Bean Field Name
first_name firstName
last_find_time lastFindTime
close_time closeTime
import java.sql.Date;

public class Customer {
    private int id;
    private String name;
    private String email;
    private Date birth;

    /* constructor */
    public Customer() {super();}
    public Customer(int id, String name, String email, Date birth) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.birth = birth;
    }

    /* getter setter */
    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 String getEmail() {return email;}
    public void setEmail(String email) {this.email = email;}
    public Date getBirth() {return birth;}
    public void setBirth(Date birth) {this.birth = birth;}

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", birth=" + birth +
                '}';
    }
    /* 省略 equals & hashCode */
}

DAO

data access object

DAO是和数据库的某一张表一一对应的,其中封装了增删改查基本等原子操作

通常建立如下的继承关系结构

(抽象类, 无抽象方法, 定义通用的增删改查操作, 多数工具包已经提供) BaseDAO
(接口, 定义对应表的原子操作) CustomerDAO
(实现类) CustomerDAOImpl extends BaseDAO implements CustomerDAO

BaseDAO

/**
 * DAO: data(base) access object
 * java代码操作数据库表的基本方法
 */
public abstract class BaseDAO {
    /**
     * SQL中占位符的数量应当与args形参列表的数目一致
     * @param conn 传入的SQL 连接, 本方法不会关闭 conn连接
     * @param sql SQL
     * @param args 形参列表
     * @return 表中改动的条目数
     */
    public int update(Connection conn, String sql, Object ... args) {
        int query = 0;
        QueryRunner queryRunner = null;
        
        try {
            queryRunner = new QueryRunner();
            query = queryRunner.update(conn, sql, args);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.closeResource(null, null);
        }
        return query;
    }

    /**
     * 针对不同表的通用查询操作,返回一条查询记录
     * @param conn sql连接
     * @param clazz 要返回的对象 T.class
     * @param sql sql语句
     * @param args sql语句的补充参数
     * @return 返回一个 T 对象
     * @param <T> 返回对象的类型
     */
    public <T> T getInstance(Connection conn, Class<T> clazz, String sql, Object...args)  {
        T query = null;
        QueryRunner queryRunner = null;
        BeanHandler<T> beanHandler = null;
        try {
            queryRunner = new QueryRunner();
            beanHandler = new BeanHandler<>(clazz);
            query = queryRunner.query(conn, sql, beanHandler, args);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            // 迷惑操作, 步骤得有
            JDBCUtils.closeResource(null, null, null);
        }
        return query;
    }

    /**
     * 针对不同表的通用查询操作,返回查询集合
     * @param conn sql连接
     * @param clazz 要返回的对象 T.class
     * @param sql sql语句
     * @param args sql语句的补充参数
     * @return 返回一个 List<T> 对象
     * @param <T> 返回对象的类型
     */
    public <T> List<T> getForList(Connection conn, Class<T> clazz, String sql, Object...args) {

        BeanListHandler<T> beanListHandler = null;
        QueryRunner queryRunner = null;
        List<T> query = null;

        try {
            beanListHandler = new BeanListHandler<>(clazz);
            queryRunner = new QueryRunner();
            query = queryRunner.query(conn, sql, beanListHandler, args);
        } catch (SQLException  | SecurityException |
                 IllegalArgumentException  e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.closeResource(null, null, null);
        }
        return query;

    }


    /**
     * 允许 SQL 中使用 count(*)\ max(col) 等组函数
     * @param conn  sql连接
     * @param sql  sql语句
     * @param args  sql语句的补充参数
     * @return 返回查询值
     * @param <E> 返回值的类型
     */
    public <E> E getValue(Connection conn, String sql, Object...args) {
        E query = null;
        QueryRunner queryRunner = null;
        ScalarHandler scalarHandler = new ScalarHandler();

        try {
            queryRunner = new QueryRunner();
            query = (E)queryRunner.query(conn, sql, scalarHandler);
        } catch (SQLException ex) {
            throw new RuntimeException(ex);
        } finally {
            JDBCUtils.closeResource(null, null, null);
        }

        return query;
    }
}

CustomerDAO

public interface CustomerDAO {
    /**
     * 将 customer 添加到数据表中
     * @param conn sql连接
     * @param customer 待添加的 Customer 对象
     */
    void inset(Connection conn, Customer customer);

    /**
     * 根据指定的id删除一条记录
     * @param conn sql连接
     * @param id 待删除的id
     */
    void deleteById(Connection conn, int id);

    /**
     * 针对于内存中的 Customer 对象, 去修改 id=customer.id 的记录
     * @param conn sql连接
     * @param customer 内存中的 Customer 对象
     */
    void updateById(Connection conn, Customer customer);

    /**
     * 根据指定的id, 查询对应的 Customer
     * @param conn sql连接
     * @param id 待查找的id
     * @return Customer对象
     */
    Customer getCustomerById(Connection conn, int id);

    /**
     * 查询表中所有记录
     * @param conn sql连接
     * @return List<Customer>对象
     */
    List<Customer> getAll(Connection conn);

    /**
     *
     * 返回表的条目数
     * @param conn sql连接
     * @return 条目数
     */
    Long getCount(Connection conn);

    /**
     * 返回数据表中的最大生日
     * @param conn sql连接
     * @return java.sql.Date 最大生日
     */
    Date getMaxBirth(Connection conn);
}

CustomerDAOImpl

public class CustomerDAOImpl extends BaseDAO implements CustomerDAO {
    @Override
    public void inset(Connection conn, Customer customer) {
        String sql = "insert into customers(name, email, birth) values (?,?,?)";
        update(conn, sql, customer.getName(), customer.getEmail(), customer.getBirth());
    }

    @Override
    public void deleteById(Connection conn, int id) {
        String sql = "delete from customers where id = ?";
        update(conn, sql, id);
    }

    @Override
    public void updateById(Connection conn, Customer customer) {
        String sql = "update customers set name=?, email=?, birth=? where id=?";
        update(conn, sql, customer.getName(), customer.getEmail(), customer.getBirth(), customer.getId());
    }

    @Override
    public Customer getCustomerById(Connection conn, int id) {
        String sql = "select id, name, email, birth from customers where id = ?";
        return getInstance(conn, Customer.class, sql, id);
    }

    @Override
    public List<Customer> getAll(Connection conn) {
        String sql = "select id, name, email, birth from customers";
        return getForList(conn, Customer.class, sql);
    }

    @Override
    public Long getCount(Connection conn) {
        String sql = "select count(*) from customers";
        return getValue(conn, sql);
    }

    @Override
    public Date getMaxBirth(Connection conn) {
        String sql = "select max(birth) from customers";
        return getValue(conn, sql);
    }
}

测试用例

import org.junit.jupiter.api.Test;

class CustomerDAOImplTest {
    private CustomerDAOImpl dao = new CustomerDAOImpl();

    @Test
    void inset() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            java.util.Date date = simpleDateFormat.parse("2022-08-26");
            Customer customer = new Customer(1, "猪鼻二号", "mewmew@cat.com", new Date(date.getTime()));

            dao.inset(conn, customer);

            System.out.println("添加成功");
        } catch (SQLException | ParseException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.closeResource(conn, null);
        }
    }

    @Test
    void deleteById() {
    }

    @Test
    void updateById() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            java.util.Date date = simpleDateFormat.parse("1914-01-17");
            Customer customer = new Customer(28, "猪鼻二号", "mewmewmew@cat.com", new Date(date.getTime()));

            dao.updateById(conn, customer);

            System.out.println("修改成功");
        } catch (SQLException | ParseException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.closeResource(conn, null);
        }
    }

    @Test
    void getCustomerById() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();

            Customer customer = dao.getCustomerById(conn, 28);

            System.out.println(customer);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.closeResource(conn, null);
        }
    }

    @Test
    void getAll() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();

            List<Customer> all = dao.getAll(conn);

            all.forEach(System.out::println);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.closeResource(conn, null);
        }
    }

    @Test
    void getCount() {

        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();

            Long count = dao.getCount(conn);

            System.out.println("表中的记录数为:" + count);
        } catch (SQLException  e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.closeResource(conn, null);
        }
    }

    @Test
    void getMaxBirth() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();

            Date maxBirth = dao.getMaxBirth(conn);

            System.out.println("表中最大的生日是:" + maxBirth);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.closeResource(conn, null);
        }
    }
}

注意事项

本文由于直接使用 Druid + Apache Commons DbUtils缩减代码量,java.sql 中两个重要的类

  • Statement/ PreparedStatement
  • ResultSet
  1. 其中 Statement 由于无法解决SQL 注入,并且每一次调用他都要验证一次 SQL 语句,不利于实际开发使用,因此多采用 PreparedStatement,获取方式为 ps = conn.prepareStatement(sql);

  2. PreparedStatement预编译了SQL语句,如

    String sql =  "select name, email from customers where name = ?";
    ps.setObject(1, "张学友");
    

    也即预编译一次,可以设置多次执行多次

    ResultSet rs = ps.executeQuery(); // 以查询为例, 也可以调用  ps.execute()
    
  3. ResultSet的获取方式见2,是一个集合,可通过获取每一行的数据

    // 处理结果集
    while (rs.next()) {
        int id = rs.getInt(1);         // id
        String name = rs.getString(2); // name
        String email = rs.getString(3);// email
        Date date = rs.getDate(4);     // birth
        Customer customer = new Customer(id, name, email, date);
        System.out.println(customer);
    }
    

总之,原生JDBC使用非常不便,前文中的DAO仅是列出了一张表的原子操作,如果多张表联查,复杂操作等,使用JDBC会非常麻烦

END~!

标签:JDBC,public,Connection,应用,sql,null,id,conn
来源: https://www.cnblogs.com/jentreywang/p/16632587.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有