zoukankan      html  css  js  c++  java
  • JDBC-02

    JDBC

    前言

      在JDBC-01当中,我们简单地学习了有关JDBC的一些基本操作,现在我们再一次进行深入的学习。

    正文

    事务

      首先,我们来学习的是JDBC中事务的运用,那么让我们再次了解一下事务的概念。

    事务的概念

      事务指的是逻辑上的一组操作,组成这组操作各个逻辑单元要么全部成功,要么全部失败。

    关于事务的API

    getAutoCommit()

    commit()

    rollback()

    异常案例:

    package com.charles.jdbc.high;
    
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    /**
     * 有关事务的案例
     * 转账案例
     * @author Charles
     */
    public class Demo01 {
        @Test
        public void demo(){
            Connection conn = null;
            PreparedStatement pste = null;
            try {
                // 加载驱动 + 获取连接
                conn = org.charl.Demo.getConnection();
                // 编写SQL
                String sql = "update account set money = money + ? where name = ?";
                // 预编译
                pste = conn.prepareStatement(sql);
                // 转账过程
                pste.setInt(1,-1000);
                pste.setString(2,"aaa");
                pste.executeUpdate();
                pste.setInt(1,1000);
                pste.setString(2,"bbb");
                pste.executeUpdate();
                // 因为这个错误,导致异常的发生
                int i = 1 / 0;
            } catch (SQLException e){
                e.printStackTrace();
            } finally {
                // 资源释放
                org.charl.Demo.release(pste,conn);
            }
    
    
    
        }
    }

    修改后的案例

    package com.charles.jdbc.high;
    
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    /**
     * 有关事务的案例
     * 转账案例
     * @author Charles
     */
    public class Demo01 {
        @Test
        public void demo(){
            Connection conn = null;
            PreparedStatement pste = null;
            try {
                // 加载驱动 + 获取连接
                conn = org.charl.Demo.getConnection();
                // 开启事务
                conn.setAutoCommit(false);
                // 编写SQL
                String sql = "update account set money = money + ? where name = ?";
                // 预编译
                pste = conn.prepareStatement(sql);
                // 转账过程
                pste.setInt(1,-1000);
                pste.setString(2,"aaa");
                pste.executeUpdate();
                pste.setInt(1,1000);
                pste.setString(2,"bbb");
                pste.executeUpdate();
                // 因为这个错误,导致异常的发生
    //            int i = 1 / 0;
                conn.commit();
            } catch (SQLException e){
                // 回滚事务
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                // 资源释放
                org.charl.Demo.release(pste,conn);
            }
    
    
    
        }
    }

    这样,数据就会进行回滚,保证了数据的安全性。

    连接池

    概念:连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。

    好处(作用):

    • 减少连接创建时间
    • 简化的编程模式
    • 受控的资源使用
    • 提高连接的效率

    连接池原理:

    自定义连接池:

      我们可以利用DataSource接口来实现一个自定义连接池

    具体步骤:

    1. 编写一个类实现DataSource接口

    2. 重写一个getConnection方法

    3. 初始化多个连接在内存中

    4. 编写归还连接的方法

    具体实现:

    /**
     * 自定义连接池
     * @author Charles
     */
    public class MyDataSource implements DataSource {
        // 在初始化的时候提供一些连接
        private List<Connection> connectionList = new ArrayList<Connection>();
        public MyDataSource(){
            // 初始化连接
            for (int i = 1; i <= 4; i++){
                // 向集合中存入连接
                connectionList.add(org.charl.Demo.getConnection());
            }
        }
        // 获得连接的方法
        @Override
        public Connection getConnection(String username, String password) throws SQLException {
            Connection conn = connectionList.remove(0);
            return conn;
        }
    
        // 归还连接的方法
        public void addBack(Connection conn){
            connectionList.add(conn);
        }

    代码案例:

    package jdbc.datasources;
    
    import org.junit.Test;
    
    import javax.management.relation.Relation;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    /**
     * 利用连接池的案例
     */
    public class Demo01 {
        @Test
        public void demo(){
            Connection conn = null;
            PreparedStatement preparedStatement = null;
            ResultSet rs = null;
            MyDataSource md = null;
    
            try{
                // 利用自定义的连接池注册驱动 + 获得连接
                md = new MyDataSource();
                conn = md.getConnection();
                // 编写SQL语句
                String sql = "select * from account";
                preparedStatement = conn.prepareStatement(sql);
                rs = preparedStatement.executeQuery();
                // 遍历结果
                while (rs.next()){
                    System.out.println(rs.getInt("id") + " " + rs.getString("name") + " "
                            + rs.getString("money"));
                }
    
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                // 释放资源
                if (preparedStatement != null){
                    try{
                        preparedStatement.close();
                    } catch (SQLException e){
                        e.printStackTrace();
                    }
                    preparedStatement = null;
                }
    
                if (rs != null){
                    try {
                        rs.close();
                    }catch (SQLException e){
                        e.printStackTrace();
                    }
                    rs = null;
                }
    
                // 归还连接
                md.addBack(conn);
    
            }
        }
    }

    Druid开源连接池

      Druid 是阿里旗下的开源连接池产品,使用非常简单,可以与Spring 框架进行快速整合。

    Maven导包

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.1.21</version>
        </dependency>

    基本代码实现

    package com.charles.datasource.demo1;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class DruidDemo1 {
    
        @Test
        public void demo01(){
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                // 使用连接池
                DruidDataSource druidDataSource = new DruidDataSource();
                druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
                druidDataSource.setUrl("jdbc:mysql:///web_test3");
                druidDataSource.setUsername("root");
                druidDataSource.setPassword("1234");
    
    // 获得连接
                connection = druidDataSource.getConnection();
                // 编写SQL
                String sql = "select * from user";
                // 预编译sql
                preparedStatement = connection.prepareStatement(sql);
                resultSet = preparedStatement.executeQuery();
                while (resultSet.next()){
                    System.out.println(resultSet.getInt("id") + " " + resultSet.getString("username")
                            + " " + resultSet.getString("password"));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
    
    
    
        }
    }

    当然也可以将这些数据库信息向外面引入,即创建一个db.properties

    代码实现:

    单元测试类

        @Test
        public void Demo02(){
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                // 使用连接池
                Properties properties = new Properties();
                properties.load(new FileInputStream("src/main/resources/db.properties"));
                DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    
                // 获得连接
                connection = dataSource.getConnection();
                // 编写SQL
                String sql = "select * from user";
                // 预编译sql
                preparedStatement = connection.prepareStatement(sql);
                resultSet = preparedStatement.executeQuery();
                while (resultSet.next()){
                    System.out.println(resultSet.getInt("id") + " " + resultSet.getString("username")
                            + " " + resultSet.getString("password"));
                }
            } catch (SQLException | FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    db.properties

    # 连接设置
    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql:///web_test3
    username=root
    password=1234
    
    # 初始化连接
    initialSize=10
    
    # 最大连接数量
    maxActive=50
    
    # 最大空闲连接
    maxIdle=20
    
    # 最小空闲连接
    minIdle=5
    
    # 超时等待时间(以毫秒为单位)
    maxWait=60000

    C3P0连接池

      C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。

    使用方法与Druid相类似

    Maven导包

    <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
    </dependency>

    基本代码实现

    package com.charles.datasource.demo1;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.junit.Test;
    
    import java.beans.PropertyVetoException;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class C3p0 {
    
        @Test
        public void demo01() {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                // 使用连接池
                ComboPooledDataSource DataSource = new ComboPooledDataSource();
                DataSource.setDriverClass("com.mysql.jdbc.Driver");
                DataSource.setJdbcUrl("jdbc:mysql:///web_test3");
                DataSource.setUser("root");
                DataSource.setPassword("1234");
    
                // 获得连接
                connection = DataSource.getConnection();
                // 编写SQL
                String sql = "select * from user";
                // 预编译sql
                preparedStatement = connection.prepareStatement(sql);
                resultSet = preparedStatement.executeQuery();
                while (resultSet.next()) {
                    System.out.println(resultSet.getInt("id") + " " + resultSet.getString("username")
                            + " " + resultSet.getString("password"));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (PropertyVetoException e) {
                e.printStackTrace();
            } finally {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    当然,C3P0连接池也可以通过外部配置文件引用

    具体代码实现:

    c3p0-config.xml配置文件

    <?xml version="1.0" encoding="utf-8"?>
    <c3p0-config>
        <default-config>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql:///web_test3</property>
            <property name="user">root</property>
            <property name="password">1234</property>
    
            <property name="initialPoolSize">5</property>
            <property name="maxPoolSize">20</property>
            <property name="minPoolSize">5</property>
        </default-config>
    
    </c3p0-config>

    单元测试类

        @Test
        public void Demo02(){
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                // 使用连接池
                ComboPooledDataSource DataSource = new ComboPooledDataSource();
                DataSource.setDriverClass("com.mysql.jdbc.Driver");
                DataSource.setJdbcUrl("jdbc:mysql:///web_test3");
                DataSource.setUser("root");
                DataSource.setPassword("1234");
    
                // 获得连接
                connection = DataSource.getConnection();
                // 编写SQL
                String sql = "select * from user";
                // 预编译sql
                preparedStatement = connection.prepareStatement(sql);
                resultSet = preparedStatement.executeQuery();
                while (resultSet.next()) {
                    System.out.println(resultSet.getInt("id") + " " + resultSet.getString("username")
                            + " " + resultSet.getString("password"));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (PropertyVetoException e) {
                e.printStackTrace();
            } finally {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    这里注意,只要将配置文件放在默认路径下,它就会自动查找,不需要手动导入。

    DBUtils

      Commons DbUtils一个对JDBC进行简单封装的工具类库,它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

    为什么要学习DBUTILES?

      两个字:方便   ----->  一个字:懒

    DBUtils常用的API:

    QuerryRunner 和 DBUtils,具体查API文档

     

    DBUtils的CRUD操作:(实例源于黑马,博主在这偷个懒)

    添加:

     

    修改:

     

    删除:

     

    查询单条(前提创造实体类):

     

    查询多条(前提创造实体类):

     

    ResultSetHandler的实现类:

    ArrayHandler 和 ArrayListHandler:

     

     

    BeanHandler 和 BeanListHandler (重要!!):

     

    MapHandler 和 MapListHandler:

     

    ColumnListHandler 和 ScalarHandler 还有 KeyedHandler:

    ColumnListHandler:

     

    ScalarHandler:查询表中有多少列

     

    KeyedHandler:

     

    小结

      以上便是JDBC的内容了,多练,练到烦了就会了。当然为了更偷懒,我们后期将会学到Mybatis,这个框架比JDBC更方便。

                                       加油!

                                 时间:2020-04-06 01:41:37

  • 相关阅读:
    PHP---无限极分类数组处理
    PHPExcel数据导入(含图片)
    PHP数组与xml互相转换
    微信APP支付【签名失败】
    winform窗体关闭方案
    ss的优先级 和 权重
    Anaconda 与 conda 区别
    c#FileStream文件读写
    C# DataTable 某一列取算
    关于解决DevExpress用DevExpress patch工具破解后经常弹出试用框的问题
  • 原文地址:https://www.cnblogs.com/Charles-H/p/Learning_JDBC02.html
Copyright © 2011-2022 走看看