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 ...
随机推荐
- eclipse导入别的项目后发现jdk版本不一样,该如何解决呢?
当我们导入其他人的项目的时候,发现导入的项目的jdk版本与我们使用电脑上的版本不同,该如何解决呢? 选中项目右键 --> Properties --> Build Path --> ...
- MonkeyRunner学习笔记(1)
MonkeyRunner是java编程语言实现的Python写出来的一个API调用工具 MonkeyRunner有三个类:MonkeyRunner,MonkeyDevice,MonkeyImage M ...
- linux mint 17编译android 2.3.1错误记录
有转载这里的也有添加的. ################# Fix 1 ########################## Error: frameworks/base/include/utils ...
- grep 命令使用
grep是Linux中最常用的"文本处理工具"之一,用于在文本中查找指定的字符串. 语法: grep [OPTION]... PATTERN [FILE]... 参数: -i:在搜 ...
- Java 基本数据类型极限值
public static void main(String[] args){ System.out.println("Integer.MIN_VALUE = " + Intege ...
- mysql 对返回字段进行拼接
使用concat函数进行拼接:示例如下: select id,username,concat( id, '-' , username) as idName from user;
- Mysql触发器实例分析
所谓触发器,就是在定义在表对象上.当触发器所在的表出现指定的事件时,会触发对应表的delete update insert的操作.说的有点绕口,其实就是到监视某种情况,然后去触发某种操作. 触发器是如 ...
- package.json详解
1.概念 Node.js项目遵循模块化的架构,当我们创建了一个Node.js项目,意味着创建了一个模块,这个模块的描述文件,被称为package.json 亦即:模块的描述文件 = package.j ...
- Inkscape 旋转并复制
画一个图形,点击图标. 然后图标中心有个十字叉, 然后把这个十字叉拖到你想要旋转的地方. 然后shift+ctrl+m打开变换菜单. 选择旋转选项卡,然后设置角度,点击应用.就可以旋转了,如果配合ct ...
- Executor线程池原理详解
线程池 线程池的目的就是减少多线程创建的开销,减少资源的消耗,让系统更加的稳定.在web开发中,服务器会为了一个请求分配一个线程来处理,如果每次请求都创建一个线程,请求结束就销毁这个线程.那么在高并发 ...