抽取基本JDBC中的基本操作与数据连接池

 

1. JDBC

DBC(Java DataBase Connectivity) :Java数据库连接技术:具体讲就是通过Java连接广泛的数据库,并对表中数据执行增、删、改、查等操作的技术。JDBC是数据库与Java代码的桥梁。

JDBC中定义了操作数据库的各种接口和类型:

增删改基本操作:

(1)获取连接 :

Connection connection = DriverManager.getConnection(url, username, password);

(2)编写SQL语句:

String sql = "insert into user(...) values(...)";

String sql = "delete from user where id =...";

String sql = "update user set name = '' where name = ''"; 

(3)创建预处理命令对象:

PreparedStatement pst = connection .prepareStatement(sql);

(4)填充参数:

pst.setInt(1,4); //pst.setInt(1,user.getId);

pst.setString(2,"赵六"); //pst.setString(2,user.getName);

(5)执行更新:

pst.executeUpdate(); //返回受影响条数

(6)释放资源

try {
            if (rs != null) { //增删改操作无rs
                rs.close();
            } 
            if(psmt!=null){
                psmt.close();
            }
            if(conn!=null && !conn.isClosed()){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

查询基本操作:

(1)获取连接

(2)编写SQL语句

(3)创建预处理命令对象

(4)填充参数

(5)执行查询:ResultSet rs = pst.executeQuery(sql);

(6)解析结果集:

List<User> userList = new ArrayList<>();
while(rs.next()){
    int id = rs.getInt(1);
    String name = rs.getString(2);
    int age = rs.getInt(3);
    User user = new User(id,name,age);
    userList.add(user);
}

(7)释放资源

2. 抽取基本JDBC中的基本操作 - BaseDao

(1)获取连接

protected Connection getConn(){
    try {
        //1.加载驱动
        Class.forName(DRIVER);
        //2.通过驱动管理器获取连接对象
        return DriverManager.getConnection(URL, USER, PWD);
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
    return null ;
}

(2)释放连接

protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
    try {
        if (rs != null) {
            rs.close();
        }
        if(psmt!=null){
            psmt.close();
        }
        if(conn!=null && !conn.isClosed()){
            conn.close();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

(3)执行增删改操作,返回受影响数量

protected  int executeUpdate(String sql,Object...params){
    try {
        //获取连接
        conn = getConn();
        //创建预处理命令对象
        psmt = conn.prepareStatement(sql);
        //填充参数
        if(params!=null && params.length>0){
            for(int i = 0;i<params.length;i++){
                psmt.setObject(i+1,params[i]);
            }
        }
        //执行更新
        return psmt.executeUpdate();
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        close(rs,psmt,conn);
    }
    return 0;
}

(4)执行查询操作,返回查询的结果集

//执行查询,返回list
protected List<T> executeQuery(String sql , Object... params){
    List<T> list = new ArrayList<>();
    try {
        //获取连接
        conn = getConn();
        //创建预处理命令对象
        psmt = conn.prepareStatement(sql);
        //填充参数
        setParams(psmt,params);
        //执行查询
        rs = psmt.executeQuery();
        /*解析结果集
            考虑:
                1.【pst.setInt(1,user.getId);】第一列未必是int类型;
                2. 列数不确定;
                3. 封装数据时不知道具体的类的实例对象,无法封装
            解决:
                1. 列表中指定类,使用泛型 List<T>,在继承该类时指明类型传过来,该类名改为BaseDao<T>
                2. 获取传过来的T的类型
                   (1)获取T的Class对象 entityClass
                    (2) 创建实例对象 entityClass.newInstance();
                    (3) 给entity中的所有属性赋值 通过反射技术 setValue 方法
         */
        //通过rs可以获取结果集中的元数据(元数据:描述结果集数据的数据,结果集中有哪些列,什么类型...)
        ResultSetMetaData rsmd = rs.getMetaData();
        //获取结果集的列数
        int columnCount = rsmd.getColumnCount();
        while(rs.next()){
            T entity = (T)entityClass.newInstance();
            //要将 columnValue 的值赋给 entity 对象的 columnName 属性
            for (int i = 0; i < columnCount; i++) {
                String columnName = rsmd.getColumnName(i + 1);//获取列的名字   id
                Object columnValue = rs.getObject(i + 1);//给每一列赋值        001
                setValue(entity,columnName,columnValue);
            }
            list.add(entity);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } finally {
        close(rs,psmt,conn);
    }
    return list;
}

    //提取给预处理对象设置参数的方法
    private void setParams(PreparedStatement psmt , Object...params) throws SQLException {
         if(params!=null && params.length>0){
            for(int i = 0;i<params.length;i++){
                psmt.setObject(i+1,params[i]);
            }
        }
    }

    //通过反射技术给Obj对象的property属性赋propertyValue值
    private void setValue(Object obj,String property,Object propertyValue){//对象,属性,属性值
        Class clazz = obj.getClass(); //获取Class对象
        try {//获取 property 字符串对应的属性名,如"id"去找obj对象中的 id 属性
            Field field = clazz.getDeclaredField(property);
            if(field!=null){
                field.setAccessible(true); //强制访问
                field.set(obj,propertyValue); //设置obj对象的field属性的值为propertyValue
            }
        } catch (NoSuchFieldException | IllegalAccessException e ) {
            e.printStackTrace();
        }
    }

(5)执行查询,返回单个实体对象

//执行查询,返回单个实体对象
protected T load(String sql , Object... params){
    try {
        conn = getConn() ;
        psmt = conn.prepareStatement(sql);
        setParams(psmt,params);
        rs = psmt.executeQuery();
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();
        if(rs.next()){
            T entity = (T)entityClass.newInstance();

            for(int i = 0 ; i<columnCount;i++){
                String columnName = rsmd.getColumnName(i+1);
                Object columnValue = rs.getObject(i+1);     
                setValue(entity,columnName,columnValue);
            }
            return entity ;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } finally {
        close(rs,psmt,conn);
    }
    return null ;
}

 (6)执行复杂查询,返回例如统计结果

protected Object[] executeComplexQuery(String sql , Object... params){
        try {
            conn = getConn() ;
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            rs = psmt.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            //获取结果集的列数
            int columnCount = rsmd.getColumnCount();
            Object[] columnValueArr = new Object[columnCount];
          
            if(rs.next()){
                for(int i = 0 ; i<columnCount;i++){
                    Object columnValue = rs.getObject(i+1); 
                    columnValueArr[i]=columnValue;
                }
                return columnValueArr ;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rs,psmt,conn);
        }
        return null ;
    }

(7)在添加操作时,获取自增列的值

-----如何获取-----(先判断是否是添加操作)-----

A. 创建pamt时,设置第二个参数

 psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);

B. 执行完更新之后,再去获取结果集,结果集中就包含了自增列的值

psmt.executeUpdate() ;

ResultSet rs = psmt.getGeneratedKeys();

Long id = rs.getLong(1);//再转为int

修改更新操作

protected  int executeUpdate(String sql,Object...params){
    boolean insertFlag = false;
    insertFlag = sql.trim().toUpperCase().startsWith("INSERT"); //如果sql语句是以“insert”开头
    try {
        //获取连接
        conn = getConn();
        if(insertFlag == true){ //创建预处理命令对象方式不一样
            //创建预处理命令对象
            psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
        }
        else{
            psmt = conn.prepareStatement(sql);
        }
        //填充参数
        setParams(psmt,params);
        //执行更新
        int count = psmt.executeUpdate();
        rs = psmt.getGeneratedKeys();
        if(rs.next()){
            //如果是删除、修改操作,返回受影响行数,如果是添加操作,返回的是自增列的值
            return ((Long) rs.getLong(1)).intValue();
        }
        return count;

    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        close(rs,psmt,conn);
    }
    return 0;
}

BaseDAO类:

public abstract class BaseDAO<T> {
    public final String DRIVER = "com.mysql.jdbc.Driver" ;
    public final String URL = "jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false";
    public final String USER = "root";
    public final String PWD = "123456" ;

    protected Connection conn ;
    protected PreparedStatement psmt ;
    protected ResultSet rs ;

    //T的Class对象
    private Class entityClass ;

    public BaseDAO(){
        //getClass() 获取Class对象,当前我们执行的是new FruitDAOImpl() , 创建的是FruitDAOImpl的实例
        //那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
        //因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
        //所以getGenericSuperclass()获取到的是BaseDAO的Class
        Type genericType = getClass().getGenericSuperclass();
        //ParameterizedType 参数化类型
        Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
        //获取到的<T>中的T的真实的类型
        Type actualType = actualTypeArguments[0];
        try {
            entityClass = Class.forName(actualType.getTypeName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    protected Connection getConn(){
        try {
            //1.加载驱动
            Class.forName(DRIVER);
            //2.通过驱动管理器获取连接对象
            return DriverManager.getConnection(URL, USER, PWD);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return null ;
    }

    protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
        try {
            if (rs != null) {
                rs.close();
            }
            if(psmt!=null){
                psmt.close();
            }
            if(conn!=null && !conn.isClosed()){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //给预处理命令对象设置参数
    private void setParams(PreparedStatement psmt , Object... params) throws SQLException {
        if(params!=null && params.length>0){
            for (int i = 0; i < params.length; i++) {
                psmt.setObject(i+1,params[i]);
            }
        }
    }

    //执行更新,返回影响行数
    protected int executeUpdate(String sql , Object... params){  //不定参数
        boolean insertFlag = false ;
        insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
        try {
            conn = getConn(); //创建连接
            if(insertFlag){
                psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            }else {
                psmt = conn.prepareStatement(sql);
            }
            setParams(psmt,params);
            int count = psmt.executeUpdate() ;

            if(insertFlag){
                rs = psmt.getGeneratedKeys();
                if(rs.next()){
                    return ((Long)rs.getLong(1)).intValue();
                }
            }
            return count ;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(rs,psmt,conn);
        }
        return 0;
    }

    //通过反射技术给obj对象的property属性赋propertyValue值
    private void setValue(Object obj ,  String property , Object propertyValue){
        Class clazz = obj.getClass();
        try {
            //获取property这个字符串对应的属性名 , 比如 "fid"  去找 obj对象中的 fid 属性
            Field field = clazz.getDeclaredField(property);
            if(field!=null){
                field.setAccessible(true);
                field.set(obj,propertyValue);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    //执行复杂查询,返回例如统计结果
    protected Object[] executeComplexQuery(String sql , Object... params){
        try {
            conn = getConn() ;
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            rs = psmt.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等

            ResultSetMetaData rsmd = rs.getMetaData();
            //获取结果集的列数
            int columnCount = rsmd.getColumnCount();
            Object[] columnValueArr = new Object[columnCount];
            //6.解析rs
            if(rs.next()){
                for(int i = 0 ; i<columnCount;i++){
                    Object columnValue = rs.getObject(i+1);     //33    苹果      5
                    columnValueArr[i]=columnValue;
                }
                return columnValueArr ;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rs,psmt,conn);
        }
        return null ;
    }

    //执行查询,返回单个实体对象
    protected T load(String sql , Object... params){
        try {
            conn = getConn() ;
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            rs = psmt.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等

            ResultSetMetaData rsmd = rs.getMetaData();
            //获取结果集的列数
            int columnCount = rsmd.getColumnCount();
            //6.解析rs
            if(rs.next()){
                T entity = (T)entityClass.newInstance();

                for(int i = 0 ; i<columnCount;i++){
                    String columnName = rsmd.getColumnName(i+1);            //fid   fname   price
                    Object columnValue = rs.getObject(i+1);     //33    苹果      5
                    setValue(entity,columnName,columnValue);
                }
                return entity ;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } finally {
            close(rs,psmt,conn);
        }
        return null ;
    }


    //执行查询,返回List
    protected List<T> executeQuery(String sql , Object... params){
        List<T> list = new ArrayList<>();
        try {
            conn = getConn() ;
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            rs = psmt.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等

            ResultSetMetaData rsmd = rs.getMetaData();
            //获取结果集的列数
            int columnCount = rsmd.getColumnCount();
            //6.解析rs
            while(rs.next()){
                T entity = (T)entityClass.newInstance();

                for(int i = 0 ; i<columnCount;i++){
                    String columnName = rsmd.getColumnName(i+1);            //fid   fname   price
                    Object columnValue = rs.getObject(i+1);     //33    苹果      5
                    setValue(entity,columnName,columnValue);
                }
                list.add(entity);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } finally {
            close(rs,psmt,conn);
        }
        return list ;
    }
}

3. 执行批处理

psmt.addBatch(); //添加批处理任务
psmt.executeBatch(); //执行批处理任务
psmt.clearBatch(); //清空批处理任务

 在url中添加参数  rewriteBatchedStatements=true

4. 数据源连接池

(每次调用basedao,用的时候去获取连接,效率偏低。

采取方式:在程序运行的时候先准备几个连接对象,要用的时候在连接池中取,用完后归还。

响应时间更快,对象利用率更高)

Druid 德鲁伊

(1)加入jar包:druid-1.1.10.jar

(2)代码步骤

  A. 建立一个连接池

  B. 设置连接池参数

  C. 获取连接

public class Demo01Druid {
    public static void main(String[] args) throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false");
        dataSource.setName("root");
        dataSource.setPassword("123456");
        //1.被close的连接对象并没有真正关闭,而是将连接状态重新设置为空闲状态,然后放回池子,这样下次获取连接池,这个对象会被重复使用。
        //2. 没有被close的连接对象会被一直占有,下次获取连接对象时,不会获取到这个对象。
        Connection connection = dataSource.getConnection();
        connection.close();

    }
}

读取外部的配置文件设置连接池

public class Demo02Druid {
    public static void main(String[] args) throws SQLException, IOException {

        Properties properties = new Properties();
        InputStream is = Demo02Druid.class.getClass().getClassLoader().getResourceAsStream("jdbc.properties");
        properties.load(is);
        
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(properties.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(properties.getProperty("jdbc.url"));
        dataSource.setName(properties.getProperty("jdbc.username"));
        dataSource.setPassword(properties.getProperty("jdbc.pwd"));
        dataSource.setInitialSize(Integer.parseInt(properties.getProperty("jdbc.initSize"))); //初始化连接池中的连接数量
        dataSource.setMaxActive(Integer.parseInt(properties.getProperty("jdbc.maxActive"))); //最大连接数量
        dataSource.setMaxWait(Integer.parseInt(properties.getProperty("jdbc.maxWait"))); //最长等待连接时间
        
        Connection connection = dataSource.getConnection();
        connection.close();
    }
}

jdbc.properties

jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username = root
jdbc.pwd = 123456
jdbc.initSize = 2
jdbc.maxActive = 5
jdbc.maxWait = 5000

Druid直接导入properties

public class Demo03Druid {
    public static void main(String[] args) throws Exception {

        Properties properties = new Properties();
        InputStream is = Demo03Druid.class.getClass().getClassLoader().getResourceAsStream("jdbc2.properties");
        properties.load(is);

        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        Connection connection = dataSource.getConnection();
        connection.close();
    }
}

 jdbc2.propertise

driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false
username = root
password = 123456
initialSize = 2
maxActive = 5
maxWait = 5000

相关文章

连接数据库的方式:第一种方式:ODBC:开放数据库连接是微软...
JDBCRequest 使用VariableNamesmysql:数据库连接池对象var...
 1.JDBCDBC(JavaDataBaseConnectivity):Java数据库连接技术...
1.需要jar包的支持:java.sqljavax.sqlmysql-conneter-java....
1.简介Activiti是一个业务流程管理(BPM)框架,它是覆盖了业务...
1.JDBC体系系统一组规范:接口JDBC接口(API)包括两个层次:...