JDBC基本原理及使用

本文详细介绍了JDBC的基本原理和使用,包括如何连接MySQL数据库,使用Statement和PreparedStatement执行SQL语句,以及ResultSet结果集的处理。同时,文章还讲解了事务处理和批处理的概念,并对比了C3P0和德鲁伊两种数据库连接池的使用方法。最后,提到了ApacheDBUtils在数据库操作中的便利性。
摘要由CSDN通过智能技术生成

目录

JDBC原理

ResultSet(返回结果集)

Statement与PreparedStatement

常用的JDBC API的使用(重点)

 JDBC工具包(自用,可不看)

事务

批处理

数据库连接池

演示C3P0的两种使用方式

德鲁伊连接池 的使用

APDBUtils的使用

BasicDao


JDBC原理

 也就是说JDBC其实是为了操作数据库的,然后Java自己定义了一套接口的规范,这一套接口的规范需要不同的数据库厂家去配合实现。然后他们都会返回一个jar包,供java调用。

 我们通过一个案例来了解来体验一下Java连接MYSQL数据库并操作。

首先我先创建了一个这样的表

public class jdbc01 {
    public static void main(String[] args) throws SQLException {
        //1.配置连接(路径、链接文件)
        String url = "jdbc:mysql://localhost:3306/yzh_db02";
        //创建Properties对象,配置连接文件
        Properties properties = new Properties();
        properties.setProperty("user","root");//使用root用户操作该数据库
        properties.setProperty("password","");//root用户的密码
        //2.注册驱动 new com.mysql.jdbc.driver
        Driver driver = new Driver();//注册驱动其实就是创建驱动对象Driver
        //3.连接
        Connection connect = driver.connect(url, properties);

        //4.执行sql语句
        String sql = "insert into actor values(null,'陈奕迅','男','1970-11-11','10086')";
        Statement statement = connect.createStatement();//用去驱动去获取
        int row = statement.executeUpdate(sql);//executeUpdate——执行更新的意思,返回影响的行数
        System.out.println(row > 0 ? "执行成功" : "执行失败");

        //关闭连接
        statement.cancel();
        connect.close();

/**
 * @author 杨志浩
 * @version 1.0
 * 连接数据库的五种方式
 */
public class jdbc_connect {
    @Test//方式一
    public void connect01() throws SQLException {
        //1.创建驱动
        Driver driver = new Driver();
        //2.创建连接路径
        String url = "jdbc:mysql://localhost:3306/yzh_db02";
        //3.配置连接对象文件
        Properties properties = new Properties();
        properties.setProperty("user","root");
        properties.setProperty("password","");
        //4.连接
        Connection connect = driver.connect(url, properties);
        connect.close();
        System.out.println(connect);
    }

    @Test//方式二
    public void connect02() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
        //使用反射动态加载创建Driver驱动
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();
        //2.创建连接路径
        String url = "jdbc:mysql://localhost:3306/yzh_db02";
        //3.配置连接对象文件
        Properties properties = new Properties();
        properties.setProperty("user","root");
        properties.setProperty("password","");
        //4.连接
        Connection connect = driver.connect(url, properties);
        connect.close();
//        System.out.println(connect);
    }

    @Test//方式三
    public void connect03() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
        //使用manager
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver)aClass.newInstance();
        String  url = "jdbc:mysql://localhost:3306/yzh_db02";
        String user = "root";
        String password = "";
        //把驱动登记到驱动管理器
        DriverManager.registerDriver(driver);
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }

    @Test//方式四(推荐)
    public void connect04() throws ClassNotFoundException, SQLException {
        //直接加载Driver类,关键
        Class.forName("com.mysql.jdbc.Driver");
        String  url = "jdbc:mysql://localhost:3306/yzh_db02";
        String user = "root";
        String password = "";
        //把驱动登记到驱动管理器
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);

        /**这种连接方式最关键的就是加载Driver类——Class.forName("com.mysql.jdbc.Driver");
         * 我们看看底层这个Driver的源码
         * public class Driver extends NonRegisteringDriver implements java.sql.Driver {
         *     public Driver() throws SQLException {
         *     }
         *
         *     static {
         *         try {
         *             DriverManager.registerDriver(new Driver());
         *         } catch (SQLException var1) {
         *             throw new RuntimeException("Can't register driver!");
         *         }
         *     }
         * }
         *
         * 我们可以看到他里面有一个静态的代码块,那么里面他直接帮我们做了这样一个工作
         * DriverManager.registerDriver(new Driver());
         */
    }

    //方式5:在方式4的基础上改进,引入配置文件,让连接mysql更加灵活
    @Test
    public void connect05() throws IOException, ClassNotFoundException, SQLException {
        //1.创建属性对象,加载配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        String url = properties.getProperty("url");
        String password = properties.getProperty("password");
        String user = properties.getProperty("user");
        String driver = properties.getProperty("driver");
        Class.forName(driver);
        Connection connection = DriverManager.getConnection(url, user, password);
//        connection.close();

    }
}

 方式5需要创建一个properties文件

ResultSet(返回结果集)

/**
 * @author 杨志浩
 * @version 1.0
 * 演示结果集ResultSet的使用
 */
public class ResultSet_ {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");

        Connection connection = DriverManager.getConnection(url, user, password);
        Class.forName(driver);

        String sql = "select id,name,sex,age from news";
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);//executeQuery——执行查询

        while (resultSet.next()) {
            //resultSet可以理解为头指针,他指向首元结点的前一行
            //resultSet.next()就是会跳到下一个结点(下一行记录)
            //一个结点代表一行记录
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            String sex = resultSet.getString("sex");
            int age = resultSet.getInt("age");

            System.out.println(id + "\t" + name + "\t" + sex + "\t" + age);
        }
        
        statement.cancel();
        resultSet.close();
        connection.close();

        /**  news表
         * +----+-----------+------+------+
         * | id | name      | sex  | age  |
         * +----+-----------+------+------+
         * |  1 | 唐三      | 男   |   23 |
         * |  2 | 唐舞麟    | 男   |   13 |
         * |  3 | 蓝轩宇    | 男   |    3 |
         * +----+-----------+------+------+
         */
    }
}

Statement与PreparedStatement

                                                         PreparedStatement

//这是一段PrepareStatement演示select语句 

//关键代码解释   
 String sql03 = "select `name`,password from admin where `name` = ? and password = ?";
        PreparedStatement preparedStatement1 = connection.prepareStatement(sql03);
        preparedStatement1.setString(1,admin_name);
        preparedStatement1.setString(2,admin_pwd);
        ResultSet resultSet1 = preparedStatement1.executeQuery();
        //上面这一句不需要在对括号填入sql03,你已经对这个preparedStatement1关联的sql语句
        //中的?进行了setString设值。如果你再把sql03填入就相当于填入了这一句
        //"select `name`,password from admin" + "where `name` = ? and password = ?";
        //这就没有对?赋值了啊

        if(resultSet1.next()){
            System.out.println("登陆成功");
        }else {
            System.out.println("登陆失败");
        }

        //必须得在同一行同一个""中
//用PreparedStatement演示删     
  Properties properties=new Properties();
        properties.load(new FileInputStream("src/mysql.properties"));
        String url=properties.getProperty("url");
        String user=properties.getProperty("user");
        String pwd=properties.getProperty("password");
        String driver=properties.getProperty("driver");
        //加载驱动(也可以获得驱动对象的Class)
        Class.forName(driver);
        //连接
        Connection connection=DriverManager.getConnection(url,user,pwd);

        String delete_sql="delete  from admin where `name` = ? and password = ?";
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入注销的用户名:");
        String admin_name=scanner.nextLine();
        System.out.println("请输入用户密码:");
        String admin_pwd=scanner.nextLine();
        PreparedStatement preparedStatement=connection.prepareStatement(delete_sql);
        //对?赋值
        preparedStatement.setString(1,admin_name);
        preparedStatement.setString(2,admin_pwd);
        //执行该语句
        int i=preparedStatement.executeUpdate();

        System.out.println(i>=1?"注销成功":"注销失败");

        preparedStatement.close();
        connection.close();
        }

其他的DML操作也是一样的,可以看charper125中的Ecercise01

常用的JDBC API的使用(重点)

简单来说,对于JDBC的操作步骤是,首先通过驱动对象(Driver / DriverManager)获取联系对象(Connection), 然后通过联系对象获取处理对象sql语句的处理对象(Statement)或者预处理对象(PreparedStatement),然后用(预处理对象/处理对象)去调用不同的方法执行sql语句,执行DML语句(增删改)则用executeUpdate,返回影响的行数,执行select则调用executeResultSet,返回你查询的结果集。并且结果集会有一个头指针,可以通过executeResultSet的引用变量去调用next(),指向下一个结点(也就是下一条记录),然后你得通过getXxx方法去获取不同的字段,当然也可以用getObject去获取。

execute是处理的意思,Result是结果的意思,Set是集合的意思。

 JDBC工具包(自用,可不看)

/**
 * @author :杨志浩
 * @version 1.0
 * 这是JDBC的工具包,完成JDBC的连接
 */
public class JDBCUtils {
    //因为只需要记载一次所以做成静态
    private static String url;
    private static String user;
    private static String password;
    private static String driver;//返回"com.mysql.jdbc.Driver"

    //用静态代码块为其赋值——静态代码块本身最大的作用就是用来给静态属性赋值的
    static {
        try {
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\mysql.properties"));
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driver = properties.getProperty("driver");
        } catch (IOException e) {
            //这里面要把这个编译异常做成运行时异常
            //因为当这里捕获到编译型异常调用者就必须得处理,
            //但是我们转成运行时异常,调用者可处理可抛出
            // 这样更方便调用者处理,
            throw new RuntimeException(e);
        }
    }

    //连接数据库, 返回 Connection
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
        //1. 将编译异常转成 运行异常
        //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便. throw new RuntimeException(e);
            throw new RuntimeException(e);
        }
    }

            //关闭相关资源
            /*
            1. ResultSet 结果集
            2. Statement 或者 PreparedStatement
            3. Connection
            4. 如果需要关闭资源,就传入对象,否则传入 null
            */
        public static void close (ResultSet set, Statement statement, Connection connection){
                //判断是否为 null
            try {
                if (set != null) {
                    set.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                //将编译异常转成运行异常抛出
                throw new RuntimeException(e);
            }
        }
    }

事务

//这是一个转账的案例 
   public static void main(String[] args) throws Exception {
        Connection connection = JDBCUtils.getConnection();
        String sql01 = "update account set balance = balance - 100 where name = '马云'";
        String sql02 = "update account set balance = balance + 100 where name = '马化腾'";

        connection.setAutoCommit(false);
        PreparedStatement preparedStatement = null;

        try {
            preparedStatement = connection.prepareStatement(sql01);
            preparedStatement.executeUpdate();
            int i = 1/0;//设置一个异常
            preparedStatement = connection.prepareStatement(sql02);
            preparedStatement.executeUpdate();
            //如果没有抛出异常进到catch则会执行到下面这行代码,提交事务
            connection.commit();
        } catch (Exception e) {
            System.out.println("出现异常,回滚发生,sql无效");
            connection.rollback();
            throw new Exception(e);
        } finally {
            JDBCUtils.close(null,preparedStatement,connection);
        }
    }
}

批处理

解读:

首先顾名思义批处理就是执行多条sql语句,他的执行机制是这样的,把你需要执行的多条sql语句先放入到一个类似于缓冲池的地方,然后再一次性发送给MysqlDBMS(mysql控制台)。

如果你需要用到批处理的操作,那么你必须在url中添加?rewriteBatchedStatements=true参数

public class BatchedStatement {
    public static void main(String[] args) throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into account values(null,'周杰伦',?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        for (int i = 0; i < 100; i++) {
            preparedStatement.setDouble(1,i);
            preparedStatement.addBatch();//把需要执行的sql语句先填入缓冲池
        }
        preparedStatement.executeBatch();
        JDBCUtils.close(null,preparedStatement,connection);
    }
}

数据库连接池

 我们在前面学的JDBC操作数据库都是像上面的步骤来做的,但是如果一旦连接数据库的连接数变多了就会面临数据库崩溃的风险,比如你链接数据库5000次(不关闭)

他会给你报一个Too many connections的异常。5000次对于一个门户网站来说其实一点也不多但是他却报错了,说明数据库根本处理不了。即使你每一次连接都关闭,那5000次连接—关闭 也需要7秒多的时间,为什么会这么耗时,因为MysqlDBMS在你的java程序在每一次发送链接请求的时候验证你的登录信息的校验会耗时0.5~0.7秒这是一个较长的时间。而我们引入的连接池的使用就是为了减去这一验证步骤是他可以复用。

解读:就是说我们会在Java程序中创建一个连接池,该连接池有很多连接引用(有限),每个连接引用都对应有一个连接通道(已经和MysqlDBMS校验过的),然后我们Java程序在操作连接数据库的时候就直接从数据库取一个连接引用,然后用完后放回连接池,注意放回连接池后该连接不会只是和java程序断掉了,并不是指该连接和数据库断掉,那我下一次在调用我就再从这个连接池拿就可以了。这样就省去了登录校验的步骤,提高了效率。这个等待队列的意思就是说,如果你的java程序在在调用连接池的连接引用时,连接引用都被占用了,那么他就会等待别的程序断掉连接引用,然后他才能够去连接的意思。

注意:不管你使用哪种连接池都得把对应的第三方工具包拿过来放到你的项目下哦 

演示C3P0的两种使用方式

先把C3P0的工具包拿过来

    public void test01_C3P0() throws Exception {
        //创建连接池
        //获得一个数据池(数据池中放了多个Connection)
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        //给数据池配置JDBC与mysql的连接路径
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/yzh_db02?rewriterBatchedStatements=true");
        comboPooledDataSource.setUser("root");//给数据池配置登录用户
        comboPooledDataSource.setPassword("");//给数据池配置登录密码
        comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");//给数据池配置驱动
        comboPooledDataSource.setInitialPoolSize(10);//数据池初始connection数量
        comboPooledDataSource.setMaxPoolSize(50);//数据池最大connection数量
        //此时该数据池可以提供有50个Connection
        //测试通过连接池连接5000次数据库,运行时间
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            Connection connection = comboPooledDataSource.getConnection();
            connection.close();
        }
        long emp = System.currentTimeMillis();
        System.out.println(emp - start);//442毫秒,也就是相当于0.4秒。牛逼
    }

 还有一种是使用C3P0厂家提供的连接配置包——在src下面引用这个文件c3p0-config.xml(文件名必须为这个)

<!-- c3p0-config.xml(文件名必须为这个)-->
<c3p0-config>
    <!--数据池名字,随意取-->
    <named-config name = "yzh_c3p0">
        <!-- 驱动类的全类名 -->
       <property name="driverClass">com.mysql.jdbc.Driver</property>
        <!-- url(JDBC与数据库连接路径) -->
       <property name="jdbcUrl">jdbc:mysql://localhost:3306/yzh_db02</property>
        <!-- 数据库用户 -->
       <property name="user">root</property>
        <!-- 用户密码 -->
       <property name="password"></property>
        <!-- 连接池中Connection每次增长的增长数 -->
       <property name="acquireIncrement">5</property>
        <!-- 连接池中Connection的初始个数 -->
       <property name="initialPoolSize">10</property>
        <!-- 连接池中Connection的至多个数 -->
        <property name="maxPoolSize">50</property>
        <!-- 连接池中Connection的最小个数 -->
       <property name="minPoolSize">5</property>
        <!--最小个数指的是当你是用一段时间连接池后发现使用连接的个数小于初始个数则初始个数变成最小个数-->

        <!--下面这个参数暂时不需要理解-->
       <property name="maxPoolSize">10</property>
    </named-config>
</c3p0-config>
    public void test02_C3P0() throws SQLException {
        //使用C3P0提供的配置文件来创建连接池,并使用
        ComboPooledDataSource cpds = new ComboPooledDataSource("yzh_c3p0");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            Connection connection = cpds.getConnection();
            connection.close();
        }
        long emp = System.currentTimeMillis();
        System.out.println(emp - start);//357
    }
}

德鲁伊连接池 的使用

    @Test//演示德鲁伊的使用。
    public void test01_Druid() throws Exception {
        //适用前提:在项目下加入第三方连接池德鲁伊包
        //配置德鲁伊链接文件(网上有)
        //1.读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));
        //2.调用DruidDataSourceFactory.createDataSource
        //      ——德鲁伊数据源工厂.创建数据源。其实这个数据源就是一个连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        //3.通过连接池获取连接
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            Connection connection = dataSource.getConnection();
            connection.close();
        }
        long emp = System.currentTimeMillis();
        System.out.println(emp - start);//396毫秒
    }

APDBUtils的使用

 我们来看上面这张图,我们都知道resultSet结果集是与connection连接相关联的,但是在某些时候我们需要动态的返回这个resultSet集合或者把这个集合发送到别的地方去的时候我们这个conncetion就很麻烦,到底关不关闭呢?我们其实时需要达到这样一个效果——即关闭connection连接也能使用resultSet集合。使用ApacheDBUtil就可以。

其实这个ApacheDBUtils就是类似于上面这张图这样。

我们先模仿一下这个ApacheDBUtils工具类:

package jdbc.datasource;

import java.util.Date;

/**
 * @author :杨志浩
 * @version 1.0
 * Actor对应actor表的记录
 */
public class Actor {
    private Integer id;
    private String name;
    private String sex;
    private Date borndate;
    private String phone;

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Actor() {
    }

    public Actor(Integer id, String name,String sex, Date borndate, String phone) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.borndate = borndate;
        this.phone = phone;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBorndate() {
        return borndate;
    }

    public void setBorndate(Date borndate) {
        this.borndate = borndate;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "\nActor{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", borndate=" + borndate +
                ", phone='" + phone + '\'' +
                '}';
    }
}
package jdbc.datasource;



/**
 * @author :杨志浩
 * @version 1.0
 * 手写演示核心的ApacheDBUtil
 */
public class JDBC_APUtil01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src//mysql.properties"));
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");

        //连接
        Connection connection = DriverManager.getConnection(url, user, password);
        //加载驱动
        Class.forName(driver);

        String select_sql = "select * from actor";
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        ArrayList<Actor> actors = new ArrayList<>();
        try {
            preparedStatement = connection.prepareStatement(select_sql);
            resultSet = preparedStatement.executeQuery();

            while (resultSet.next()){
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String sex = resultSet.getString("sex");
                Date borndate = resultSet.getDate("borndate");
                String phone = resultSet.getString("phone");
                actors.add(new Actor(id,name,sex,borndate,phone));

            }
            System.out.println(actors);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtils.close(resultSet,preparedStatement,connection);
        }
    }
}

其实Apache-DBUtils的底层思想就是创建一个与表结构对应的JavaBean对象(比如Actor),接着创建一个集合该集合指定泛型为Actor,然后把返回的结果集resultSet存入这个集合中。

 演示使用:

package jdbc.datasource;
/**
 * @author :杨志浩
 * @version 1.0
 * 使用德鲁伊+APAChe-DBUtil
 */
public class DBUtils_USE {
    //使用apache-DBUtils+druid完成对表的crud的操作
    @Test
    public void testQueryMany() throws Exception {//返回多行记录
        //1.读取连接配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
       //2.使用德鲁伊连接池获得连接
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        Connection connection = dataSource.getConnection();
        //3.组织sql语句
        String select_sql = "select * from actor where id>?";
        //4.引入Apache-DBUtils.jar包(commons-dbutils-1.3.jar)
        //并创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //5.调用query方法执行sql语句
        List<Actor> list =
                queryRunner.query(connection,select_sql,new BeanListHandler<>(Actor.class),1);
        //query方法的参数解读
        //1.首先你得知道这个query方法就是用来执行查询语句的
        //2.query(连接,sql语句,BeanListHandler返回List<Actor>,sql的?参数值-可传入多个)
        //new BeanListHandler<>(Actor.class)底层:
        // 通过映射得到Actor的完整内部结构,并且创建List<Actor>,再把返回的resultSet结果集add到该集合中
        //最后返回这个集合。
        //注意1:第三个参数可以变为BeanHandler<>(Actor.class),他会返回一个Actor对象
        //注意2:query方法底层会把resultSet集合、PrepareStatement关闭
        for(Actor actor : list){
            System.out.println(actor);
        }
        //5.关闭资源
        JDBCUtils.close(null,null,connection);
        //这里,resultSet、statement在前面query方法中底层已经关闭了

    }
}

也就是说查询方法query第三个参数决定了返回的值,那么第三个参数有三种情况:

1.第三个参数为BeanListHandler<a.class>返回List<a>——业务为查询结果集

2.第三个参数为BeanHandler<a.class>返回a对象——业务为查询单行记录

3.第三个参数为ScalarHandler返回一个Object对象——业务为查询单行单列(Scalar:单一值)

注意:2/3中如果sql业务查询不存在则返回值为null

 @Test//使用APACheJDBCUtils + Druid 演示DML(Update、insert、delete)
    public void testUpdate() throws Exception {
        //1.得到连接
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        Connection connection = dataSource.getConnection();

        //2.创建queryRunner
        QueryRunner queryRunner = new QueryRunner();
        //3.组织sql语句
        String sql = "Update actor set name = ? where id = ?";
        //4.调用queryRunner.update方法,DML语句都用该方法,返回影响行数
        int affectedRow = queryRunner.update(connection, sql, "张三丰", 2);
        System.out.println(affectedRow>0?"执行成功":"受影响行数为0");
        //5.关闭资源
        JDBCUtils.close(null,null,connection);
    }

BasicDao

问题引出:

 这个时候我们就可以用到DAO的概念应用了。DAO——Data Access Object(数据访问对象)其实DAO他只是把访问数据的操作封装成对象,但是他衍生出来的其他东西才是最重要的,就是说现在如果我需要用到这个DAO,那么需要理解下面这张图的开发模式,在现实开发中我们对数据库的操作其实是一种比较复杂的处理,不可能像前面所学的那样去对数据库来操作,那样太笨拙了。下面这种模式是在开发中对数据库比较常用的一种操作,关键是理解其中的数据层交互关系,必须要理解下面这张图:

解读:

1.domain层对应数据库中各个表对象

2.DAO层存放着各个表对应的DAO对象,每一个DAO对象都可以对对应的表进行crud,其中BasicDAO表示基本的DAO,里面是一些链接、关闭等公用的业务,可提供给各个DAO使用。

3.Service层就是业务层了,这个没啥好说的。

代码实现:

代码层

BasicDAO

package dao_.dao;

import dao_.utils.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

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

/**
 * @author :杨志浩
 * @version 1.0
 * 该类是其他DAO的父类,基础DAO
 */
public class BasicDAO<T> {//泛型指定具体的DAO类
    private QueryRunner qr = new QueryRunner();

    //创建update方法操作dml
    private int update(String dml_sql,Object... parameters){
        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            int affectedRow = qr.update(connection, dml_sql, parameters);
            return affectedRow;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }

    /**
     * 创建queryMulti方法,该方法执行多行查询语句
     * @param sql 字符串 查询语句
     * @param clazz 泛型 clazz,比如Actor clazz
     * @param parameters 可变参数?
     * @return 返回集合ArrayList<T>
     */
    public List<T> queryMulti(String sql,Class<T> clazz,Object... parameters){
        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            List<T> query = qr.query(connection, sql, new BeanListHandler<T>(clazz), parameters);
            return query;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }

    //创建querySingle该方法执行单行查询语句
    public T querySingle(String sql,Class<T> clazz,Object... parameters){
        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            T query = qr.query(connection, sql, new BeanHandler<T>(clazz), parameters);
            return query;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }

    //创建queryScalar执行查询单行单列的sql语句
    public Object queryScalar(String sql,Object... parameters){
        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            Object query = qr.query(connection, sql, new ScalarHandler(), parameters);
            return query;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }


}

 ActorDAO

package dao_.dao;

import dao_.domain.Actor;

/**
 * @author :杨志浩
 * @version 1.0
 */
public class ActorDAO extends BasicDAO<Actor>{
    //这里还可以写其他ActorDAO特有的操作
}
testActorDAO
public class TestDAO {
    @Test
    public void testActorDAO(){
        ActorDAO actorDAO = new ActorDAO();
        String sql = "select * from actor where id >= ?";
        List<Actor> actors = actorDAO.queryMulti(sql, Actor.class, 1);
        for (Actor actor : actors){
            System.out.println(actor);
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

new麻油叶先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值