java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、
一、JDBC的概述
1.JDBC为访问不同的数据薛是供了统一的接口,为使用者屏蔽了细节问题。
2. Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。
二。JDBC带来的好处
java程序可以直接对数据库进行调用,但是没有很好的移植性(对用于不同的数据库),所以不推荐
JDBC带来的好处:JDBC是java提供一套用于数据库操作的接口API,Java程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口,提供不同实现。
JDBC API:JDBC API 是一系列的接口,它统一和规范了应用程序与数据库的连接,执行SQL语句,并得到返回结果等各类操作;
JDBC程序编写步骤
1、注册驱动 --- 加载Driver类
2、获取连接 --- 得到Connection
3、执行增删改查 --- 发送Sql给mysql执行
4、释放资源 --- 关闭相关连接
获取数据库连接的5种方式:
方式1:使用(com.mysql.jdbc.Driver)com.mysql.cj.jdbc.Driver,属于静态加载,灵活性差,依赖性强
方式2:使用反射机制,属于静态加载
方式3:使用DriverManager替代driver进行统一管理
方式4:使用Class.forName自动完成注册驱动,简化代码
这种方式连接是使用得最多的(推荐使用)
在底层会完成注册:
提示:
(1)mysql驱动5.1.6可以无需Class.forName(“com.mysql.jdbc.Driver”);
(2)从jdk1.5以后使用了jdbc4,不再需要显示调用class.forName()注册驱动而是自动调用驱动jar包下META-INF\servicesljava .sql.Driver文本中的类名称去注册
(3)建议加上Class.forName(“com.mysql.jdbc.driver”),能够更加明确的感受到程序流程,利于掌握;
方式5:利用properties文件配置数据库需要的相关的配置
更加的灵活,可以直接通过properties配置文件修改数据库连接相关的数据
对方式5的实例:
//properties配置文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
user=root
password=123456
//连接数据库的相关操作
import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; public class jdbc02 {
public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
//创建一个properties对象
Properties properties = new Properties();
//加载和获取创建的properties的相关数据
properties.load(new FileInputStream("src\\db.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password"); String sql = "insert into actor values (null,'王五','男','1975-11-23','110')"; //driver驱动,也可以不加,但是加上更容易读懂流程
Class.forName(driver);
//连接和执行操作
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
statement.executeUpdate(sql);
//关闭连接
System.out.println("连接"+connection);
statement.close();
connection.close(); }
}
三、RestSet【结果集】
基本介绍:
1.表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
2. ResultSet对象保持一个光标指向其当前的数据行。最初,光标位于第一行之前
3. next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回
false,因此可以在while循环中使用循环来遍历结果集
简单测试:
四、Statement:
基本介绍:
1.Statement对象用于执行静态SQL语句并返回其生成的结果的对象
2.在连接建立后,需要对数据库进行访问,执行命名或是SQL语句,可以通过
Statement【存在SQL注入】
PreparedStatement【预处理】
CallableStatement【存储过程】
3. Statement对象执行SQL语句,存在SQL注入风险
4.SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库。
5.要防范SQL注入,只要用 PreparedStatement(从Statement扩展而来)取
代 Statement就可以了
import java.io.*;
import java.sql.*;
import java.util.Properties; public class jdbc02 {
public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
//创建一个properties对象
Properties properties = new Properties();
//加载和获取创建的properties的相关数据
properties.load(new FileInputStream("src\\db.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password"); String sql = "insert into actor values (null,'三毛','男','1975-11-23','110')";
String sql1 = "select id,name from actor"; //driver驱动,也可以不加,但是加上更容易读懂流程
Class.forName(driver);
//连接和执行操作
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
// statement.executeUpdate(sql); // String sql1 = "select id,name from actor";
ResultSet resultSet = statement.executeQuery(sql1);
while (resultSet.next()) {
int i = resultSet.getInt(1);
String string1 = resultSet.getString(2);
System.out.println(i+"=="+string1);
}
//关闭连接
resultSet.close();
System.out.println("连接"+connection);
statement.close();
connection.close(); }
}
PrepareStatement:
1. PreparedStatement 执行的SQL语句中的参数用问号(?)来表示,调用
PreparedStatement对象的setXxx()方法来设置这些参数. setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值
2.调用executeQuery),返回ResultSet 对象
3.调用executeUpdate):执行更新,包括增、删、修改
预处理的好处:
1.不再使用+拼接sql语句,减少语法错误
2.有效的解决了sql注入问题!
3.大大减少了编译次数,效率较高
对preparestatement的测试代码,配置文件还是上面的配置文件
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties; public class PrepareStatement {
public static void main(String[] args) throws Exception { Properties properties = new Properties();
properties.load(new FileInputStream("src\\db.properties"));
String drive = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password"); //更新操作
// String sql = "update actor set phone = ? where name = ?";
//删除操作
// String sql = "delete from actor where name = ?";
// 添加操作
// String sql = "insert into actor values(null,?,?,?,?)";
//查询操作
String sql = "select * from actor"; Class.forName(drive); Connection connection = DriverManager.getConnection(url, user, password); PreparedStatement preparedStatement = connection.prepareStatement(sql);
//更改操作
// preparedStatement.setString(1, "123456");
// preparedStatement.setString(2, "三毛");
//删除操作
// preparedStatement.setString(1, "二狗");
//添加操作
// preparedStatement.setString(1, "张三");
// preparedStatement.setString(2, "男");
// preparedStatement.setString(3, "1975-11-23 00:00:00");
// preparedStatement.setString(4,"456789");
// int i = preparedStatement.executeUpdate();
// System.out.println(i >0 ? "成功" : "失败"); //查询操作
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString(2));
} preparedStatement.close();
connection.close(); }
}
总结:
五、事务:将多行代码当做SQL事务来处理,主要流程需要的关键代码:
connection.setAutoCommit(false);//取消自动提交的操作,取消之后,会在提及之后完成事务
connection.commit();提交事务
connection.rollback();//用于回退事务
批处理:
基本介绍:
1、当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允
许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
2、JDBC的批量处理语句包括下面方法:
addBatch():添加需要批量处理的SQL语句或参数executeBatch(:执行批量处理语句;
clearBatch():清空批处理包的语句
3、 JDBC连接MySQL时,如果要使用批处理功能,请再url中加参
数?rewriteBatchedStatements=true
4、批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高
过程:
(1)将sql语句加入到批处理包中
preparedStatement.addBatch();
preparedStatement.addBatch(sql);
(2)执行sql和清空sql
//批量执行sql语句
preparedStatement.executeBatch();
//清除批量的sql语句
preparedStatement.clearBatch();
将 SQL加入到批处理包中源码所做的事情:
六、数据库连接池
传统connection问题分析:
1.传统的JDBC数据库连接使用 DriverManager来获取,每次向数据库建立
连接的时候都要将Connection 加载到内存中,再验证IP地址,用户名和密码(0.05s~1s时间)。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器崩溃。2每一次数据库连接,使用完后都得断开,如果程序出现异常面未能关闭,将
导致数据库内存泄漏,最终将导致重启数据库。
3.传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致
内存泄漏,MySQL崩溃。
4.解决传统开发中的数据库连接问题,可以采用数据库连接池技术
(connection pool).
数据库连接池基本介绍:
1.预先在缓冲池中放入一定数量的连接,,当需
要建立数据库连接时,只需从“缓冲池”中取出一个,,使用完毕之后再放回去。
2.数据库连接池负责分配、管理和释放数据库
连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
3.当应用程序向连接池请求的连接数超过最大
连接数量时,这些请求将被加入到等待队列中
数据库连接池示意图:
数据库连接池种类:
1.JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource
只是一个接口,该接口通常由第三方提供实现
2.C3PO 数据库连接池,速度相对较慢,稳定性不错(hibernate, spring)
3.DBCP数据库连接池,速度相对c3p0较快,但不稳定
4. Proxool数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
5.BoneCP数据库连接池,速度快
6.Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3P0、Proxool
优点于身的数据库连接池
测试:C3P0连接池的连接(需要导入第三方库:c3p0的jar包)
第一个C3P0连接的配置文件还是上面的配置文件内容
第二个C3P0的连接需要有一个xml配置文件
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.jupiter.api.Test; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; public class ConDatasource {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\db.properties"));
String driver = properties.getProperty("driver");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url"); //建立comboPooledDataSource管理连接池
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password); //设置初始化连接数和最大连接数
comboPooledDataSource.setInitialPoolSize(10);
comboPooledDataSource.setMaxPoolSize(50);
//这个方法就是从DataSource接口实现的
Connection connection = comboPooledDataSource.getConnection();
System.out.println("1连接成功");
connection.close(); } @Test
public void ConDatasource02() throws SQLException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("test_C3P0"); long start = System.currentTimeMillis();
System.out.println("测试连接5000次需要的时间");
for (int i = 0; i < 5000; i++) {
Connection connection = comboPooledDataSource.getConnection();
// System.out.println("2连接成功");
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("花费时长:"+(end-start));
}
}
//第二种方式的xml文件
<c3p0-config> <named-config name="test_C3P0">
<!-- 驱动类 -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<!-- url-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC</property>
<!-- 用户名 -->
<property name="user">root</property>
<!-- 密码 -->
<property name="password">123456</property>
<!-- 每次增长的连接数-->
<property name="acquireIncrement">5</property>
<!-- 初始的连接数 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!-- 最大连接数 -->
<property name="maxPoolSize">10</property> <!-- 可连接的最多的命令对象数 -->
<property name="maxStatements">5</property> <!-- 每个连接对象可连接的最多的命令对象数 -->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>
测试:Druid连接池的连接(需要第三方库druid的jar包)
package com.zjl.jdbc; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.util.Properties; public class Druidsource {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\druid.properties"));//如下定义的配置文件 DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
long start = System.currentTimeMillis();
for (int i = 0;i < 500000;i++ ) {
Connection connection = dataSource.getConnection();
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("Druid连接5000 次需要的时间:" + (end - start));//Druid连接500000 次需要的时间:625
}
}
//连接中需要的一个配置文件
druid.properties:放在src目录下
#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
#url=jdbc:mysql://localhost:3306/girls
username=root
password=123456
#initial connection Size初始连接数
initialSize=10
#min idle connecton size最小等待连接数
minIdle=5
#max active connection size最大连接数
maxActive=20
#max wait time (5000 mil seconds)
# 最大等待时间,时间超过就结束这次连接等待下一次的连接
maxWait=5000
注意:对于c3p0和Druid他们的close()是按照第三方库的连接方式,仅仅是将从连接池引用的数据库连接断开(放弃引用)
重新将连接放回到连接池中,和原生 的jdbc连接中的close方法断开连接不同;
用Druid创建一个连接和断开的工具类;
package com.zjl.jdbc; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; public class JDBCUtilsByDruid {
static DataSource ds;
static {
Properties properties = new Properties(); try {
properties.load(new FileInputStream("src\\druid.properties"));
ds = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//编写获取Connection的方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
} public static void close(ResultSet resultSet, Statement statement, Connection connection) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
//将编译异常转成运行异常抛出
throw new RuntimeException(e);
}
}
}
七、Apache-DBUtils
1、问题引出:在使用Druid连接数据库,返回结果集之后,如果断开连接,结果集就不能够再使用。解决方法如图,将返回的结果集保存到一个泛型列表中,那么当数据库连接断开后,还是可以使用返回的结果集。
2、对Apache-DBUtils的基本介绍
1).commons-dbutils 是 Apache组织提供的一个开源 JDBC工具类库,它是对JDBC的封装,
使用dbutils能极大简化jdbc编码的工作量[真的]。
DbUtils类
(1). QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理
(2).使用QueryRunner类实现查询
(3). ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式
对该DBUtils进行测试:需要对应的jar包(commons-dbutils-1.7.jar)可以去:http://commons.apache.org/下载
相应的JDBCUtilsByDruid类是上面的测试类:
package com.zjl.jdbc; import com.zjl.bean.Actor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List; public class TestDBUtils {
public static void main(String[] args) throws Exception {
String sql = "select * from `actor`";
//从Druid中获取一个连接
Connection connection = JDBCUtilsByDruid.getConnection();
//引入DBUtils的jar包,并获得一个QueryRunner对象
QueryRunner queryRunner = new QueryRunner(); //利用QueryRunner对象就可以直接查询数据库,执行SQl语句,返回结果封装到ArrayList集合中
// connection是一个连接,sql是一个执行语句
//new BeanListHandler<>(Actor.class):在将resultSet中的结果以Actor对象方式封装到ArrayList
//底层使用反射机制,获取Actor类的属性,然后进行封装
//1就是给sql 语句中的?赋值,可以有多个值,因为是可变参数0bject... params
// List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
//如果要返回单个查询数据就使用BeanHandler<>(Actor.class),返回结果就会是单个对象或者为空
List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class));
//在底层会得到resultSet并在query中关闭,也会在底层使用preparedStatement并关闭
// JDBCUtilsByDruid.close(null, null, connection);
Iterator<Actor> iterator = list.iterator();
while (iterator.hasNext()) {
Actor next = iterator.next();
System.out.println(next);
}
//进行更新操作
String updateSql = "update `actor` set name = ? where id = ?";
int update = queryRunner.update(connection, updateSql, "王无无", 8);
System.out.println((update > 0) ? "更新成功" : "更新失败");
//进行删除操作
String delSql = "delete from `actor` where id = ?";
int update1 = queryRunner.update(connection, delSql, 10);
System.out.println((update > 0) ? "删除成功" : "删除失败"); //关闭资源
JDBCUtilsByDruid.close(null, null, connection);
} }
八、BasicDao--DAO和增删改查通用方法(DAO:data access object 数据访问对象)
基本说明:
1)、 DAO:data access object数据访问对象
2)、这样的通用类,称为 BasicDao,是专门和数据库交互的,即完成对数据库(表)的crud操作。
3)、在BaiscDao的基础上,实现一张表对应一个Dao,更好的完成功能;
关系图如下:
java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、的更多相关文章
- 通过实现ServletContextListener接口创建数据库连接池(C3P0方式)
使用Listener步骤 1. 定义Listener实现类 2. 在web.xml中配置(或使用Annotation) 使用C3P0方式创建数据库连接池需要添加的jar包 1.c3p0-0.9.5.j ...
- Java中数据库连接池原理机制的详细讲解以及项目连接数据库采用JDBC常用的几种连接方式
连接池的基本工作原理 1.基本概念及原理 由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理.我们知道,对于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式 ...
- 网络协议 finally{ return问题 注入问题 jdbc注册驱动问题 PreparedStatement 连接池目的 1.2.1DBCP连接池 C3P0连接池 MYSQL两种方式进行实物管理 JDBC事务 DBUtils事务 ThreadLocal 事务特性 并发访问 隔离级别
1.1.1 API详解:注册驱动 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 原因有2个: >导致驱动被注册2 ...
- java基础 JDBC & Statement & PreparedStatement
参考文章: http://blog.csdn.net/wang379275614/article/details/23393335 概念 JDBC-数据库连接,是由一些类和接口构成的API,是J2SE ...
- Lucene搜索方式大合集
package junit; import java.io.File; import java.io.IOException; import java.text.ParseException; imp ...
- Jmeter连接数据库方式
关系型数据库: 1.mysql: 方式:Database URL:jdbc:mysql://localhost:port/DBname?user=**&password=**&allo ...
- ipv6下jdbc的连接数据库方式
ipv6下jdbc的连接数据库方式 MySQL: ipv4 Driver URL: jdbc:mysql://127.0.0.1:3306/database ipv6 Driv ...
- 基于已有集群动态发现方式部署 Etcd 集群
etcd提供了多种部署集群的方式,在「通过静态发现方式部署etcd集群」 一文中我们介绍了如何通过静态发现方式部署集群. 不过很多时候,你只知道你要搭建一个多大(包含多少节点)的集群,但是并不能事先知 ...
- 基于 DNS 动态发现方式部署 Etcd 集群
使用discovery的方式来搭建etcd集群方式有两种:etcd discovery和DNS discovery.在 「基于已有集群动态发现方式部署etcd集群」一文中讲解了etcd discove ...
随机推荐
- Win10 开启 Hyper-V 及简单使用
简介 Windows 10 上内置了 Hyper-V.Hyper-V 提供硬件虚拟化,每个虚拟机都在虚拟硬件上运行. 系统要求 Windows 10 企业版.专业版或教育版.家庭版.移动版.移动企业版 ...
- Linux登录时,下游回显非常慢
问题现象 登录linux时,远程连接正常,[root@...]回显非常慢,在执行脚本时,很容易导致命令下发错乱 原因分析 家目录下的.bash_history文件太大,导致每次登陆时读取这个文件耗时太 ...
- CentOS 7 如何清空文件内容
https://www.cnblogs.com/zqifa/p/linux-vim-4.html 方法1.在非编辑状态下使用快捷键gg跳至首行头部,再使用dG即可清空,或 输入"%d&quo ...
- js 多层 元素叠起来避免误触的解决方法
添加一层 元素,将点击事件设为 onClick="event.cancelBubble = true" 这样就能将两个可触发事件的元素给隔开
- windows更改pip源(可用)
中国科学技术大学 : https://pypi.mirrors.ustc.edu.cn/simple 清华:https://pypi.tuna.tsinghua.edu.cn/simple 豆瓣:ht ...
- spring security 关于 http.sessionManagement().maximumSessions(1);的探究
1.前言 spring security 支持对session的管理 , http.sessionManagement().maximumSessions(1);的意思的开启session管理,ses ...
- MySQL提权之启动项提权
关于MySQL的启动项提权,听其名知其意.就是将一段 VBS脚本导入到 C:\Documents and Settings\All Users\「开始」菜单\程序\启动 下,如果管理员重启了服务器, ...
- kali linux2020 虚拟机改root密码
kali在2020版的更新中,好多小伙伴登不进root账号,这里来教大家怎样改root账户的密码 1.当我们打开虚拟机看到这个界面的时候,按e进入编辑模式 2.在编辑模式中,"quite s ...
- Redisson-关于使用订阅数问题
一.前提 最近在使用分布式锁redisson时遇到一个线上问题:发现是subscriptionsPerConnection or subscriptionConnectionPoolSize 的大小不 ...
- 一条 Git 命令减少了一般存储空间,我的服务器在偷着笑
元旦不是搭建了一个<Java 程序员进阶之路>的网站嘛,其中用到了 Git 来作为云服务器和 GitHub 远程仓库之间的同步工具. 作为开发者,相信大家都知道 Git 的重要性.Git ...