Java基础(三十二)JDBC(2)连接数据库
一、连接数据库的过程
连接数据库的过程:加载数据库驱动程序,不过只需在第一次访问数据库时加载一次,然后在每次访问数据库时创建一个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
- 初始化:通过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 {
...
}
} - 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)连接数据库的更多相关文章
- “全栈2019”Java第三十二章:增强for循环Foreach语法
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Bootstrap <基础三十二>模态框(Modal)插件
模态框(Modal)是覆盖在父窗体上的子窗体.通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动.子窗体可提供信息.交互等. 如果您想要单独引用该插件的功能,那么您需要引用 ...
- Java进阶(三十二) HttpClient使用详解
Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...
- Java基础(十二):包(package)
一.Java 包(package): 为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间.包的作用: 1.把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用. 2.如同文件夹 ...
- javaweb学习总结(三十二)——JDBC学习入门
一.JDBC相关概念介绍 1.1.数据库驱动 这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡 ...
- java基础(十二章)
一.变量的作用域(有效的使用范围) 1.变量有2种 1.1成员变量(属性) 声明在类的里面,方法的外面 1.2 局部变量 声明在方法里面或for循环结构中 2.调用时的注意事项(初始值不同.作用域不同 ...
- avaweb(三十二)——JDBC学习入门
一.JDBC相关概念介绍 1.1.数据库驱动 这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡 ...
- Java基础(十二)IO输入输出
一.IO 概述 1.IO 概念 IO:I 代表 Input 输入:O 代表 Output 输出. Java 中 IO 是以流为基础进行输入输出,所有的数据被串行化(保存)写入输出流,或者从输入流读入. ...
- 夯实Java基础(十二)——异常处理
1.异常处理概述 在Java程序执行过程中, 总是会发生不被期望的事件, 阻止程序按照程序员预期正常运行, 这就是Java程序出现的异常. 异常处理是基于面向对象的一种运行错误处理机制,通过对异常问题 ...
- java基础第十二篇之集合、增强for循环、迭代器和泛型
Collection接口中的常用方法: * 所有的子类子接口都是具有的 * 集合的方法:增删改查 * * public boolean add(E e);//添加元素 返回值表示是否添加成功 * pu ...
随机推荐
- 小红书第五章——引用类型之function类型
有趣的函数——function类型 函数实际上是对象,每个函数都是function类型的实例,具有属性和方法. 1.函数的定义方法 1)函数声明语法 function sum(num1,num2){/ ...
- Mycat 配置文件rule.xml
rule.xml配置文件定义了我们对表进行拆分所涉及到的规则定义.我们可以灵活的对表使用不同的分片算法,或者对表使用相同的算法但具体的参数不同. 该文件里面主要有tableRule和function这 ...
- <机器学习>无监督学习算法总结
本文仅对常见的无监督学习算法进行了简单讲述,其他的如自动编码器,受限玻尔兹曼机用于无监督学习,神经网络用于无监督学习等未包括.同时虽然整体上分为了聚类和降维两大类,但实际上这两类并非完全正交,很多地方 ...
- Windows Terminal 安装及美化
windows terminal 是今年微软Build大会上推出的一款的全新终端,用来代替cmder之类的第三方终端.具有亚克力透明.多标签.Unicode支持(中文,Emoji).自带等宽字体等这些 ...
- InnoDB引擎的启动过程
一 前言 一直对InnoDB引擎的启动过程不太了解,查资料整理了下InnoDB引擎启动的过程和关闭过程,后续会整理些有关redo undo 的知识点. 二 思维导图 三 参考文章 MySQL运维内 ...
- Mac 安装node npm cnpm vue 以及卸载 node 和 npm 的方法 清空npm缓存的方法
S01 安装node(内含npm) 首先,到官网下载长期支持版,截止目前,最新的长期支持版本号是10.16.3 https://nodejs.org/zh-cn/download/ 下载完毕后,安装该 ...
- RDD基础-笔记
RDD编程 基础Spark中的RDD是一个不可变的分布式对象集合.每个RDD都被分为多个分区,这些分区运行在集群中的不同节点上.RDD可以包含Python.java.Scala中任意类型的对象,甚至可 ...
- 无意间做了个 web 版的 JVM 监控端(前后端分离 React+Spring Boot)
之前写了JConsole.VisualVM 依赖的 JMX 技术,然后放出了一个用纯 JMX 实现的 web 版本的 JConsole 的截图,今天源码来了. 本来就是为了更多的了解 JMX,第一步就 ...
- Android OkHttp + Retrofit 取消请求的方法
本文链接 前言 在某一个界面,用户发起了一个网络请求,因为某种原因用户在网络请求完成前离开了当前界面,比较好的做法是取消这个网络请求.对于OkHttp来说,具体是调用Call的cancel方法. 如何 ...
- display——table-cell属性
display的table和table-cell一般情况下用的不多,所以很少有人去关注它,但他们两个联手起来会给你惊喜! 当两个或者两个以上标签一起使用显示在同一行时,以前常用的是float.posi ...