2021-3-28 JDBC入门包含数据库连接池
里面的数据库连接池所需要的jar包可以在这里面下载:
https://blog.csdn.net/m0_49647974/article/details/115287069
文章目录
- 一.概念:Java DataBase Connectivity
- 二.具体流程:
- 三. 代码实现
- 四.详解各个对象:
- 1.DriverManager :驱动管理对象
- (1)注册驱动:
- (2)获取数据库连接:
- 2.Connection :数据库连接对象
- (1)获取执行中的sql对象
- (2)管理事务
- 3.Statement :执行sql的对象
- 4.Resultset :结果集对象
- 5.Preparedstatement :执行sql的对象
- 五、数据库连接池
- 1.标准接口:DataSourcejavax.sql包下的
- 2.数据库厂商实现:
- 3.C3P0:数据库连接池技术
- 4.Druid:数据库连接池实现技术(阿里巴巴)
- 六.Spring JDBC
- 记录:学习中遇到的一些bug
- 1.JDBC连接时错误:closing inbound before receiving peer's close_notify
- 2.JDBC连接时错误:
- 3.C3P0数据库连接池报错:An attempt by a client to checkout a Connection has timed out.
- 4.警告: Cannot resolve com.mysq.jdbc.Connection.ping method. Will use 'SELECT 1' instead.
一.概念:Java DataBase Connectivity
Java 数据库连接,Java语言操作数据库
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
二.具体流程:
(1)导入驱动jar包 如:mysql-connector-java-5.1.37-bin.jar
- 复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
- 右键–>Add As Library
(2)注册驱动
(3)获取数据库连接对象connection4.
(4)定义sql
(5)获取执行sql语句的对象statement6.
(6)执行sq1,接受返回结
(7)处理结果
(8)释放资源
三. 代码实现
/*** @Auther: Parsifal* @Date: 2021/03/22/20:04* @Description:*/
public class JDBCTest {public static void main(String[] args) {Connection connection = null;Statement statement = null;try {//1、导入驱动jar包//2、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//3、获取数据库连接对象String userName = "root";String password = "root";//报错一:The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to util// 解决方法与原因:当mysql和connector版本八以上时,系统时区错误,需要在配置连接数据库的url加上:?serverTimezone=GMT%2B8// 报错二: javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify//解决方法:需要在配置连接数据库的url加上: &useSSL=falseconnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=false", userName, password);//4、定义sql语句String sql = "SELECT * FROM student";//5、获取执行sql的对象、Statementstatement = connection.createStatement();boolean execute = statement.execute(sql);//6、处理结果System.out.println(execute);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();} finally {//7、关闭资源if (statement!=null){try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (connection!=null){try {connection.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}}
}
但是我们一般都会把这些代码封装成一个Util,把数据库信息写在配置文件里面,如下:
/*** @Auther: Parsifal* @Date: 2021/03/24/21:24* @Description:*/
public class JDBCUtil {private static String url;private static String user;private static String password;private static String driver;//静态模块会在类加载时执行static {FileInputStream fileInputStream = null;try {//properties处理属性文件//获取src路径下的文件的方式一(stream)Properties properties = new Properties();fileInputStream = new FileInputStream("jdbc.properties");//加载流对应的文件properties.load(fileInputStream);//获取src路径下的文件的方式二(path)
/* ClassLoader classLoader = JDBCUtil.class.getClassLoader();URL resource = classLoader.getResource("jdbc.properties");String path = resource.getPath(); //获取绝对路径System.out.println(path);properties.load(new FileReader(path));*/url = properties.getProperty("url");user = properties.getProperty("user");password = properties.getProperty("password");driver = properties.getProperty("driver");Class.forName(driver);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();} finally {if (fileInputStream!=null){try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}}}public static Connection getConnection(){try {return DriverManager.getConnection(url,user,password);} catch (SQLException throwables) {throwables.printStackTrace();}return null;}//关闭资源public static void close(Statement statement, Connection connection, ResultSet resultSet){if (statement!=null){try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (connection!=null){try {connection.close();} catch (SQLException throwables) {throwables.printStackTrace();}if (resultSet!=null){try {resultSet.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}
}//关闭资源 重载方法public static void close(Statement statement, Connection connection){if (statement!=null){try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (connection!=null){try {connection.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}
}
jdbc.properties配置文件
url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=false
user=root
password=root
driver=com.mysql.cj.jdbc.Driver
四.详解各个对象:
1.DriverManager :驱动管理对象
(1)注册驱动:
static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。
写代码使用: class.forName(“com.mysql.jdbc.Driver”); 把此类加载进内存。
(注意:在mysql5之后的驱动jar包可以省略注册驱动的步骤)
在com.mysql.jdbc.Driver类中存在以下静态代码块,在类加载时运行创建Driver类。
static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}
}
(2)获取数据库连接:
方法:DriverManager.getConnection(“jdbc:mysql://localhost:3306/test”, userName, password);
参数:
url:指定连接路径 : jdbc:mysql:// ip地址(域名): 端口 /数据库名称
用 " ?"在url后边可以添加属性,”&”可以连接不同的属性,以下举例一些属性:
serverTimezone=GMT mysql8版本以上要加上,作用为调整时区
allowMultiQueries=true,支持mybatis执行多条语句;
useSSL=false,是否进行ssl连接,高版本可能需要设为true;
serverTimezone=UTC,设置时区
uersName:用户名称,password:密码。
注意如果是本机mysql服务器,并且mysql服务默认端口为3306,则url可以不写(jdbc:mysql:///test)
2.Connection :数据库连接对象
(1)获取执行中的sql对象
- Statement createStatement() 创建Statement对象
- PreparedStatement preparedStatement(String sql)
(2)管理事务
事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败
为什么要使用事务?
首先我们先了解没有事务的时候:如果不通过事务方式管理SQL语句。此时的SQL语句的提交(commit),是由驱动程序负责管理,在SQL执行完后,就会自动帮我们进行提交,每一条SQL都相当于一个事务。但是执行多条相关联SQL语句,而不通过事务来管理时。如果再某些步骤中中止或操作失误,就会破坏数据库的一致性。(如下,由于没有通过事务sql,我有两条sql语句修改两个内容,当第一条语句执行完后,中间遇到步骤终止和操作失误,会导致第二条sql无法执行。这是很严重的后果。)
步骤:
- 开启事务: setAutocommit(boolean autocommit):调用该方法设置参数为false,即开启事务
- 提交事务: commit()
- 回滚事务: rollback()
//JDBC事务@Testpublic void test2(){Connection connection = null;Statement statement = null;PreparedStatement preparedStatement1 =null;PreparedStatement preparedStatement2 =null;try {//获取连接connection = JDBCUtil.getConnection();//开启事务connection.setAutoCommit(false);//修改id=1的学生的绩点String sql1 = " update student set name='张三' where id= ? ";//修改id=2的学生的绩点String sql2 = "update student set name='李四' where id= ? ";preparedStatement1 = connection.prepareStatement(sql1);preparedStatement2 = connection.prepareStatement(sql2);preparedStatement1.setInt(1,1);preparedStatement2.setInt(1,2);preparedStatement1.executeUpdate();//手动制造异常
// int a =1/0;preparedStatement2.executeUpdate();//提交事务connection.commit();} catch (Exception throwables) {try {//事务的回滚if (connection!=null) {connection.rollback();}} catch (SQLException e) {e.printStackTrace();}throwables.printStackTrace();} finally {JDBCUtil.close(preparedStatement1, connection);if (preparedStatement2!=null) {try {preparedStatement2.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}}
没有使用事务(两条语句中间手动制造异常,第一条语句执行)
使用事务同时无法执行(两条语句都无法执行)
3.Statement :执行sql的对象
- 执行sql语句
- boolean execute(string sql):可以执行任意的sql
- int executeUpdate(string sql)∶执行DML (insert、update、delete)语句、DDL(对表和库的操作如:create,alter,drop)语句
- 该方法的返回值是影响的行数、如果返回值>0则执行成功,反之,则失败
- Resultset executeQuery(string sql)︰执行DQL (select)语句
4.Resultset :结果集对象
常用方法:
- boolean next():游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
- getxxx(参数):获取数据xxx:代表数据类型如: int getInt() , string getstring()
- int : 代表列的编号,从1开始如:getstring(1)
- String :代表列名称。如: getDouble(“email”)
- 如图:getString(1)与getDouble(“id”)是同一个值
5.Preparedstatement :执行sql的对象
作用: 预编译sql语句防止恶意sql注入
SQL注入问题∶在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
- 输入用户随便,输入密码:a’ or "a’ = 'a
- sql : select * from user where username = 'fhdsjkf’ and password = ‘a’ or ‘a’ = ‘a’
使用方法:
(1)使用 ?占位符写sql(如 :select * from student where id = ?and grade=?)
(2)获取执行sql语句的对象Preparedstatement Connection.prepareStatement(String sql)
(3)给?赋值:格式preparedstatement.setXxx(参数1,参数2) ==>参数1:?的位置,参数2:?的值
(4)执行sql,接受返回结果,不需要传递sql语句
@Test
public void test1(){Connection connection = null;PreparedStatement preparedStatement =null;try {connection = JDBCUtil.getConnection();//使用 ?占位符写sqlString sql = "select * from student where id = ? and grade=? ";//给?赋值preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1,1);preparedStatement.setFloat(2,3.5f);ResultSet resultSet = preparedStatement.executeQuery();//处理结果while (resultSet.next()) {int id = resultSet.getInt("id");String name = resultSet.getString("name");String email = resultSet.getString("email");double grade = resultSet.getDouble("grade");System.out.println(id + name + email + grade); //结果:1 zzz 564894525@qq.com 3.5}} catch (SQLException throwables) {throwables.printStackTrace();} finally {JDBCUtil.close(preparedStatement, connection);}}
五、数据库连接池
概念::其实就足一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
好处:
- 节约资源
- 用户访问高效
实现:
1.标准接口:DataSourcejavax.sql包下的
- 方法∶
- 获取连接:getConnection()
- 归还连接:connection.close()。如果连接对貌Connection是从连接池中获取的,那么调用connection.close()方法,则不会再关闭连接了。而是归还连接
2.数据库厂商实现:
- C3P0:数据库连接池技术
- Druid:数据库连接池实现技术(阿里巴巴)
3.C3P0:数据库连接池技术
- 导入jar两个 c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar
- 定义配置文件:
- 名称:c3p0.properties 或者 c3p0-config.xml (注意:C3P0只能识别这两个配置文件)
- 路径:直接接将文件放在src目录下即可。
- 创建核心对象数据库连接池对象comboPooledDataSource
- 获取连接: getConnection
/*** @Auther: Parsifal* @Date: 2021/03/27/20:38* @Description: C3P0的演示*/
public class C3P0Test {public static void main(String[] args) throws SQLException {// 1、创建数据库连接池对象 ->使用默认配置
// DataSource ds = new ComboPooledDataSource();//使用指定配置DataSource ds = new ComboPooledDataSource("otherc3p0");
// 2、获取连接对象Connection conn = ds.getConnection();System.out.println(conn);conn.close();}
<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
<!-- 使用默认的配置读取连接池对象--><default-config>
<!-- 连接参数--><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=false</property><property name="user">root</property><property name="password">root</property>
<!-- 连接池参数-->
<!-- 初始化申请的连接数量--><!-- 初始化五个Connection对象--><property name="initialPoolSize">5</property>
<!-- 最大连接数量--><property name="maxPoolSize">10</property>
<!-- 如果申请不到,最多会等待三秒--><property name="checkoutTimeout">3000</property></default-config><named-config name="otherc3p0"> </named-config>
</c3p0-config>
4.Druid:数据库连接池实现技术(阿里巴巴)
- 导人jar包druid-1.o.9.jar定义配置i文件:
- 可以叫任何名称,可以放在任何目录下
- 是properties形式的
- 获取数据库连接池对象∶通过工厂来来获取DruidDataSourceFactory
- 获取连接∶getConnection
实现代码:
package DateSource;import DateSource.Druid.DruidTest;
import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;/*** @Auther: Parsifal* @Date: 2021/03/27/22:22* @Description: 使用Druid数据库连接池的JDBCUtil*/
public class JDBCUtil {static DataSource ds;static {//加载配置文件try {//1、导入jar包//2、定义配置文件//3、加载配置文件 不可以默认配置文件 ,必须指定文件Properties properties =new Properties();InputStream is = DruidTest.class.getClassLoader().getResourceAsStream("druid.properties");properties.load(is);//4、获取数据库连接池对象ds = DruidDataSourceFactory.createDataSource(properties);} catch (Exception e) {e.printStackTrace();}}/*** 获取连接* @return* @throws SQLException*/public static Connection getConnection() throws SQLException {return ds.getConnection();}/*** 关闭资源* @param resultSet* @param statement* @param connection*/public static void close(ResultSet resultSet, Statement statement, Connection connection){if (resultSet!=null){try {resultSet.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (statement!=null){try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (connection!=null){try {connection.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}/*** 重载* @param statement* @param connection*/public static void close(Statement statement ,Connection connection){close(null,statement,connection);}/*** 获取数据库连接池* @return*/public static DataSource getDataSource(){return ds;}
}
六.Spring JDBC
spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发步骤︰
步骤:
导入四个jar包 spring-tx-5.0.5.RELEASE.jar spring-jdbc-5.0.5.RELEASE.jar spring-core-5.0.5.RELEASE.jar spring-beans-5.0.5.RELEASE.jar commons-logging-1.2.jar
创建JdbcTemplate对象。依赖于数据源Datasource
调用JdbcTemplate的方法来完成CRUD的操作
update():执行DML语句。增、删、改语句
queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value将这条记录封装为一个map集合
- 注意:这个方法查询的结果集长度只能是1
queryForList():查询结果将结果集封装为list集合
- 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
query():查询结果,将结果封装为javaBean对象
- 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
query的参数:RowMapper
- 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装new
- BeanPropertyRowMapper<类型>(类型.class)
queryForobject :查询结果,将结果封装为对象
/*** @Auther: Parsifal* @Date: 2021/03/28/14:12* @Description:*/
public class JDBCTemplateTest {//1、导入jar//2、创建JDBCTemplate对象static JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtil.getDataSource());//查询所有的记录用List集合@Testpublic void test(){String sql = "select * from student";//自定义接口List<Student> students = jdbcTemplate.query(sql, new RowMapper<Student>() {@Overridepublic Student mapRow(ResultSet resultSet, int i) throws SQLException {int id = resultSet.getInt("id");String name = resultSet.getString("name");String email = resultSet.getString("email");float grade = resultSet.getFloat("grade");Student student = new Student(id,name,email,grade);return student;}});students.forEach(System.out::println);}//查询所有的记录用List集合@Testpublic void test1(){String sql = "select * from student";//使用封装好的接口List<Student> students = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Student>(Student.class));students.forEach(System.out::println);}
}
记录:学习中遇到的一些bug
mysql版本号为8.0.13
1.JDBC连接时错误:closing inbound before receiving peer’s close_notify
解决方法与原因:配置连接数据库的url错误,在后面加上&useSSL=false即可
2.JDBC连接时错误:
The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to util
解决方法与原因:当mysql和connector版本八以上时,系统时区错误,需要在配置连接数据库的url加上:?serverTimezone=GMT%2B8
3.C3P0数据库连接池报错:An attempt by a client to checkout a Connection has timed out.
解决方法与原因:配置文件的url错误(并且注意:&需要转义为&)
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=false</property>
顺便说一下:可以试试看其他的解决方法:
重启mysql服务
<property name="checkoutTimeout">3000</property> 改大等待时间
<property name="maxPoolSize">10</property> 改小最大连接数量
4.警告: Cannot resolve com.mysq.jdbc.Connection.ping method. Will use ‘SELECT 1’ instead.
解决方法与原因:druid版本与mysql版本不兼容,更换druid版本1.1.21即可
2021-3-28 JDBC入门包含数据库连接池相关推荐
- Java JDBC篇4——数据库连接池
Java JDBC篇4--数据库连接池 1.DBCP 1.1.依赖jar包 官网:https://mvnrepository.com/artifact/org.apache.commons/commo ...
- JDBC开发之数据库连接池
JDBC开发之数据库连接池 使用数据库连接池优化程序性能 应用程序直接获取链接的缺点:用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万 ...
- JDBC中C3PO数据库连接池详解
-----------------------------------------------------JDBC中C3PO数据库连接池详解------------------------------ ...
- 【JavaWeb】JDBC优化 之 数据库连接池、Spring JDBC
1 数据库连接池 为什么要使用数据库连接池? 数据库连接是一件费时的操作,连接池可以使多个操作共享一个连接 使用连接池可以提高对数据库连接资源的管理 节约资源且高效 概念:数据库连接池其实就是一个容器 ...
- java银行管理系统(MySql+JDBC+数据库(Druid数据库连接池)+GUI)重要代码有解析注释
java银行管理系统 小白又来水博客了 文章目录 java银行管理系统 一.项目需求与分析: 二.知识及有关技术的概述: 三.银行管理系统需求的具体实现: 四.部分功能预览: 五.Last: 一.项目 ...
- JDBC学习笔记03【JDBC事务管理、数据库连接池、JDBCTemplate】
黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...
- JDBC——数据库连接池
目录 前言 一.为什么要使用数据库连接池 二.数据库连接池 2.1 优点 三.多种开源数据库连接池 3.1 C3P0数据库连接池 3.2 DBCP连接池 3.3 Druid(德鲁伊)数据库连接池 总结 ...
- 数据库连接池的选择及其开发配置
转载自 数据库连接池的选择及其开发配置 一.数据库连接池概述 数据库连接的建立是一种耗时.性能低.代价高的操作,频繁的数据库连接的建立和关闭极大的影响了系统的性能.数据库连接池是系统初始化过程中创建 ...
- 数据库驱动和JDBC、DBCP-C3P0连接池
目录 数据库驱动 第一个JDBC程序 statement对象详解 SQL注入问题 PreparedStatement对象 JDBC操作事务 DBCP-C3P0连接池 DBCP C3P0 C3P0与DB ...
最新文章
- OC学习7——类别、扩展和协议
- mysql 查看锁_MySQL反应慢的排查思路
- 79. 单词搜索(dfs)
- 关于JAVA异常处理的20个最佳实践
- ReactiveLodeBalancerClientFilter响应式负载均衡代理
- javafx窗体程序_JavaFX真实世界应用程序:欧洲电视网广播联盟
- Exam化的软件项目管理
- echo 多行_Java中Scanner的用法:单行多行输入
- leetcode题解102-二叉树的层序遍历
- JavaScript学习总结(4)——JavaScript数组
- ipad是买WiFi版的好,还是买4G版的好?
- 普中28335开发攻略_带你了解TI的DSP入门芯片TMS320F28335
- linux 搜索文件后缀名,Linux -find、文件后缀名
- 泛泰A870K去掉相机快门声音的方法
- java des ecb_DES ECB加解密的Java实现
- 论文写作-如何提高英语论文写作水平
- 处理火绒弹窗拦截无法开机启动
- 读书笔记——高效能人士的七个习惯3
- 【Alpha】阶段第九次Scrum Meeting
- 架构师修炼系列【FMEA故障分析与影响分析】
热门文章
- 大数据挖掘分析工具集
- 好家伙,你的 GitHub 年度报告曝光!
- oppo watch安装王者荣耀,adb完整代码及步骤
- linux python prophet,在python中使用Prophet预测每个类别的值
- Python3原生爬虫获取熊猫直播某一分类下的主播人气并保存到Excel
- apicloud优化点击事件与tapmode
- linux系统调用的来龙去脉(上)
- 北京工商大学计算机软件技术基础课件,《智能科学与技术专业发展问题》 课件.ppt...
- 笔记本电脑进水后的正确处理方法
- android_binder