JDBC及衍生知识(下)
JDBC及衍生知识(下)
前言
上一篇文章我们学习了JDBC,今天,我们乘胜追击来学习数据库连接池。
数据库连接池
概述
上篇我们使用JDBC的代码中,我们每一次访问都要去获取连接,再释放资源,每一次访问都要这样,这在底层是极大的浪费资源,因为我们在不断的建立连接、释放连接,而我们数据库连接池的存在的意义就是优化这部分的性能。
概念:其实就是一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
数据库连接池将建立的连接保存在一个“pool”中,当我们需要建立连接,不会再去动用系统底层去申请连接,而是会拿pool中的连接对象,当我们访问结束,不会释放掉该连接对象的资源,会将该连接对象再归还给pool。
作用:数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
优点:
- 节约资源
- 用户访问高效
这种池技术并不局限于数据库连接,在Unity3D程序中基础框架我也见识过了,Unity缓存池技术也应用到了“池”技术,针对Unity中的物体,当销毁时并不是真正的销毁,而是setActive(false)让其失活,在需要时才会再setActive(true),对性能非常友好。
实现介绍
标准接口:DataSource ( javax.sql包下)
连接池一般都会实现如下方法:
- 获取连接方法:
Connection getConnection()
Connection getConnection(String username, String password)
- 归还连接:如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接释放资源了,而是归还连接。
该接口下的方法一般不是由我们来实现,是由数据库厂商来实现。
下面我们来介绍两种连接池技术:
C3P0:数据库连接池技术
步骤:
- 导入jar包
链接:https://pan.baidu.com/s/17Y0OKGm4TTnpCslfjYHHOg
提取码:knnq
需要导入两个jar包,c3p0-0.9.5.2.jar依赖mchange-commons-java-0.2.12.jar
- 定义配置文件
- 名称:c3p0.properties 或者 c3p0-config.xml
- 路径:直接将文件放在src目录下即可
- 创建核心对象 数据库连接池对象 ComboPooledDataSource
- 获取连接:getConnection
好,接下来我们来一点一点做:
我们新开一个JavaSE项目,创建一个目录lib,将成c3p0的两个jar包导入目录lib中,并添加到项目。
导入MySQL的驱动jar包。
接下来我们需要引入一个c3p0的配置文件,我们可以将上面网盘分享的目录中的c3p0-config.xml文件复制到src根目录下。
OK,基本准备工作就做好了。
配置文件c3p0-config.xml中内容(注意,我的MySQL版本大于8.0,所以在URL中需要一些特别声明一些参数):
<?xml version="1.0" encoding="utf-8"?>
<c3p0-config><!--使用默认的配置读取连接池对象--><default-config><!--连接参数--><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/db4?useSSL=false&serverTimezone=UTC</property><property name="user">root</property><property name="password">964939451</property><!--连接池参数--><!--初始化连接数--><property name="initialPoolSize">5</property><!--最大连接数,超过会报错--><property name="maxPoolSize">10</property><!--申请连接等待时间,超时会报错--><property name="checkoutTimeout">5000</property></default-config><named-config name="otherc3p0"> </named-config>
</c3p0-config>
然后我们在pers.luoluo.datasource.c3p0包下创建一个C3P0Demo1.java文件来使用连接池:
public class C3P0Demo2 {public static void main(String[] args) {Connection conn=null;//1.创建数据库连接池对象,获取DataSource//ComboPooledDataSource无参则使用默认配置,//有参则使用对应named-config的name的配置DataSource ds=new ComboPooledDataSource();//2.获取连接对象try {conn=ds.getConnection();//打印一下System.out.println(conn);} catch (SQLException e) {e.printStackTrace();}finally {try {//归还连接conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}
就如上就可以取到池中连接,非常简单吧。
Druid:数据库连接池实现技术
这个连接池,又名“德鲁伊”,是由阿里巴巴公司开发的数据库连接池。
步骤
- 导入jar包
我这边也给大家提供一个分享链接(不过我这个版本有点老了)
链接:https://pan.baidu.com/s/12UV_ZtQv4pLo6Xmy7kYFTw
提取码:9g12
导入一个druid-1.0.9.jar即可。
- 定义配置文件
- 配置文件是properties类型的文件
- 配置文件可以叫任意名称,可以放在任意的目录下,但是这也意味着你需要手动加载。
- 加载配置文件:
- 获取数据库连接池对象:通过工厂类来获取 DruidDataSourceFactory。
- 获取连接:getConnection
下面我们来实际演示:
在src目录下创建一个配置文件,druid.properties:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db4?useSSL=false&serverTimezone=UTC
username=root
password=964939451
#初始化连接数
initialSize=5
#最大连接数
maxActive=10
#等待时间
maxWait=3000
在包pers.luoluo.druid目录下,我们创建一个DruidDemo1.java文件:
public class DruidDemo1 {public static void main(String[] args) {Connection conn=null;//1.导入jar包//2.定义配置文件try {//3.手动加载配置文件Properties pro=new Properties();InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");pro.load(is);//4.获取连接池对象DataSource ds = DruidDataSourceFactory.createDataSource(pro);//5.获取连接conn=ds.getConnection();System.out.println(conn);} catch (Exception e) {e.printStackTrace();}}
}
控制台打印:
七月 29, 2020 1:23:09 下午 com.alibaba.druid.pool.DruidDataSource error
严重: testWhileIdle is true, validationQuery not set
七月 29, 2020 1:23:09 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
com.mysql.cj.jdbc.ConnectionImpl@29ca901e
不用理会红色的日志信息,看来我们成功了。
关于类加载器的知识可以好好看看这篇文章。
上面是Druid连接池的基本使用,但是其实在实际开发中,我们这样使用也不合适,例如每一次使用都要创建一个连接池对象,这非常的不合理,所以我们一般使用的话也是会创建一个Druid工具类的:
定义工具类:
- 定义一个类 JDBCUtils
- 提供静态代码块加载配置文件,初始化连接池对象
- 提供方法;
- 获取连接方法:通过数据库连接池获取连接
- 释放资源
- 获取连接池的方法
在包pers.luoluo.utils包下创建一个类——JDBCUtile.java。
工具类内容如下:
public class JDBCUtils {//1.定义成员变量 DataSourceprivate static DataSource ds;static {try {//1.加载配置文件Properties pro=new Properties();pro.load(JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties"));//2.获取DataSourceds= DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {e.printStackTrace();}}/*** @Description 获取连接**/public static Connection getConnection() throws SQLException {return ds.getConnection();}/*** @Description 获取连接池的方法**/public static DataSource getDateSource(){return ds;}/*** @Description 释放资源**/public static void close(Statement stmt,Connection conn){if(stmt!=null){try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}if(conn!=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}public static void close(ResultSet rs, Statement stmt, Connection conn){if(rs!=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}close(stmt,conn);}
}
这个工具类和我们之前那个工具类道理一样,只是底层不是手动建立连接或者清理资源了,而是去从连接池中申请连接或归还连接。
连接池工具类定义结束,使用起来也非常方便:
public class DruidDemo2 {public static void main(String[] args) {/*给db3中的account表添加一条记录*/Connection conn=null;PreparedStatement pstmt=null;try {//1.获取连接conn = JDBCUtils.getConnection();//2.定义sqlString sql="INSERT INTO account VALUES(null,?,?)";//3.获取pstmt对象pstmt = conn.prepareStatement(sql);//4.给预编译的SQL语句中的占位符赋值pstmt.setString(1,"Alis");pstmt.setDouble(2,2000);//5.执行sqlint count=pstmt.executeUpdate();System.out.println(count);} catch (SQLException e) {e.printStackTrace();}finally {//6.释放资源JDBCUtils.close(pstmt,conn);}}
}
测试结果正常。
Spring JDBC
概念
Spring JDBC是由Spring框架提供的对JDBC的简单封装。
它提供了一个JDBC Template对象来简化JDBC的开发。
具体使用
入门使用
步骤:
- 导入jar包
- commons-logging-
- spring-beans
- spring-core
- spring-jdbc
- spring-tx
这里提供我分享的jar包
链接:https://pan.baidu.com/s/1uLLESl3H863d6m4gG_EVhA
提取码:ya6n
lib目录下的那五个jar包全需要导入
- 创建JDBCTemplate对象,依赖于数据源DataSource (即需要数据库连接池对象作为参数)
- 调用JDBCTemplate的方法来完成CRUD的操作
- update():执行DML语句
- queryForMap():执行DQL,查询结果,将结果封装为map集合
- queryForList():执行DQL,查询结果,将结果封装为List集合
- query():查询结果,将结果封装为JavaBean对象
- queryForObject:查询结果,将结果封装为对象
我们先将五个需要的jar包导入项目中,然后我们在包pers.luoluo.jdbctemplate下面来写测试代码:
我们的SpringJDBC是对数据库连接池的再优化,所以数据库的jdbc驱动包、连接池(Druid)包这些包当然也得有了,这些是基石。
public class JdbcTemplateDemo1 {public static void main(String[] args) {//1.导入jar包//2.创建JDBCTemplate对象JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDateSource());//3.调用方法String sql="UPDATE account SET balance=5000 WHERE name=?";int count=template.update(sql,"Tom");System.out.println(count);}
}
直接执行就OK,JdbcTemplate的对象template对负责从连接池中建立连接,并且在执行结束后进行连接的归还操作,你要做的就是写好SQL语句执行即可,这是我第一次接触Java的Spring框架,感到非常好用。
DML、DQL语句的执行
有表emp如下:
id ename job_id mgr joindate salary bonus dept_id
------ --------- ------ ------ ---------- -------- -------- ---------1001 孙悟空 4 1004 2000-12-17 8000.00 (NULL) 201002 卢俊义 3 1006 2001-02-20 16000.00 3000.00 301003 林冲 3 1006 2001-02-22 12500.00 5000.00 301004 唐僧 2 1009 2001-04-02 29750.00 (NULL) 201005 李逵 4 1006 2001-09-28 12500.00 14000.00 301006 宋江 2 1009 2001-05-01 28500.00 (NULL) 301007 刘备 2 1009 2001-09-01 24500.00 (NULL) 101008 猪八戒 4 1004 2007-04-19 30000.00 (NULL) 201009 罗贯中 1 (NULL) 2001-11-17 50000.00 (NULL) 101010 吴用 3 1006 2001-09-08 15000.00 0.00 301011 沙僧 4 1004 2007-05-23 11000.00 (NULL) 201012 李逵 4 1006 2001-12-03 9500.00 (NULL) 301013 小白龙 4 1004 2001-12-03 30000.00 (NULL) 201014 关羽 4 1007 2002-01-23 13000.00 (NULL) 10
- 修改1号数据的salary为10000
- 添加一条记录
- 删除刚才添加的记录
- 查询id为1的记录,将其封装为Map集合
- 查询所有的记录,将其封装为List
- 查询所有的记录,将其封装为Emp对象的List集合
- 查询总的记录数
好,我们开始。
创建一个pers.luoluo.domain包,domain包中创建一个JavaBean对象,Emp,意为员工
public class Emp {private Integer id;private String ename;private Integer job_id;private Integer mgr;private Date joindate;private Double salary;private Double bonus;private Integer dept_id;@Overridepublic String toString() {return "Emp{" +"id=" + id +", ename='" + ename + '\'' +", job_id=" + job_id +", mgr=" + mgr +", joindate=" + joindate +", salary=" + salary +", bonus=" + bonus +", dept_id=" + dept_id +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getEname() {return ename;}public void setEname(String ename) {this.ename = ename;}public Integer getJob_id() {return job_id;}public void setJob_id(Integer job_id) {this.job_id = job_id;}public Integer getMgr() {return mgr;}public void setMgr(Integer mgr) {this.mgr = mgr;}public Date getJoindate() {return joindate;}public void setJoindate(Date joindate) {this.joindate = joindate;}public Double getSalary() {return salary;}public void setSalary(Double salary) {this.salary = salary;}public Double getBonus() {return bonus;}public void setBonus(Double bonus) {this.bonus = bonus;}public Integer getDept_id() {return dept_id;}public void setDept_id(Integer dept_id) {this.dept_id = dept_id;} }
这个类中,我们类的属性全都是引用类型的变量,即基本数据类型的变量我们也使用了对应封装类,这么做的原因和后面的BeanPropertyRowMapper有关,一会你就知道了。
接下来我们通过单元测试的方法来解决那些问题,还记得单元测试吗?下面是我分享的JUnit包:
链接:https://pan.baidu.com/s/1If_y5S16T6P1uXCJwTPb4g
提取码:wun0
pers.luoluo.jdbctemplate包下新建一个java文件来测试,下面我已经将七个任务封装成七个方法,可以利用单元测试执行。
public class JdbcTemplateTest {//1.获取JDBCTemplate对象private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDateSource());// 修改1号数据的salary为10000@Testpublic void test1(){//2.定义sqlString sql="UPDATE emp SET salary=10000 WHERE id=1001";//3.执行SQLint count=template.update(sql);Assert.assertEquals(1,count); //测试通过}// 添加一条记录@Testpublic void test2(){//2.定义sqlString sql="INSERT INTO emp(id,ename,dept_id) values(?,?,?)";int count=template.update(sql,1015,"郭靖",10);Assert.assertEquals(1,count); //测试通过}// 删除刚才添加的记录@Testpublic void test3(){String sql="DELETE FROM emp WHERE id=?";int count=template.update(sql,1015);Assert.assertEquals(1,count); //测试通过}// 查询id为1的记录,将其封装为Map集合//将字段封装为key,将数据封装为value//注意:queryForMap方法查询的结果集长度只能是1@Testpublic void test4(){String sql="SELECT * FROM emp WHERE id=?";Map<String, Object> map = template.queryForMap(sql, 1001);System.out.println(map);}// 查询所有的记录,将其封装为List// 将每一条记录封装为一个Map集合,再将多个Map集合装载到一个List集合中@Testpublic void test5(){String sql="SELECT * FROM emp";List<Map<String, Object>> maps = template.queryForList(sql);for(Map<String,Object> map:maps){System.out.println(map);}}// 查询所有的记录,将其封装为Emp对象的List集合@Testpublic void test6_1(){String sql="SELECT * FROM emp";//手动重写RowMapper接口的方法实现装载List<Emp> query = template.query(sql, new RowMapper<Emp>() {@Overridepublic Emp mapRow(ResultSet rs, int i) throws SQLException {Emp emp = new Emp();//获取数据(rs的getXXX的参数传入名必须与数据库端字段名相同)emp.setId(rs.getInt("id"));emp.setEname(rs.getString("ename"));emp.setJob_id(rs.getInt("job_id"));emp.setMgr(rs.getInt("mgr"));emp.setJoindate(rs.getDate("joindate"));emp.setSalary(rs.getDouble("salary"));emp.setBonus(rs.getDouble("bonus"));emp.setDept_id(rs.getInt("dept_id"));return emp;}});for(Emp emp:query){System.out.println(emp);}}// 查询所有的记录,将其封装为Emp对象的List集合//一般我们使用BeanPropertyRowMapper实现类,可以完成数据到JavaBean的自动封装//参数要传入JavaBean的class对象,它会自动匹配变量名和数据库中的字段名//另外,JavaBean中的字段对应的数据库字段的数据有NULL的话,JavaBean的那个变量请设置成引用类型//因为基本数据类型是不能被赋值NULL的,必须是引用类型才可以。//这也就是为什么前面Emp表中的变量的类型int变成了Integer(int的封装类)等@Testpublic void test6_2(){String sql="SELECT * FROM emp";List<Emp> query = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));for(Emp emp:query){System.out.println(emp);}}// 查询总的记录数//queryForObject一般用于聚合函数的查询@Testpublic void test7(){String sql="SELECT COUNT(id) FROM emp";long total = template.queryForObject(sql, Long.class);Assert.assertEquals(14,total); //测试通过} }
test6中我们分成了两种情况:
第一种是说创建RowMapper的匿名对象 ,这里是匿名内部类的写法,我们在后面重写具体的方法,实现ResultSet到JavaBean的映射。
第二种是使用了一个Spring框架内部提供的类——BeanPropertyRowMapper,通过传入字节码文件,它会自动将数据库字段与JavaBean类中的变量进行映射,需要注意的是JavaBean中的变量建议使用引用类型,如果是基本数据类型,而对应的数据库字段中有个数据是null,那么这里就会报错(因为基本数据类型不能是null,所以这里无法映射过来)。
JDBC,以及衍生出来的数据库连接池、Spring JDBC的知识点的学习就到此为止了。
青山不改、绿水长流,我们后会有期。
商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢
JDBC及衍生知识(下)相关推荐
- JDBC及衍生知识(上)
JDBC及衍生知识(上) 前言 补了补MySQL,终于又回到了Java的怀抱. 今天来开始学习JDBC等知识. JDBC 概念 JDBC,Java DataBase Connectivity,即J ...
- 聊聊 JDBC 的 executeBatch || 对比下不同数据库对 JDBC batch 的实现细节
聊聊 JDBC 的 executeBatch || 对比下不同数据库对 JDBC batch 的实现细节 || 剖析下 Mysql 的 参数 rewriteBatchedStatements || 剖 ...
- Spark Structured : HIve jdbc方式访问待下划线的表,找不到表的错误
1.背景 Spark Structured : HIve jdbc方式访问待下划线的表,找不到表的错误 > select * from default._xd_after limit 1; &g ...
- 营养素的基础知识下(非技术文)
营养素的基础知识下 一.碳水化合物(糖类) 1.什么是碳水化合物 2.碳水化合物的分类 3.碳水化合物的作用 4膳食纤维 二.矿物质 1.矿物质的作用 2.矿物质的的特点 3.缺乏矿物质后会产生的后果 ...
- [0 to 0.5]从零开始学习Android动画知识(下)
[0 to 0.5]从零开始学习Android动画知识(下) 矢量动画(Scalable Vector Graphics) 不同于前面的为控件做动画效果的方法,矢量动画则是为图形做出动画效果 矢量图 ...
- mysql binlog_checksum_【原创】研发应该懂的binlog知识(下)
引言 这篇是<研发应该懂的binlog知识(上)>的下半部分.在本文,我会阐述一下binlog的结构,以及如何使用java来解析binlog. 不过,话说回来,其实严格意义上来说,研发应该 ...
- C语言程序设计做题笔记之C语言基础知识(下)
C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...
- 电商商家玩抖音裂变营销,必须要知道的数据分析知识-下秒数据
电商商家玩抖音裂变营销,必须要知道的数据分析知识 我国电商进入了飞速发展的时代,在电商上有很多营销产品的机会,对于商家们来说,只有去留住忠诚客户.不断的吸引新客户才能得到更多的收益,所以找一个适合自己 ...
- java高级之JDBC的基本操作知识
1.SQL的表达式中可用的通配符有%(百分号)和_(下划线),而在SELECT子句中虽然可用*(星号)来表示从表中取出所有列,但它不是通配符.%匹配包含零个或多个字符的任意字符串.这个通配符既可以用作 ...
最新文章
- ueditor html显示图片,百度ueditor编辑器上传图片后img标签的title、alt属性优化简单方法...
- acwing算法题--多重背包问题一
- Javascript设计模式
- linux中iptable中端口,Linux如何打开iptables中的端口
- sublime text3安装js提示的插件
- 13.5.SolrCloud集群使用手册之数据导入
- Uvaoj 11624 - Fire!
- Linux内核网络协议栈1- socket文件系统注册
- 初学JAVA随记——8bit(1byte)的取值范围是+127到—128
- 技巧:使用User Control做HTML生成(转)
- 将文件夹下所有csv文件转换成所有txt
- 为什么20的阶乘是负的Java_为什么 n 为20 阶乘为负数
- Windows系统下快速安装、配置Aira2,及图形界面配置、度盘、B站视频下载
- 一周之内连过5人,HCIE-RS新版实验这么好考?
- dqw3721:自己动手写打印机监控程序
- python基础语法大全
- 【软件project】 文档 - 银行业务管理 - 需求分析
- 计算机课代表中段考总结,第一学期中段考试总结
- ALTAS,LAPACK, SCALAPACK, MUMPS记录
- Resultful API的拦截(过滤器——Filter)
热门文章
- Outlook邮箱只显示一个邮箱账号内容怎么解决,outlook如何切换邮箱账号显示
- C语言中变量未初始化的处理
- Microsoft Windows Office 2019官方下载链接
- top.location和window.location有什么区别?
- php 此网页包含重定向循环,打开网页浏览器提示:此网页包含重定向循环怎么办...
- 智达信股票自动交易软件 3.2.1207.3
- 如何判断dll程序的位数:32位or64位
- 车载OS - AGL 和 GENIVI区别
- Web前端之去除超链接的下划线
- C# 定积分求周长面积原理 代码实现