一、连接数据库的过程

  连接数据库的过程:加载数据库驱动程序,不过只需在第一次访问数据库时加载一次,然后在每次访问数据库时创建一个Connection实例,然后执行操作数据库的SQL语句,并返回执行结果,最后在完成此次操作时销毁前面创建的Connection实例,释放与数据库的连接。

  1.加载JDBC驱动程序

    // 加载数据库驱动类,加载失败抛出ClassNotFoundException异常
Class.forName(Driver);

  2.创建数据库连接

// 创建一个数据库连接对象,创建失败会抛出SQLException异常
Connection conn = DriverManager.getConnection(Url, User, Password);

  3.创建一个Statement对象

            // 通过Connection示例创建Statement实例
Statement statement = conn.createStatement();

  4.执行SQL语句并获得查询结果

            // 通过Statement实例执行SQL语句并返回执行结果
ResultSet rs = statement.executeQuery("select * from user");

  5.关闭连接释放资源

  在每次访问数据库后,应该按照下面的顺序,及时销毁这些实例,释放它们占用的所有资源。

            rs.close();
statement.close();
conn.close();

  二、Statement实例的三种类型

  Statement接口中,执行executeQuery方法可以返回查询结果到结果集中,执行executeUpdate方法可以插入、删除或者修改数据库记录,并返回一个int型数值,表示影响数据库记录的条数。

  Statement实例分为三种类型:Statement实例、(继承自Statement)PreparedStatement实例和(继承自PreparedStatement)CallableStatement实例。

  (1)Statement实例是最简单的Statement实例,只能用来执行静态的SQL语句

            ResultSet rs_queue = statement.executeQuery("select * from user");
while (rs_queue.next()) {
System.out.println(rs_queue.getInt("id") + " "
+ rs_queue.getString("name") + " "
+ rs_queue.getString("sex") + " "
+ rs_queue.getString("birthday"));
}
System.out.println(statement.executeUpdate("update user set sex='女' where id=1")); // 打印:1
       rs_queue.close();
            statement.close()

  (2)PreparedStatement实例增加了执行动态SQL语句的功能

            String sql = "update user set name = ?, sex = ?, birthday = ?where id =?";
PreparedStatement predStatement = conn.prepareStatement(sql);
predStatement.setString(1, "loser");
predStatement.setString(2, "女");
predStatement.setDate(3, new Date(System.currentTimeMillis()));
predStatement.setInt(4, 1);
System.out.println(predStatement.executeUpdate()); // 打印:1
predStatement.close();

  (3)CallableStatement实例增加了执行数据库存储过程的功能

  首先在MySQL中创建一个存储过程并测试:

mysql> select * from user //
+----+-------+------+------------+
| id | name | sex | birthday |
+----+-------+------+------------+
| 1 | loser | 女 | 2018-08-06 |
| 2 | lsl | 男 | 2017-12-12 |
| 3 | zgs | 女 | 2016-06-01 |
+----+-------+------+------------+
3 rows in set (0.00 sec) mysql> create procedure proc_count_select_by_sex(IN girl_or_boy VARCHAR(255))
-> READS SQL DATA
-> BEGIN
-> select count(*) from user where sex=girl_or_boy;
-> END
-> //
Query OK, 0 rows affected (0.00 sec) mysql> call proc_count_select_by_sex('女') //
+----------+
| count(*) |
+----------+
| 2 |
+----------+
1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec)

  然后使用CallableStatement对象调用存储过程:

            String sql = "{call proc_count_select_by_sex(?)}";
CallableStatement cablStat = conn.prepareCall(sql);
cablStat.setString(1, "女");
ResultSet rs = cablStat.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt(1)); // 打印:2
}
rs.close();
cablStat.close();

  三、标准JDBC程序设计

package jdbc.jun.iplab;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; public class JDBC { private static final String Driver = "com.mysql.jdbc.Driver";
private static final String Url = "jdbc:mysql://localhost:3306/mysqldb?useSSL=false";
private static final String User = "root";
private static final String Password = "bjtungirc"; static {
try {
Class.forName(Driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
try {
// 创建一个数据库连接对象,创建失败会抛出SQLException异常
Connection conn = DriverManager.getConnection(Url, User, Password);
// 通过Connection示例创建Statement实例
Statement statement = conn.createStatement();
// 通过Statement实例执行SQL语句并返回执行结果
ResultSet rs_queue = statement.executeQuery("select * from user");
while (rs_queue.next()) {
System.out.println(rs_queue.getInt("id") + " "
+ rs_queue.getString("name") + " "
+ rs_queue.getString("sex") + " "
+ rs_queue.getString("birthday"));
}
System.out.println(statement.executeUpdate("update user set sex='女' where id=1"));
rs_queue.close();
statement.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

JDBC标准代码设计

  实际工程中使用JDBC的标准写法

package fileTransfer;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle; public class DBUtils { private static String driverClass;
private static String url ;
private static String userName;
private static String password;
private static Connection connection = null; static{
//读取配置文件,加载数据库相关信息
ResourceBundle resourceBundle = ResourceBundle.getBundle("info");
driverClass = resourceBundle.getString("driverClass");
url = resourceBundle.getString("url");
userName = resourceBundle.getString("userName");
password = resourceBundle.getString("password"); try {
Class.forName(driverClass);
} catch (Exception e) {
System.out.println(e.toString()+"加载驱动失败!");
}
} public static Connection getConnection(){ try {
connection = DriverManager.getConnection(url, userName, password);
} catch (SQLException e) {
// TODO Auto-generated catch block
System.out.println(e.toString()+"数据库连接失败!");
}
return connection;
} public static void CloseAll(ResultSet resultSet, PreparedStatement pStatement, Connection connection){
if (resultSet!=null) {
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} if (pStatement != null) {
try {
pStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

JDBC标准工程写法

  四、JDBC连接池

  实际工程中应该考虑下面的问题:建立数据库连接需要开销,因为数据库连接是有限的资源,如果用户要离开应用一段时间,那么他占用的连接就不应该保持打开状态;另一方面,每次查询都获取连接并在随后关闭它的代价也是相当高的。

  解决上述问题的方法时建立数据库连接池(pool),这意味着数据库连接在物理上并为关闭,而是保留在一个队列中并被反复重用。

  连接池的使用对程序员来说是完全透明的,可以通过获取数据源并调用getConnection方法来得到连接池中的连接。使用完连接后,需要调用close()方法,该方法不再物理上关闭连接,而是只告诉连接池已经使用完该连接,将Connection对象返回到LinkedList对象中。

  1.编写连接池需要实现java.sql.DataSource接口

  2.创建LinkedList对象,并创建“最小连接数”个Connection对象并将这些对象添加到LinkedList对象中

  3.重写getConnection方法,使用动态代理技术管理连接池中的Connection对象

  4.封装getConnection()方法和release()方法

  示例代码

  • 配置文件jdbc.properties
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mysqldb?useSSL=false
userName = root
password = bjtungirc ConnectionPoolInitSize = 10

jdbc.properties

  • 连接池类ConnectionPool
  1. 初始化:通过ResourceBundle.getBundle("jdbc")读取jdbc.properties里面的配置内容,然后初始化新建立默认的最小数据库连接对象10个Connection对象,并将这些对象加入到由LinkedList类实现的链表中。

    public class ConnectionPool implements DataSource {
    
        private static String driver;
    private static String url ;
    private static String userName;
    private static String password;
    private static int ConnectionPoolInitSize; private static LinkedList<Connection> conn_list = new LinkedList<>(); static { try {
    ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc");
    driver = resourceBundle.getString("driver");
    url = resourceBundle.getString("url");
    userName = resourceBundle.getString("userName");
    password = resourceBundle.getString("password");
    ConnectionPoolInitSize = Integer.parseInt(resourceBundle.getString("ConnectionPoolInitSize"));
    Class.forName(driver);
    for (int i = 0; i < ConnectionPoolInitSize; i++) {
    Connection conn = DriverManager.getConnection(url, userName, password);
    conn_list.add(conn);
    }
    } catch (SQLException e) {
    e.printStackTrace();
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    } catch (Exception e) {
    e.printStackTrace();
    }
    } @Override
    public Connection getConnection() throws SQLException {
    ...
    }
    }
  2. getConnection()方法的重写:执行该方法会从LinkedList链表中拿出一个Connection对象conn并返回,然后通过动态代理实现:如果拿出来的这个conn对象执行了close方法,就将这个conn对象重新放回到LinkedList链表中。
        @Override
    public Connection getConnection() throws SQLException {
    if (conn_list.size()>0) {
    final Connection conn = conn_list.removeFirst();
    System.out.println(1);
    return (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() { @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (!method.getName().equalsIgnoreCase("close")) {
    return method.invoke(conn, args);
    } else {
    conn_list.add(conn);
    return null;
    }
    }
    });
    } else {
    System.out.println("数据库连接失败");
    }
    return null;
    }
  • 封装的JDBC连接类DBUtils类(包括了getConnection方法和closeAll方法)

    package connPool.jun.iplab;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException; public class Get_jdbc_conn_from_cPool { private static ConnectionPool cPool = new ConnectionPool(); public static Connection getConnection() throws SQLException{
    return cPool.getConnection();
    } public static void CloseAll(ResultSet resultSet, PreparedStatement pStatement, Connection connection){
    if (resultSet!=null) {
    try {
    resultSet.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    } if (pStatement != null) {
    try {
    pStatement.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    if(connection != null){
    try {
    connection.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }
    }
  • 测试类
    package connPool.jun.iplab;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement; public class CPoolTest { public static void main(String[] args) throws SQLException { // 得到数据库连接对象
    Connection conn = DBUtils.getConnection();
    // 数据库操作
    Statement statement = conn.createStatement();
    ResultSet rs = statement.executeQuery("select * from user where sex='男'");
    while (rs.next()) {
    System.out.println(rs.getInt("id") + " "
    + rs.getString("name") + " "
    + rs.getString("sex") + " "
    + rs.getString("birthday"));
    }
    // 执行这条语句时,conn对象执行了close()方法,因此会将conn对象重新添加到LinkedList集合中
    DBUtils.CloseAll(rs, statement, conn);
    }
    }
  • 输出
    2 lsl 男  2017-12-12
    4 winner 男 2018-08-07
    9 nine 男 2018-08-07
    ResultSet对象已关闭
    Statement对象已关闭
    Connection对象已关闭

Java基础(三十二)JDBC(2)连接数据库的更多相关文章

  1. “全栈2019”Java第三十二章:增强for循环Foreach语法

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  2. Bootstrap <基础三十二>模态框(Modal)插件

    模态框(Modal)是覆盖在父窗体上的子窗体.通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动.子窗体可提供信息.交互等. 如果您想要单独引用该插件的功能,那么您需要引用  ...

  3. Java进阶(三十二) HttpClient使用详解

    Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...

  4. Java基础(十二):包(package)

    一.Java 包(package): 为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间.包的作用: 1.把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用. 2.如同文件夹 ...

  5. javaweb学习总结(三十二)——JDBC学习入门

    一.JDBC相关概念介绍 1.1.数据库驱动 这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡 ...

  6. java基础(十二章)

    一.变量的作用域(有效的使用范围) 1.变量有2种 1.1成员变量(属性) 声明在类的里面,方法的外面 1.2 局部变量 声明在方法里面或for循环结构中 2.调用时的注意事项(初始值不同.作用域不同 ...

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

    一.JDBC相关概念介绍 1.1.数据库驱动 这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡 ...

  8. Java基础(十二)IO输入输出

    一.IO 概述 1.IO 概念 IO:I 代表 Input 输入:O 代表 Output 输出. Java 中 IO 是以流为基础进行输入输出,所有的数据被串行化(保存)写入输出流,或者从输入流读入. ...

  9. 夯实Java基础(十二)——异常处理

    1.异常处理概述 在Java程序执行过程中, 总是会发生不被期望的事件, 阻止程序按照程序员预期正常运行, 这就是Java程序出现的异常. 异常处理是基于面向对象的一种运行错误处理机制,通过对异常问题 ...

  10. java基础第十二篇之集合、增强for循环、迭代器和泛型

    Collection接口中的常用方法: * 所有的子类子接口都是具有的 * 集合的方法:增删改查 * * public boolean add(E e);//添加元素 返回值表示是否添加成功 * pu ...

随机推荐

  1. Spring常犯的十大错误,你踩过吗?

    1.错误一:太过关注底层 我们正在解决这个常见错误,是因为 "非我所创" 综合症在软件开发领域很是常见.症状包括经常重写一些常见的代码,很多开发人员都有这种症状. 虽然理解特定库的 ...

  2. IT修养-基础篇

    1.科学基础 成为开发人员的过程不尽相同,有的是科班出身,有的是兴趣爱好,还有的是专业机构的培训,在这个过程中,可能全面或者零散甚至没有学习过计算机基础学科,但无论是哪一种,想要成为更高层次的开发人员 ...

  3. Python学习笔记整理总结【MySQL】

    一. 数据库介绍 1.什么是数据库?数据库(Database)是按照数据结构来组织.存储和管理数据的仓库.每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据.我们也可以将 ...

  4. 基于WeChat的消息存储备份、远程控制、小功能项目开源分享计划

    WeChat+ 关于该项目 起源 该项目的起因是一个比较程(老)序(油)猿(条)的理由,有一天我发现我下班时间比较早,有点尴尬,但是又不想没事干还坐在公司,那么如何解决我的问题呢,初步想法是远程控制电 ...

  5. 前端基于VUE的v-charts的曲线显示

    目录 前端基于VUE的v-charts的曲线显示 1. 应用背景 2. 分析数据生产者生成 3. 取出数据消费者 4. 前端显示 4.1 安装V-charts插件 4.2 引入veline曲线插件 4 ...

  6. Hadoop点滴-何时使用hadoop fs、hadoop dfs与hdfs dfs命令

    何时使用hadoop fs.hadoop dfs与hdfs dfs命令 编辑 删除 hadoop fs:使用面最广,可以操作任何文件系统. hadoop dfs与hdfs dfs:只能操作HDFS文件 ...

  7. java进阶文章优选链接,面试干货集合

    Java多线程: java多线程详细总结:https://blog.csdn.net/chenruijia170707/article/details/78505351 ThreadLocal 用法及 ...

  8. git 查看分支

    1.查看本地分支 git branch 2.查看所有分支 git branch -a 2.查看所有分支及对应版本信息 git branch -va

  9. VR应用评测 - Luna

    Luna http://store.steampowered.com/app/605770/Luna/ Steam VR 2017年10月发布 | 开发者:Funomena | 好评率92% 一款制作 ...

  10. Scala和Java混合项目搭建:(Eclipse)

     Scala和Java混合项目搭建:(Eclipse)  项目结构: pom.xml: <project xmlns="http://maven.apache.org/POM/4.0. ...