JDBC以及数据库连接池
JDBC
1 JDBC概述
JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API)
简单理解为:JDBC,是SUN提供的一套 API,使用这套API可以实现对具体数据库的操作(获取连接、关闭连接、DML、DDL、DCL)
数据库的驱动:数据库厂商针对于JDBC这套接口,提供的具体实现类的集合。
面向接口编程的思想:
JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。
不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。
通过Driver接口获取数据库连接:
准备工作:
Driver是一个接口,数据库厂商必须提供实现的接口,从而获取到数据库连接,可以通过Driver的实现类的对象获取连接
- 加入mysql驱动
- 解压mysql-connector-java-5.1.18.zip
- 在当前目录下新建lib目录
- 把mysql-connector-java-5.1.18-bin.jar复制到lib目录
- 右键->build-path->add build path加载到类路径下
1、创建一个Driver实现类的对象
Driver driver=new com.mysql.jdbc.Driver();
2、准备连接数据库的基本信息,url,user,password
String url="jdbc:mysql://localhost:3306/mybatis";
String user = "root";
String password = "234523";
3、调用DriverManager.getConnection获取连接
Connection connection = DriverManager.getConnection(url, user, password);
4、关闭数据库连接
connection.close();
完整代码:
public class ConnectionTest {public static void main(String[] args) throws SQLException {// 1、获取MySQL驱动Driver driver = new com.mysql.jdbc.Driver();// 2、加载数据库基本信息String url="jdbc:mysql://localhost:3306/mybatis";String user = "root";String password = "232323";// 3、建立连接Connection connection = DriverManager.getConnection(url, user, password);System.out.println(connection);// 4、关闭连接connection.close();}
}
测试结果:com.mysql.jdbc.JDBC4Connection@ee7d9f1
但是上面这种方式不太理想,对于数据库的信息起不到保护作用!
连接数据库最佳方法:
首先,我们新建一个配置文件名字叫做jdbc.Properties(最好放在src下面,方便引用),里面添加我们连接数据库需要的信息
注意:配置文件中不要加空格,不要加双引号
user=root
password=123123
url=jdbc:mysql://localhost:3306/mybatis
driverClass=com.mysql.jdbc.Driver
完整代码:
public class BestConnection {public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {// 1、获得类加载器ClassLoader classLoader = BestConnection.class.getClassLoader();// 2、读取配置文件信息InputStream is = classLoader.getResourceAsStream("jdbc.properties");Properties properties = new Properties();// 3、加载对应的输入流properties.load(is);// 4、拿到配置文件的具体值,getProperty里的值必须和配置文件的一致String user = properties.getProperty("user");String url = properties.getProperty("url");String password = properties.getProperty("password");String driverClass = properties.getProperty("driverClass");// 5、加载数据库驱动程序Class.forName(driverClass);// 6、建立连接Connection connection = DriverManager.getConnection(url, user, password);System.out.println(connection);// 7、关闭连接connection.close();}
}
2 JDBCUtils
说明:
为了方便操作,将连接(关闭)数据库封装成一个工具类
public class JDBCUtils {// 获取数据库连接public static Connection getConnection() throws Exception {// 1.读取配置文件中的4个基本信息InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");// 2.加载驱动Class.forName(driverClass);// 3.获取连接Connection conn = DriverManager.getConnection(url, user, password);return conn;}// 增删改的关闭方法public static void closeResource(Connection conn, Statement ps) {try {if (ps != null) {ps.close();}if (conn != null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}// 查询的关闭方法public static void closeResource(Connection conn, Statement ps, ResultSet rs) {try {if (rs != null) {rs.close();}if (ps != null) {ps.close();}if (conn != null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}
}
3 使用PreparedStatement操作Blob(图片、音频等大型文件)类型的变量
插入blob类型数据到数据库:
@Test// 插入图片到数据库public void insertTest() throws Exception {Connection conn = JDBCUtils.getConnection();String sql = "insert into photos(id,photo) values(?,?)";// 预编译SQL语句PreparedStatement ps = conn.prepareStatement(sql);// 填充占位符ps.setObject(1, 1);FileInputStream fis = new FileInputStream(new File("src\\com\\zwh\\blob\\3.jpg"));ps.setObject(2, fis);// 执行ps.execute();// 关闭连接JDBCUtils.closeResource(conn, ps);}
查询数据库的Blob数据:
@Test
// 从数据库将图片取出
public void getBlob() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;InputStream is = null;FileOutputStream fos = null;try {conn = JDBCUtils.getConnection();String sql = "select id,photo from photos";ps = conn.prepareStatement(sql);rs = ps.executeQuery();if (rs.next()) {int id = rs.getInt("id");// 将Blob类型的字段下载下来,以文件的方式保存在本地Blob photo = rs.getBlob("photo");is = photo.getBinaryStream();fos = new FileOutputStream("src\\com\\zwh\\blob\\six.jpg");byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}}} catch (Exception e) {e.printStackTrace();} finally {try {if (fos != null) {fos.close();}if (is != null) {is.close();}} catch (IOException e) {e.printStackTrace();}JDBCUtils.closeResource(conn, ps, rs);}
}
注意:
数据库,默认max_allowed_packet=4M,更根据你文件大小进行增加。
blob类型不够的话,使用longblob可以解决,xxx too long 的问题
开发中使用PreparedStatement替换Statement,Statement存在SQL注入问题
4 数据库事务
事务:
一组逻辑操作单元,使数据从一种状态变换到另一种状态。
一组逻辑操作单元:
一个或多个DML操作。
事务处理的原则:
保证所事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。
哪些操作会导致数据的自动提交?
DDL操作一旦执行,都会自动提交。set autocommit = false 对DDL操作失效
DML默认情况下,一旦执行,就会自动提交。我们可以通过set autocommit = false的方式取消DML操作的自动提交。
默认在关闭连接时,会自动的提交数据
代码实现:
@Test
public void testUpdateWithTx() {Connection conn = null;try {conn = JDBCUtils.getConnection();System.out.println(conn.getAutoCommit());//true//1.取消数据的自动提交conn.setAutoCommit(false);String sql1 = "update user_table set balance = balance - 100 where user = ?";update(conn,sql1, "AA");//模拟网络异常System.out.println(10 / 0);String sql2 = "update user_table set balance = balance + 100 where user = ?";update(conn,sql2, "BB");System.out.println("转账成功");//2.提交数据conn.commit();} catch (Exception e) {e.printStackTrace();//3.回滚数据try {conn.rollback();} catch (SQLException e1) {e1.printStackTrace();}}finally{//修改其为自动提交数据//主要针对于使用数据库连接池的使用try {conn.setAutoCommit(true);} catch (SQLException e) {e.printStackTrace();}JDBCUtils.closeResource(conn, null);}
}
5 通用的增删改查
通用的增删改:
//1、通用的增删改
public static void commonCRD(String sql, Object[] args) throws Exception {Connection conn = null;PreparedStatement ps = null;try {//1、建立数据库连接conn = JDBCUtils.getConnection();//2、预编译sql语句ps = conn.prepareStatement(sql);//3、填充占位符并执行for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}ps.execute();System.out.println("操作成功~");} catch (SQLException e) {e.printStackTrace();} finally {//4、关闭连接JDBCUtils.closeResource(conn, ps);}
}
通用的返回表中所有数据:
//2、针对于不同的表的通用的查询操作,返回表中的所有记录
public static <T> List<T> commSelAll(Class<T> clazz, String sql, Object... args) throws Exception {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;List<T> allStu = null;try {//1、建立连接conn = JDBCUtils.getConnection();//2、预编译ps = conn.prepareStatement(sql);//3、填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}//4、执行并且处理结果集rs = ps.executeQuery();//5、获取结果集中的元数据:ResultSetMetaDataResultSetMetaData rsmd = rs.getMetaData();//6、通过ResultSetMetaData获取结果集中的列数int columnCount = rsmd.getColumnCount();//7、创建集合对象allStu = new ArrayList<>();while (rs.next()) {T t = clazz.newInstance();//8、处理结果集一行数据中的每一个列:给t对象指定的属性赋值for (int i = 0; i < columnCount; i++) {// 9、获取列值Object columValue = rs.getObject(i + 1);// 10、获取每个列的列名String columnName = rsmd.getColumnClassName(i + 1);String columnLabel = rsmd.getColumnLabel(i + 1);//11、给t对象指定的columnName属性,赋值为columValue:通过反射Field field = clazz.getDeclaredField(columnLabel);field.setAccessible(true);field.set(t, columValue);}allStu.add(t);}} catch (SQLException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} finally {//4、关闭JDBCUtils.closeResource(conn, ps, rs);}return allStu;
}
通用的单条查询:
//3、针对于不同的表的通用的查询操作,返回表中的一条记录
public <T> T getInstance(Class<T> clazz, String sql, Object... args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = JDBCUtils.getConnection();ps = conn.prepareStatement(sql);for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}rs = ps.executeQuery();// 获取结果集的元数据 :ResultSetMetaDataResultSetMetaData rsmd = rs.getMetaData();// 通过ResultSetMetaData获取结果集中的列数int columnCount = rsmd.getColumnCount();if (rs.next()) {T t = clazz.newInstance();// 处理结果集一行数据中的每一个列for (int i = 0; i < columnCount; i++) {// 获取列值Object columValue = rs.getObject(i + 1);// 获取每个列的列名// String columnName = rsmd.getColumnName(i + 1);String columnLabel = rsmd.getColumnLabel(i + 1);// 给t对象指定的columnName属性,赋值为columValue:通过反射Field field = clazz.getDeclaredField(columnLabel);field.setAccessible(true);field.set(t, columValue);}return t;}} catch (Exception e) {e.printStackTrace();} finally {JDBCUtils.closeResource(conn, ps, rs);}return null;
}
6 数据库连接池
数据库:
在每一次请求数据库都要经历上述过程,创建连接和释放资源也都是些重复性的动作,当请求量比较大时,资源是个很大的浪费。
假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。
连接池:
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。
几种常用的数据库连接池:
1、DBCP(Database Connection Pool)
是一个依赖Jakarta commons-pool对象池机制的数据库连接池,Tomcat的数据源使用的就是DBCP。
2、C3P0
是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象,sql执行效率较低。
3、Proxool
是一个Java SQL Driver驱动程序,提供了对你选择的其它类型的驱动程序的连接池封装。可以非常简单的移植到现存的代码中。完全可配置。快速,成熟,健壮。可以透明地为你现存的JDBC驱动程序增加连接池功能,在激烈并发时会抛异常,完全不靠谱。
4、BoneCP
是一个开源的快速的 JDBC 连接池。BoneCP很小,只有四十几K
5、Druid
是阿里提供的数据库连接池,据说是集DBCP、C3P0、Proxool优点于一身的连接池,性能最好的数据库连接池
6.1 DBCP数据库连接池
准备工作 :
在项目src目录下创建dbcpconfig.properties配置文件
需要引用的包 commons-dbcp-1.4.jar commons-pool-1.6.jar
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=root#<!-- 初始化连接 -->
initialSize=10#最大连接数量
maxActive=50#<!-- 最大空闲连接 -->
maxIdle=20#<!-- 最小空闲连接 -->
minIdle=5#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;
characterEncoding=utf8#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLEdefaultTransactionIsolation=READ_UNCOMMITTED
通过DBCP封装连接数据库的方法:
public class DBCPUtils {//创建一个DBCP数据库连接池private static DataSource dataSource;static {try {Properties properties = new Properties();FileInputStream fis = new FileInputStream(new File("src\\com\\zwh\\dbcp\\dbcp.properties"));properties.load(fis);// 创建数据源 工厂模式dataSource = BasicDataSourceFactory.createDataSource(properties);} catch (Exception e) {e.printStackTrace();}}// 获取连接public static Connection getCollection() throws SQLException {return dataSource.getConnection(); //从数据源中获取数据}// 释放连接public static void release(Connection connection, PreparedStatement ps, ResultSet rs) {try {if (rs != null) {rs.close();}if (ps != null) {ps.close();}if (connection != null) {connection.close();}} catch (SQLException throwables) {throwables.printStackTrace();}}
}
6.2 C3P0数据库连接池
准备工作 :
在项目src目录下创建c3p0-config.xml配置文件
导入c3p0的包
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config><!-- c3p0的缺省设置如果在代码中 ComboPooledDataSource ds = new ComboPooledDataSource() 这样表示的使用c3p0的默认设置--><default-config><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc</property><property name="user">root</property><property name="password">java</property><property name="acquireIncrement">5</property><property name="initialPoolSize">10</property><property name="maxPoolSize">20</property><property name="minPoolSize">5</property></default-config><!-- c3p0的命名设置如果在代码中 ComboPooledDataSource ds = new ComboPooledDataSource("mysql") 这样表示的使用c3p0的命名设置--><named-config name="mysql"><!-- 提供获取连接的4个基本信息 --><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/mybatis</property><property name="user">root</property><property name="password">2132456</property><!-- 进行数据库连接池管理的基本信息 --><!-- 当数据库连接池中的连接数不够时,c3p0一次性向数据库服务器申请的连接数 --><property name="acquireIncrement">5</property><!-- c3p0数据库连接池中初始化时的连接数 --><property name="initialPoolSize">10</property><!-- c3p0数据库连接池维护的最少连接数 --><property name="minPoolSize">10</property><!-- c3p0数据库连接池维护的最多的连接数 --><property name="maxPoolSize">100</property><!-- c3p0数据库连接池最多维护的Statement的个数 --><property name="maxStatements">50</property><!-- 每个连接中可以最多使用的Statement的个数 --><property name="maxStatementsPerConnection">2</property></named-config>
</c3p0-config>
通过C3P0封装连接数据库的方法:
public class C3P0Utils {private static ComboPooledDataSource cpds = new ComboPooledDataSource("mysql");public static Connection getConnection() throws SQLException {Connection conn = cpds.getConnection();return conn;}public static void main(String[] args) throws SQLException {Connection connection = getConnection();System.out.println(connection);}
}
6.3 Druid数据库连接池
准备工作:
导入Druid的jar包
创建druid.properties:
url=jdbc:mysql://localhost:3306/mybatis
username=root
password=123452
driverClassName=com.mysql.jdbc.Driver
initialSize=10
maxActive=10
测试代码:
public class DruidUtils {private static DataSource source;static {try {Properties pros = new Properties();FileInputStream fis = new FileInputStream(new File("src\\com\\zwh\\druid\\druid.properties"));pros.load(fis);source = DruidDataSourceFactory.createDataSource(pros);} catch (Exception e) {e.printStackTrace();}}public static Connection getConnection() throws SQLException {Connection conn = source.getConnection();return conn;}
}
JDBC以及数据库连接池相关推荐
- Java -- JDBC 学习--数据库连接池
JDBC数据库连接池的必要性 在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤: 在主程序(如servlet.beans)中建立数据库连接. 进行sql操作 断开数据库连接. 这种模式开 ...
- JavaWeb:JDBC之数据库连接池
JDBC系列阅读 JavaWeb:用JDBC操作数据库 JavaWeb:JDBC之事务 JavaWeb:JDBC之数据库连接池 使用JDBC实现水果超市管理系统 1. 池参数(所有池参数都有默认值) ...
- Java JDBC和数据库连接池 韩顺平老师自学笔记
JDBC和数据库连接池 JDBC 概述 基本介绍 原理示意图 代码示例 JdbcInterface 模拟Java公司提供给其它数据库厂商的接口,供给调用 TestJdbc 模拟一个类来实现数据库的调用 ...
- 【JDBC】数据库连接池技术
文章目录 一.数据库连接池技术 二.多种开源的数据库连接池 一.数据库连接池技术 1.数据库连接池的基本思想︰ 就是为数据库连接建立一个"缓冲池".预先在缓冲池中放入一定数量的连接 ...
- JDBC以及数据库连接池的使用
文章目录 JDBC 步骤 数据库连接池 1.概念 2.接口规范方法 3.第三方数据库连接池技术 C3p0 Druid:由阿里提供 Druid工具类 JDBC 概念 JDBC是sun公司提供的一套用 ...
- 从JDBC到数据库连接池
文章目录 基本的JDBC操作方式 基本的JDBC操作在高并发的情况下带来的问题 第三方应该具备条件 连接池的初步设计 C3P0从数据源获取到连接的过程 如何从C3P0获取连接池状态信息 基本的JDBC ...
- 基于JDBC的数据库连接池技术研究与应用
引言 近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机 应用程序已从传统的桌面应用转到Web应用.基于B/S(Browser/Server)架构的3层开 ...
- 基于JDBC的数据库连接池高效管理策略
2019独角兽企业重金招聘Python工程师标准>>> 介绍 在使用Java语言进行和数据库有关的的应用开发中,一般都使用JDBC来进行和数据库的交互,其中有一个关键的概念就是Con ...
- JDBC【数据库连接池、DbUtils框架、分页】
1.数据库连接池 什么是数据库连接池 简单来说:数据库连接池就是提供连接的... 为什么我们要使用数据库连接池 数据库的连接的建立和关闭是非常消耗资源的 频繁地打开.关闭连接造成系统性能低下 编写连接 ...
- kylin调优,项目中错误总结,知识点总结,kylin jdbc driver + 数据库连接池druid + Myba
首先给大家分享一个巨牛巨牛的人工智能教程,是我无意中发现的.教程不仅零基础,通俗易懂,而且非常风趣幽默,还时不时有内涵段子,像看小说一样,哈哈-我正在学习中,觉得太牛了,所以分享给大家!点这里可以跳转 ...
最新文章
- 【自然语言处理】N-最短路径法进行中文分词
- mciSendString 的两个小坑
- html与css项目,项目六HTML与CSS基础.doc
- (转)Response.Redirect 打开新窗口的两种方法
- 求1-100数字的和
- keil5怎么配置程序风格_开发微信小程序怎么配置域名?
- BZOJ 2821 分块+二分
- Glance - 直接操作image
- java deadlock oracle_【DEADLOCK】Oracle“死锁”模拟
- codeIgniter3 学习笔记二(基于 MVC 开发模式实现小案例)
- JAVA 基础练习题
- Markdown下载地址
- Shuffle failed with too many fetch failures and insufficient progress!
- 理解JavaScriptES6中的TDZ(暂时性死区)
- 一文总结经典卷积神经网络CNN模型
- 松下LUMIX S1相机断电MDT文件修复MP4视频(LPCM)
- 龙ol服务器维护补偿boss,总裁酷炫狂霸拽 《龙OL》练武场深处的BOSS
- Ipmitool工具安装以及常见使用方法
- Android 之路56---AIDL建立远程通信
- 有哪些权威的职业性格测试?职业性格测试靠谱吗?
热门文章
- 移动端前台页面需要注意的几点
- redis分布式锁与zk分布式锁的对比
- linux-CentOS6.4安装Memcached+memcached扩展+安装memcache扩展+Memcache+mecached同步SESSION的几种方法
- C语言实现二分法查找某个数字(超详细)
- 【HTML 教程】网页元素的属性
- 微软 2020 财年营收突破 1 万亿人民币、净利润 3099 亿元
- ARM开发板移植lsusb命令
- (附源码)springboot+mysql+采用协同过滤算法的视频推荐系统的设计与实现 毕业设计261620
- Mxnet (20): 循环神经网络(RNN)下
- RAM与ROM的原理与区别