java | (二十)JDBC (1)概述、JDBC实现增删改查

常用api

请添加图片描述

数据库连接配置

URL:连接数据库系统资源描述符
DriverClass:数据库系统驱动类名称
UserName:登录数据库系统用户名称
Password:登录数据库系统用户密码

数据库连接信息通常以普通文本属性文件进行配置dbconf.properties
创建属性文件
在这里插入图片描述

## 数据库属性配置信息
jdbc_url = jdbc:oracle:thin:@127.0.0.1:1521:orcl
jdbc_driver = oracle.jdbc.driver.OracleDriver
jdbc_system = system
jdbc_password = system

读取这个文件

package com.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public final class Env extends Properties {
    public static final String JDBC_URL;
    public static final String JDBC_DRIVER;
    public static final String JDBC_USER;
    public static final String JDBC_PASSWORD;

    private static final String CONF_FILE="com/conf/dbconf.properties";
    private static Env env;

    static{
        if(env == null){
            env = new Env();//加载文件流
        }
        /*获取指向文件的输入流*/
        InputStream in = env.getClass().getClassLoader().getResourceAsStream(CONF_FILE);
        try {
            env.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        JDBC_URL = env.getProperty("jdbc_url");
        JDBC_DRIVER = env.getProperty("jdbc_driver");
        JDBC_USER = env.getProperty("jdbc_system");
        JDBC_PASSWORD = env.getProperty("jdbc_password");
    }
    private Env(){

    }

    public static void main(String[] args) {
        System.out.println(Env.JDBC_DRIVER);
        System.out.println(Env.JDBC_PASSWORD);
        System.out.println(Env.JDBC_URL);
        System.out.println(Env.JDBC_USER);
        /*oracle.jdbc.driver.OracleDriver
        system
        jdbc:oracle:thin:@127.0.0.1:1521:orcl
        system
         */
    }
}

建立数据源管理组件

package com.util;

import java.sql.*;

/*数据源管理组件,提供最基本的通用数据库链接*/
public final class DateSourceManager {
    /*提供目标数据源的连接通用方法*/
    public static Connection getConnection(){
        Connection conn = null;

        try {
            //加载数据库驱动
            Class.forName(Env.JDBC_DRIVER);
            conn = DriverManager.getConnection(Env.JDBC_URL,Env.JDBC_USER,Env.JDBC_PASSWORD);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    /*关闭数据库连接的通用方法*/
    public static void close(Connection conn){
        try {
            if(conn != null && !conn.isClosed()){ //如果不是空且灭有断开
                conn.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    public static void close(Statement state){
        try {
            if(state != null && !state.isClosed()){
                state.close();
            }
        }catch (SQLException e){
            e.printStackTrace();
        }
    }

    public static void close(ResultSet set){
        try {
            if(set != null && !set.isClosed()){
                set.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

编写DAO数据处理组件

定义更新,删除,添加、查询功能
先给出相关的java类

package com.pojo;
/*映射部门信息*/
public class Department {
    
    
    private int id;//部门id
    private String name;//部门名称

    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;
    }
}

类的相关文件存入pojo文件夹中
在这里插入图片描述

添加数据

package com.dao;

import com.pojo.Department;
import com.util.DateSourceManager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/*数据访问组件,实现增删改查操作*/
public class DeptDao {
    
    
    public int addDepartment(Department dep){
    
    
        int res = 0;
        String sql = "insert into dep values(?,?) ";
        Connection conn = DateSourceManager.getConnection();//获取数据库链接
        PreparedStatement ps = null;
        try {
    
    
            ps = conn.prepareStatement(sql);//获取prepareStatement对象
            /*设置替换sql语句中参数占位符 ? */
            ps.setString(1,dep.getName());
            ps.setString(2,String.valueOf(dep.getId()));
            res = ps.executeUpdate();//数据更新
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }finally{
    
    
            DateSourceManager.close(ps);
            DateSourceManager.close(conn);
        }
        return res;
    }
}

测试:

package com.test;

import com.dao.DeptDao;
import com.pojo.Department;

public class testDepDao {
    
    
    public static void main(String[] args) {
    
    
        Department dep1 = new Department();
        dep1.setId(7);
        dep1.setName("摸鱼部");
        DeptDao dDao = new DeptDao();
        int res = dDao.addDepartment(dep1);
        System.out.println("影响数据库表中的行数是:" + res);//影响数据库表中的行数是:1
    }

}

在运行测试时,出现了java.sql.SQLRecoverableException: IO 错误: Undefined Error
根据这条链接解决
结果:
在这里插入图片描述

修改数据

    /*修改选定 部门对象*/
    public int modifyDepartment(Department dep){
    
    
        int res = 0;
        String sql = "update dep set dep_name=? where id = ?";
        Connection conn = DateSourceManager.getConnection();
        PreparedStatement ps = null;
        try {
    
    
            ps = conn.prepareStatement(sql);
            ps.setString(1,dep.getName());
            ps.setString(2,String.valueOf(dep.getId()));
            res = ps.executeUpdate();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            DateSourceManager.close(ps);
            DateSourceManager.close(conn);

        }
        return res;
    }
        /*测试修改数据*/
        Department dep2 = new Department();
        dep2.setName("生活部");
        dep2.setId(2);
        int res2 = dDao.modifyDepartment(dep2);
        System.out.println(res2);

结果:
在这里插入图片描述
删除数据

    /*根据部门id删除部门*/
    public int deleteDepartmentById(String id){
    
    
        int res = 0;
        String sql = "delete from dep where id = '" + id + "'";
        Connection conn = DateSourceManager.getConnection();
        PreparedStatement ps = null;
        try{
    
    
            ps = conn.prepareStatement(sql);
            //执行删除操作
            res = ps.executeUpdate();
        }catch (SQLException e){
    
    
            e.printStackTrace();
        }finally {
    
    
            DateSourceManager.close(ps);
            DateSourceManager.close(conn);
        }
        return res;
    }
}
        new DeptDao().deleteDepartmentById("7");

结果(把id为7的删除了)
在这里插入图片描述

查找数据

Java.sql.ResultSet接口是jdbcAPI中唯一用来封装查询结果记录行的组件,ResultSet接口唯一创建方式是通过执行SQL查询返回创建此对象

   /*查询获取部门所有列表*/
    public List<Department> queryDepartmentList(){
    
    
        List<Department> depList = new ArrayList<Department>();
        String sql = "select id,dep_name from dep";//可以根据数据库跟着写
        Connection conn = DateSourceManager.getConnection();
        PreparedStatement ps = null;
        ResultSet set = null;
        try {
    
    
            ps = conn.prepareStatement(sql);
            set = ps.executeQuery();//注意这里是exexuteQuery提交查询
            /*处理结果集,封装成对象*/
            while (set.next()) {
    
    
                Department dep = new Department();
                String idTemp = set.getString(1);//获取部门id
                dep.setId(Integer.parseInt(idTemp));
                dep.setName(set.getString(2));//获取部门名称
                depList.add(dep);
            }
        }catch (SQLException e){
    
    
            e.printStackTrace();
        }finally {
    
    
            DateSourceManager.close(set);
            DateSourceManager.close(ps);
            DateSourceManager.close(conn);
        }
        return depList;
    }
package com.test;

import com.dao.DeptDao;
import com.pojo.Department;

import java.util.ArrayList;

public class baseQureyTest {
    
    
    public static void main(String[] args) {
    
    
        //测试查询结果
        ArrayList<Department> depList = (ArrayList)new DeptDao().queryDepartmentList();
        for(Department dep:depList){
    
    
            System.out.println("id:" + dep.getId() + ",name" + dep.getName());
        }
    }
}

结果:
在这里插入图片描述

连接池

这里使用了c3p0的,连接池有很多,在网上下载jar包后使用

package com.util;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public final class DataSourceForPool {
    
    
    private static ComboPooledDataSource c3p0;
    public static void createComboPooledDateSource(){
    
    
        if(c3p0 == null){
    
    
            c3p0 = new ComboPooledDataSource();
        }
        /*数据源相关属性*/
        try {
    
    
            c3p0.setDriverClass(Env.JDBC_DRIVER);
            c3p0.setUser(Env.JDBC_USER);
            c3p0.setPassword(Env.JDBC_PASSWORD);
            c3p0.setJdbcUrl(Env.JDBC_URL);
            c3p0.setCheckoutTimeout(3000);/*设置超时时间*/
            c3p0.setDataSourceName("c3p0DateSource");/*设置名称*/
            c3p0.setMaxPoolSize(30);/*最大池数量*/

        }catch(PropertyVetoException e){
    
    
            e.printStackTrace();
        }
    }

    public static Connection getConnection(){
    
    
        Connection conn = null;
        createComboPooledDateSource();//创建数据源
        try {
    
    
            conn = c3p0.getConnection();//由数据源获取一个打开的链接
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }
        return conn;
    }

    /*以下方法跟DateSourceManager一致*/
    /*关闭数据库连接的通用方法*/
    public static void close(Connection conn){
    
    
        try {
    
    
            if(conn != null && !conn.isClosed()){
    
     //如果不是空且灭有断开
                conn.close();
            }
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }
    }

    public static void close(Statement state){
    
    
        try {
    
    
            if(state != null && !state.isClosed()){
    
    
                state.close();
            }
        }catch (SQLException e){
    
    
            e.printStackTrace();
        }
    }

    public static void close(ResultSet set){
    
    
        try {
    
    
            if(set != null && !set.isClosed()){
    
    
                set.close();
            }
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }
    }
}

上述代码的功能跟之前的DateSourceManager的功能大体一致,但使用c3p0可以更方便的设置

实现分组聚合统计查询(使用连接池的方式)

上一份代码写了连接池的相关类,这里开始使用
先贴出在数据库中的emp类和dep类
请添加图片描述

请添加图片描述
其中,emp.dep_id 和dep.id 是外键约束
我们要实现以下查询
在这里插入图片描述

    /*分组查询员工信息聚合*/
    public List<Map<String,Object>> queryListMap(){
    
    
        List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();

        String sql = "select dep.dep_name 部门名称,\n" +
                "e.dep_id 部门代号,\n" +
                "count(e.dep_id) 部门人数,\n" +
                "sum(e.salary) 部门所发薪水总数,\n" +
                "max(e.salary) 部门中最高工资 \n" +
                "from emp e \n" +
                "left join dep on dep.id = e.dep_id\n" +
                "group by e.dep_id,dep.dep_name";      //注意这个group by,因为left join,所以要加上dep_name
        Connection conn = DataSourceForPool.getConnection();
        PreparedStatement ps = null;
        ResultSet set = null;

        try {
    
    
            ps = conn.prepareStatement(sql);
            set = ps.executeQuery(); //返回查询ResultSet结果集对象

            while(set.next()){
    
    
                Map<String,Object> map = new HashMap<String, Object>();
                map.put("部门代号",set.getString("部门代号"));
                map.put("部门名称",set.getString("部门名称"));
                map.put("部门人数",set.getString("部门人数"));
                map.put("部门所发薪水总数",set.getString("部门所发薪水总数"));
                map.put("部门中最高工资",set.getInt("部门中最高工资"));
                list.add(map);
            }
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally{
    
    
            DataSourceForPool.close(set);
            DataSourceForPool.close(ps);
            DataSourceForPool.close(conn);
        }
        return list;
    }

测试

        List<Map<String, Object>> list = new DeptDao().queryListMap();
        for(Map map:list){
    
    
            /*查询结果懒得输了*/
            System.out.println(map.get("部门代号"));
        }

结果:
在这里插入图片描述

分页查询

    /*分页查询显示员工薪水记录*/
    public Map<String,Object> querySalaryByPaging(int pageNum,int pageSize){
    
    
        Map<String,Object> map = new HashMap<String, Object>();
        Connection conn = DateSourceForPool.getConnection();
        PreparedStatement ps2 = null; //执行查询统计条目数
        PreparedStatement ps3 = null; //执行查询结果集
        ResultSet set2 = null;  // 封装统计条目的结果集
        ResultSet set3 = null;  // 封装统计查询结果集
        int rowCount = 0;
        int pageSum = 0;

        String rowcountSql = "select count(sid) rowcounts from emp";
        String pagingSql = "select e3.sid,e3.name,e3.address,e3.salary from\n" +
                "(select rownum rt,e2.* from emp e2 where rownum <= ?) e3\n" +
                "where e3.rt >= ?";
        try {
    
    
            //统计符合查询条件的总记录行数rowcounts
            ps2 = conn.prepareStatement(rowcountSql);
            set2 = ps2.executeQuery();
            while (set2.next()){
    
    
                rowCount = set2.getInt(1);
            }
            map.put("rowCount",rowCount);
            //统计总共分成多少页(总记录行数 / pageSize)
            pageSum = this.countPageSum(rowCount,pageSize);
            map.put("pageSum",pageSum);
            // 统计符合条件每页结果集
            ps3 = conn.prepareStatement(pagingSql);
            ps3.setInt(1,pageSize * pageNum);//设置第一个问好
            ps3.setInt(2,pageSize * pageNum - (pageNum - 1));//设置第二个?
            set3 = ps3.executeQuery();
            List<Map<String,Object>> rows = new ArrayList<Map<String, Object>>();
            while(set3.next()){
    
    
                Map<String,Object> rowMap = new HashMap<String,Object>();
                rowMap.put("sid",set3.getString("sid"));
                rowMap.put("name",set3.getString("name"));
                rowMap.put("address",set3.getString("address"));
                rowMap.put("salary",set3.getDouble("salary"));
                rows.add(rowMap);
            }
            map.put("rows",rows);
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally{
    
    
            DateSourceForPool.close(set2);
            DateSourceForPool.close(set3);
            DateSourceForPool.close(ps2);
            DateSourceForPool.close(ps3);
            DateSourceForPool.close(conn);
        }

        return map;
    }

    /*计算分成多少页的函数*/
    private int countPageSum(int rowCount,int pageSize){
    
    
        return rowCount % pageSize ==0 ? rowCount / pageSize : rowCount / pageSize + 1;
    }

package com.test;

import com.dao.DeptDao;

import java.util.List;
import java.util.Map;

public class testPaging {
    
    
    public static void main(String[] args) {
    
    
        //输入页码1     每页显示行数为5
        Map<String,Object> map = new DeptDao().querySalaryByPaging(1,6);
        Object rowCount = map.get("rowCount").toString();//符合条件记录总数
        System.out.println("符合条件记录总数:" + rowCount);

        List<Map<String,Object>> rows = (List<Map<String, Object>>) map.get("rows");
        for(Map<String,Object> row:rows){
    
    
            System.out.println(row.get("name"));
        }

    }
}

结果:
在这里插入图片描述

JDBC处理存储过程

JDBCAPI 中CallableStatement接口是唯一处理数据库系统存储过程的通用组件
例一
sql中的proc定义如下:

create or replace procedure pro_hello(username in out varchar2) as
hello string(4) := '你好';
begin
     username := hello || ' ' || username;
end pro_hello;

jdbc调用带输入输出的存储过程

    /*调用带输入输出的存储过程*/
    public String callProcedure(String name){
    
    
        String procName = "{call pro_hello(?)}";// 定义调用的过程及参数
        Connection conn = DateSourceForPool.getConnection();
        CallableStatement call = null;
        try {
    
    
            call = conn.prepareCall(procName);//创建callablestatement对象
            call.registerOutParameter(1, Types.VARCHAR);// 注册一个输出类型
            call.setString(1,name);//设置输入的参数值
            call.execute(); //调用存储过程
            name = call.getString(1);//获取输出类型参数值

        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally {
    
    
            DateSourceForPool.close(call);
            DateSourceForPool.close(conn);
        }

        return name;
    }
System.out.println(new DeptDao().callProcedure("张飞"));//hello 张飞

例二
SQL中一个返回查询表的函数

create or replace procedure pro_dep_info(dates out sys_refcursor)
as
begin
     open dates for select * from dep;
end pro_dep_info;

java代码

    /*存储过程返回表*/
    public List<Department> callProcedure2(){
        List<Department> list = new ArrayList<>();
        String procSql = "{call pro_dep_info(?)}";
        Connection conn = DateSourceForPool.getConnection();
        CallableStatement call = null;
        ResultSet rSet = null;
        try {
            call = conn.prepareCall(procSql);
            call.registerOutParameter(1, OracleTypes.CURSOR);//注册oracle游标类型,可以封装查询结果
            call.execute();
            rSet = (ResultSet) call.getObject(1);//返回输出类型
            while (rSet.next()){
                Department dep = new Department();
                dep.setId(Integer.parseInt(rSet.getString("id")));
                dep.setName(rSet.getString("dep_name"));
                list.add(dep);
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally{
            DateSourceForPool.close(rSet);
            DateSourceForPool.close(call);
            DateSourceForPool.close(conn);
        }

        return list;
    }

测试

        List<Department> list = new DeptDao().callProcedure2();
        for(Department d:list){
    
    
            System.out.println(d.getName());
        }

结果(返回部门名称):
在这里插入图片描述

数据库批量操作

批处理(Batch proces)是指一次连接访问数据中发送一组SQL操作语句,通常对数据库多条数据行进行更新操作。
一般执行批量修改、批量删除、批量插入

在数据库中新建了一个person表,暂时为空,在java中建立相关类如下:
在这里插入图片描述
建立PersonDao类进行数据库批量插入处理

package com.dao;

import com.pojo.Person;
import com.util.DateSourceForPool;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;

public class PersonDao {
    
    
    /*实现批处理插入数据*/
    public void testButchInsert(List<Person> list){
    
    
        String sql = "insert into person values(?,?,?,?)";
        Connection conn = DateSourceForPool.getConnection();
        try {
    
    
            PreparedStatement ps = conn.prepareStatement(sql);
            for(Person p:list){
    
    
                ps.setString(1,p.getId());
                ps.setString(2,p.getName());
                ps.setString(3,p.getSex());
                ps.setInt(4,p.getAge());
                /*将以上设置添加到批处理命令中*/
                ps.addBatch();
            }
            /*提交批处理命令,提交数据库执行sql操作*/
            int[] res = ps.executeBatch();//返回int类型的数组
            for(int i = 0;i < res.length;i++){
    
    
                System.out.println("第" + (i+1) + "条语句影响数据库的行数是" + res[i]);
            }
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally{
    
    
            DateSourceForPool.close(conn);
        }
    }
}

在数据库中的结果:
请添加图片描述

jdbc事务处理

参考这个链接

总结

三周多的时间接触数据库和jdbc,总感觉还有好多东西没有知晓,但为了就业,也只能匆匆离开。时间不多了,还需要加快进度。

猜你喜欢

转载自blog.csdn.net/weixin_42953201/article/details/119881545