MySQL 系列(二)Jdbc

MySQL 系列(二)Jdbc

一、Jdbc 基本操作

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;

public class TestJdbc {

    @Test
    public void run1() throws Exception{
        //1、注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //DriverManager.registerDriver(new Driver());

        //2、获取连接
        //DriverManager 管理一组 jdbc 的操作
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");

        //3、编写sql
        String  sql="select * from users where name=?";

        //4、创建语句执行者
        PreparedStatement st = conn.prepareStatement(sql);

        //5、设置参数
        st.setString(1, "aaaa");

        //6、执行sql
        ResultSet rs = st.executeQuery();

        //7、处理结果
        while(rs.next()){
            System.out.println(rs.getString("id") + "=>" + rs.getString("name"));
        }

        //8、释放资源.
        rs.close();
        st.close();
        conn.close();
    }
}

补充:将类加载到内存中方法:

  • Class.forName("全限定名");//包名 + 类名 com.mysql.jdbc.Driver
  • 类名.class
  • 对象.getClass()

二、MySQL API

2.1 DriverManager.getConnection()

管理一组 jdbc 的操作

2.2 Connection 接口

常用方法:

  • (了解)Statement createStatement(): 获取普通的语句执行者,会出现sql注入
  • ☆PreparedStatement prepareStatement(String sql): 获取预编译语句执行者
  • (了解)CallableStatement prepareCall(String sql): 获取调用存储过程的语句执行者
  • (了解)setAuotCommit(false): 手动开户事务
  • (了解)Commit(): 提交事务
  • (了解)rollback(): 事务回滚

2.3 PreparedStatement 预编译的语句执行者 接口

父类 Statement 语句执行者 接口 有注入

  • setString(int 第几个?号, object)
  • setInt(int 第几个?号, object)
  • setObject(int 第几个?号, object)
  • execute(sql): 执行 sql 语句,查询返回结果集,cud 返回受影响的行数
  • executeQuery(sql): 执行 r 语句,返回值:结果集
  • executeUpdate(): 执行 cud 语句,返回值:影响的行数

2.4 ResultSet 接口: 结果集

  • next(): 判断是否有下一条记录,若有返回true且将光标移动到下一行,若没有则返回false。光标一开始处于第一条记录的上面。
  • getString(int|string): 若参数为int: 第几列,若参数为 string: 列名(字段名) getString getInt getObject

2.5 实例,对 jdbc 进行简单的封闭

第一步:创建 jdbc.properties 文件

driverClass=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/test
user=root
password=root

第二步:创建 jdbcUtils.java 文件

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

public class jdbcUtils {

    static final String DRIVERCLASS, URL, USER, PASSWORD;

    //静态代码块,加载代码时运行,只执行一次人
    static {
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        DRIVERCLASS = bundle.getString("driverClass");
        URL = bundle.getString("url");
        USER = bundle.getString("user");
        PASSWORD = bundle.getString("password");
        System.out.println(DRIVERCLASS);
    }

    static {
        //连接驱动
        try {
            Class.forName(DRIVERCLASS);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException {
        //建立连接
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public static void closeResource(Connection conn, Statement st, ResultSet rs) {
        closeResultSet(rs);
        closeStatement(st);
        closeConn(conn);
    }

    /**
     * 释放连接
     * @param conn
     */
    public static void closeConn(Connection conn) {
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            conn = null;
        }
    }

    /**
     * 释放语句执行者
     * @param st
     */
    public static void closeStatement(Statement st) {
        if(st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            st = null;
        }
    }

    /**
     * 释放结果集
     * @param rs
     */
    public static void closeResultSet(ResultSet rs) {
        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            rs = null;
        }
    }
}

第三步:测试

import org.junit.Test;
public class jdbcUtils {

    @Test
    public void run2() {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = jdbcUtils.getConnection();

            //创建 sql
            String sql = "insert into users (name) values (?)";

            //获取语句执行者
            st = conn.prepareStatement(sql);

            //设置参数
            st.setString(1, "sss");

            //执行 sql
            int i = st.executeUpdate();

            //处理结果
            if(i == 1) {
                System.out.println("success");
            } else {
                System.out.println("fail");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭连接资源
            jdbcUtils.closeResource(conn, st, rs);
        }
    }
}

补充:properties 配置文件读取:

常见配置文件格式有 propertiesxml两种,properties 文件读取方式如下:

import java.util.ResourceBundle;

public class TestProperties {
    @Test
    public void read() throws Exception{
        //①获取 ResourceBundle 对象
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");

        //①通过 ResourceBundle 对象获取配置信息
        String driverClass = bundle.getString("driverClass");
    }
}

三、连接池

使用 jdbc 时,每次操作都需要获取连接(创建),用完之后把连接释放(销毁),通过连接池来优化。

3.1 自定义连接池

实现一个自定义的最简单连接池

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

/**
 * 最简单的连接池
 */
public class MyDataSource {
    //LinkedList 增删快,查询慢
    static LinkedList<Connection> pool = new LinkedList<>();

    //初始化连接池,放入3个连接
    static {
        for(int i = 0; i< 3; i++) {
            try {
                Connection conn = jdbcUtils.getConnection();
                pool.addLast(conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //获取连接
    public static Connection getConnection() {
        if(pool.isEmpty()) {
            for(int i = 0; i< 3; i++) {
                try {
                    Connection conn = jdbcUtils.getConnection();
                    pool.addLast(conn);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("获取连接");
        return pool.removeFirst();
    }

    //归还连接
    public static void addBack(Connection conn) {
        System.out.println("已经归还连接");
        pool.addLast(conn);
    }
}

增强方法

  • 继承/实现
  • 装饰者模式(静态代理)
    • 装饰者和被装饰者实现同一个接口或者继承同一个类
    • 装饰者中要有被装饰者的引用
    • 对需要的增强的方法进行加强
    • 对不需要的方法调用原来的方法
  • 动态代理

增强连接池,实现 conn.close() 归还连接池:

第一步:修改 MyDataSource.java 中 getConnection() 方法的返回值

System.out.println("获取连接");
return new ConnectionWrap(pool.removeFirst(), pool);

第二步:新建 ConnectionWrap.java 对 Connection 的 close() 方法进行增强

import java.sql.*;
import java.util.LinkedList;

public class ConnectionWrap implements Connection {
    //连接池
    private LinkedList pool;
    private Connection conn;

    public ConnectionWrap(Connection conn) {
        this.conn = conn;
    }

    public ConnectionWrap(Connection conn, LinkedList pool) {
        this.conn = conn;
        this.pool = pool;
    }

    @Override
    //修改close方法为归还连接池
    public void close() throws SQLException {
        this.pool.addLast(this.conn);
        System.out.println("连接已经归还!");
    }

    @Override
    //不用增强的方法调用原来的方法
    public Statement createStatement() throws SQLException {
        return conn.createStatement();
    }

    @Override
    //不用增强的方法调用原来的方法
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return conn.prepareStatement(sql);
    }

    //...
}

第三步:测试

import org.junit.Test;

public class TestJdbc {

    @Test
    public void run3() throws Exception{

        MyDataSource dataSource = new MyDataSource();

        ConnectionWrap conn = (ConnectionWrap) dataSource.getConnection();
        conn.close();
        //获取连接
        //连接已经归还!
    }
}

3.2 dbcp连接池

第一步:导入 jar 包

commons-dbcp-1.4.jar
commons-pool-1.5.6.jar

第二步:新建 src/main/resources/jdcp.properties 配置文件

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=root

第三步:dbcp-api

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Properties;

public class TestJdbc {
    @Test
    public void dbcp() throws Exception{
        //方法一:
        /*BasicDataSource  dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("root");*/

        //方法二:
        Properties prop = new Properties();
        /*prop.setProperty("driverClassName", "com.mysql.jdbc.Driver");
        prop.setProperty("url", "jdbc:mysql://localhost:3306/test");
        prop.setProperty("username", "root");
        prop.setProperty("password", "root");*/

        prop.load(new FileInputStream("src/main/resources/jdcp.properties"));
        BasicDataSource dataSource = (BasicDataSource) new BasicDataSourceFactory().createDataSource(prop);

        //1、获得连接:
        Connection conn = dataSource.getConnection();
        //2、编写SQL语句.
        String sql = "insert into users values (null, ?, null)";
        //3、预编译SQL:
        PreparedStatement st = conn.prepareStatement(sql);
        //4、设置参数:
        st.setString(1, "Tom");
        //5、执行SQL
        st.execute();
        //6、关闭连接
        st.close();
        conn.close();
    }
}

3.3 c3p0连接池(能自动回收空闲连接的功能)

第一步:导入 jar 包 c3p0-0.9.1.2.jar

第二步:c3p0 默认到 src/main/resources/c3p0.properties 读取配置文件

c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test
c3p0.user=root
c3p0.password=root

或 c3p0 默认到 src/main/resources/c3p0-config.xml 读取配置文件

<c3p0-config>
    <!-- 默认配置,如果没有指定则使用这个配置 -->
    <default-config>
        <!-- 基本配置 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
        <property name="user">root</property>
        <property name="password">root</property>

        <!--扩展配置-->
        <property name="checkoutTimeout">30000</property>
        <property name="idleConnectionTestPeriod">30</property>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </default-config> 

    <!-- 命名的配置 -->
    <named-config name="name">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/xxxx</property>
        <property name="user">root</property>
        <property name="password">1234</property>

        <!-- 如果池中数据连接不够时一次增长多少个 -->
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">20</property>
        <property name="minPoolSize">10</property>
        <property name="maxPoolSize">40</property>
        <property name="maxStatements">20</property>
        <property name="maxStatementsPerConnection">5</property>
    </named-config>
</c3p0-config> 

第三步:c3p0-api

import org.junit.Test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class TestJdbc {
    @Test
    public void c3p0() throws Exception {
        //默认到 src/main/resources/c3p0.properties 读取配置文件
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        //使用命名的配置,若找不到就使用默认的配置
        //ComboPooledDataSource dataSource = new ComboPooledDataSource("name");
        /*dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUser("root");
        dataSource.setPassword("root");*/

        //1、获得连接:
        Connection conn = dataSource.getConnection();
        //2、编写SQL语句.
        String sql = "insert into users values (null, ?, null)";
        //3、预编译SQL:
        PreparedStatement st = conn.prepareStatement(sql);
        //4、设置参数:
        st.setString(1, "Tom2");
        //5、执行SQL
        st.execute();
        //6、关闭连接
        st.close();
        conn.close();
    }
}

dbutils

DBUtils 封装了对 JDBC 的操作,简化了 JDBC 操作。

Dbutils 三个核心功能介绍:

  • QueryRunner 提供对 sql 语句操作的 API
  • ResultSetHandler 接口,用于定义 select 操作后,怎样封装结果集
  • DbUtils 工具类,定义了关闭资源与事务处理的方法

QueryRunner

  • QueryRunner(DataSource ds) 提供数据源(连接池),DBUtils底层自动维护连接connection
  • update(String sql, Object... params) 执行更新数据
  • query(String sql, ResultSetHandler<T> rsh, Object... params) 执行查询

ResultSetHandler

结果集 说明
ArrayHandler 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值
ArrayListHandler 将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。
BeanHandler 将结果集中第一条记录封装到一个指定的javaBean中。
BeanListHandler 将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
ColumnListHandler 将结果集中指定的列的字段值,封装到一个List集合中
KeyedHandler 将结果集中每一条记录封装到Map
MapHandler 将结果集中第一条记录封装到了Map
MapListHandler 将结果集中每一条记录封装到了Map
ScalarHandler 它是用于单数据,返回五long值。例如select count(*) from 表操作。

DbUtils

  • closeQuietly(Connection conn) 关闭连接,如果有异常 try 后不抛
  • commitAndCloseQuietly(Connection conn) 提交并关闭连接
  • rollbackAndCloseQuietly(Connection conn) 回滚并关闭连接

例子:

import com.herolei.bean.Users;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;

public class TestJdbc {

    //1、获取连接池
    ComboPooledDataSource dataSource = null;
    //2、构造方法QueryRunner(),底层创建连接,创建语句执行者,释放资源
    QueryRunner qr = null;

    @Before
    public void setUp() {
        dataSource = new ComboPooledDataSource();
        qr = new QueryRunner(dataSource);
    }

    @Test
    public void update() throws Exception {
        //3、编写SQL语句.
        String sql = "insert into users values (null, ?, null)";
        //4、执行sql
        qr.update(sql, "Tom4"); //cud操作
        //qr.query(sql, "Tom3");        //r操作
    }

    @Test
    //将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值
    public void arrayHandler() throws Exception {
        String sql = "select * from users";
        Object[] query = qr.query(sql, new ArrayHandler());

        for (Object obj: query) {
            System.out.println(obj);
        }
    }

    @Test
    //将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中
    public void arrayListHandler() throws Exception {
        String sql = "select * from users";
        List<Object[]> list = qr.query(sql, new ArrayListHandler());

        for (Object[] obj: list) {
            System.out.println(Arrays.toString(obj));
        }
    }

    @Test
    //将结果集中第一条记录封装到一个指定的javaBean中
    public void beanHandler() throws Exception {
        String sql = "select * from users where id = 19";
        Users user = (Users) qr.query(sql, new BeanHandler(Users.class));

        System.out.println(user);
    }

    @Test
    //将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
    public void beanListHandler() throws Exception {
        String sql = "select * from users";
        List<Users> list = (List<Users>) qr.query(sql, new BeanListHandler(Users.class));

        for(Users user: list) {
            System.out.println(user);
        }
    }
}


每天用心记录一点点。内容也许不重要,但习惯很重要!

原文地址:https://www.cnblogs.com/binarylei/p/9026472.html

时间: 2024-08-26 06:09:12

MySQL 系列(二)Jdbc的相关文章

Mysql系列二:Centos7.4安装mysql5.7.28源码

本文为博客Mysql系列二:Centos7.4安装mysql5.7.28源码 mysql安装方法有多种,以Centos7为例,可以官网下载编译好的二进制代码进行安装,可以官网下载rpm包进行yum install rpm包进行安装,本文我们介绍官网下载源码自行编译安装. 根据Mysql系列一下载的源码,我们开始安装mysql源码,安装方法希望大家多从官网的document上阅读,吸取精髓,安装方法和顺序并不唯一,如下内容可供参考. 基础环境: yum install -y ntp wget cu

MySQL系列二

使用程序设计语言如何跟RDBMS交互: 嵌入式SQL:与动态SQL类似,但其语言必须在程序编译时完全确定下来 动态SQL:程序设计语言使用函数(mysql_connect()) 表管理器: 负责创建.读取或修改表定义文件:维护表描述符高速缓存:管理表锁 表维护模块: 表创建.删除.重命名.移除.更新或插入之类的操作 表维护模块: 检查.修改备份.恢复.优化(碎片整理)及解析 ########################################################## 文件

JAVA使用JDBC连接MySQL数据库 二(2)

本文是对 <JAVA使用JDBC连接MySQL数据库 二>的改进. 上节使用的是PreparedStatement来执行数据库语句,但是preparedStatement需要传递一个sql语句参数,才能创建.然而,DBHelper类只是起到打开和关闭数据库的作用,所以sql语句是要放到应用层部分的,而不是放到DBHelper类中. 而statment不需要传递一个sql语句参数,就能创建. 修改部分如下: public class DBHelper { String driver = &quo

屌炸天实战 MySQL 系列教程(二) 史上最屌、你不知道的数据库操作

此篇写MySQL中最基础,也是最重要的操作! 第一篇:屌炸天实战 MySQL 系列教程(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:屌炸天实战 MySQL 系列教程(二) 史上最屌.你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网远程连接法 查看\创建\使用\删除\清空\修改 数据库表(是否可空,默认值,主键,自增,外键) 表内容的增删改查 where条件.通配符_%.限制limit.排序desc\asc.连表join.组合union 查

MySQL系列(二)

MySql 事务 目录 MySQL系列(一):基础知识大总结 MySQL系列(二):MySQL事务 MySQL系列(三):索引 什么是事务(transaction) 保证成批操作要么完全执行,要么完全不执行,维护数据的完整性.也就是要么成功要么失败. 事务可以是n条sql语句(n>=0) 不是所有数据库引擎支持事务,InnoDB引擎支持事务处理 事务四大特性 原子性(Atomic):事务的所有所有操作要么全部执行,要么全部不执行.如果中途出现错误不会停止,而是回滚到事务前的状态 一致性(Cons

MySQL并发复制系列二:多线程复制 2016

并发复制(Parallel Replication) 系列二: Enhanced Multi-threaded Slaves作者:沃趣科技MySQL数据库工程师  麻鹏飞 首先梳理下传统MySQL/MariaDB主备复制基本原理: 主从复制通过三个线程来完成,在master节点运行的binlog dump的线程,I/O线程和SQL线程运行在slave 节点 master节点的Binlog dump线程,当slave节点与master正常连接的时候,master把更新的binlog 内容推送到sl

MySQL备份和还原系列二:cp冷备份 和 mysqldump

如果要备份,请确保 mysql 打开 log-bin,有了 binarylog,mysql 才可以在必要的时候做完整恢复,或基于时间点的恢复,或基于位置的恢复. 我的数据存放目录为: mysql> SHOW VARIABLES LIKE '%datadir%'; +---------------+-----------------+ | Variable_name | Value           | +---------------+-----------------+ | datadir 

MySQL并发复制系列二:多线程复制

http://blog.itpub.net/28218939/viewspace-1975822/ 并发复制(Parallel Replication) 系列二: Enhanced Multi-threaded Slaves作者:沃趣科技MySQL数据库工程师  麻鹏飞 首先梳理下传统MySQL/MariaDB主备复制基本原理: 主从复制通过三个线程来完成,在master节点运行的binlog dump的线程,I/O线程和SQL线程运行在slave 节点 master节点的Binlog dump

avaweb(三十二)——JDBC学习入门

一.JDBC相关概念介绍 1.1.数据库驱动 这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡,同样道理,我们安装好数据库之后,我们的应用程序也是不能直接使用数据库的,必须要通过相应的数据库驱动程序,通过驱动程序去和数据库打交道,如下所示: 1.2.JDBC介绍 SUN公司为了简化.统一对数据库的操作,定义了一套Java操作数据库的规范(接口),称之为JDBC.这套接口由数据库厂商去实现,这