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 ...
随机推荐
- Spring MVC-从零开始-view-向页面传递data(ModelAndView)
1.applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans ...
- springmvc(三)
Spring MVC上传 Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的.SpringMVC使用Apache Commons FileU ...
- openstack问题记录
先去查看对应的日志:/var/log/,再来排查错误 1.实例处于错误状态 解决办法: 1.使用openstack hypervisor list查看 2.然后openstack hypervisor ...
- LeetCode 题解汇总
前言 现如今,对于技术人员(软开.算法等)求职过程中笔试都是必不可少的(免笔试的除外,大部分人都需要笔试),而笔试一般组成都是选择.填空.简答题.编程题(这部分很重要),所以刷题是必不可少的:对于应届 ...
- 一步一步带你在VS 2017中配置OpenGL
在VS2017环境中配置OpenGL,我们分三步:配置GLFW.配置GLAD.导出项目模板. 配置GLFW 1.首先下载GLFW,点击这里,进入Github下载. 或者 点击这里从百度云下载,提取码为 ...
- 4、pytest 中文文档--pytest-fixtures:明确的、模块化的和可扩展的
目录 1. fixture:作为形参使用 2. fixture:一个典型的依赖注入的实践 3. conftest.py:共享fixture实例 4. 共享测试数据 5. 作用域:在跨类的.模块的或整个 ...
- 04-12 scikit-learn库之随机森林
目录 scikit-learn库之随机森林 一.RandomForestClassifier 1.1 使用场景 1.2 代码 1.3 参数 1.4 属性 1.5 方法 二.RandomForestRe ...
- A-05 前向选择法和前向梯度法
目录 前向选择法和前向梯度法 一.前向选择法 1.1 余弦相似度求投影 1.2 举例 1.3 前向选择法优缺点 1.3.1 优点 1.3.2 缺点 二.前向梯度法 2.1 举例 2.2 前向梯度法优缺 ...
- js构造函数的浅薄理解
任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数 如:任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数 : fuction Preson(){...} var pres ...
- 云计算之走进LINUX(一)
引言 小比特的随笔: 亲爱的博友所有随笔部分记录的是小比特的一些学习笔记,阅读性不是太强仅供有基础的博友参考,对小白来说阅读起来可能会有些吃力.当然也可以参考啦!小比特将在文章部分提供详细的内容介绍供 ...