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 ...
随机推荐
- 第六届蓝桥杯java b组第四题
第四题 两个整数做除法,有时会产生循环小数,其循环部分称为:循环节. 比如,11/13=6=>0.846153846153….. 其循环节为[846153] 共有6位. 下面的方法,可以求出循环 ...
- hadoop之mapreduce详解(基础篇)
本篇文章主要从mapreduce运行作业的过程,shuffle,以及mapreduce作业失败的容错几个方面进行详解. 一.mapreduce作业运行过程 1.1.mapreduce介绍 MapRed ...
- Oracle clob列union的方法(ORA-00932)
今天在做“站内搜索”数据抽取时,为了能将多个相似的数据库表数据合并,使用了SQL中union关键字,期望将多个单独的SQL查询结果合并到一起.每个单独的SQL都能成功执行,在union合并的过程中遇到 ...
- 【ASP.NET-中级】SQLHelper数据访问公共类
ASP.NET开发中的三层开发思想指的是UI层(界面显示层),BLL层(业务逻辑层),DAL层(数据访问层)三层,三层之间通过函数的调用来达到降低耦合,易于系统维护的目的,SQLHelper助手类的主 ...
- JS/jQuery点击某元素之外触发事件
JQuery // 第一步:点击任何地方都触发事件 $(document).click(function(){ alert("点击当前页面的任何地方都触发此点击事件:"); }); ...
- Kafka 学习笔记之 Kafka0.11之producer/consumer(Scala)
Kafka0.11之producer/consumer(Scala): KafkaConsumer: import java.util.Properties import org.apache.kaf ...
- 面试|简单描述MySQL中,索引,主键,唯一索引,联合索引 的区别,对数据库的性能有什么影响(从读写两方面)
索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们 包含着对数据表里所有记录的引用指针. 普通索引(由关键字 KEY 或 INDEX 定义的索引)的唯一任务是加快对数据的 ...
- 你所不知道的TIME_WAIT和CLOSE_WAIT
你遇到过TIME_WAIT的问题吗? 我相信很多都遇到过这个问题.一旦有用户在喊:网络变慢了.第一件事情就是,netstat -a | grep TIME_WAIT | wc -l 一下.哎呀妈呀,几 ...
- C#中winform中panel重叠无法显示问题
C#中winform中panel重叠无法显示问题: 最近开发一个项目有个需求是需要多个模式来回切换的,本来考虑使用多个窗口来实现这个功能,但是这样做浪费资源,而且工作量大,所以想到使用panel控件来 ...
- 06-01 DeepLearning-图像识别
目录 深度学习-图像识别 一.人脸定位 二.手工提取特征的图像分类 2.1 识图认物 2.2 传统分类系统的特征提取 2.3 计算机眼中的图像 2.4 什么是图像特征? 2.5 卷积运算 2.6 利用 ...