jdbc mysql分页_JDBC【数据库连接池、DbUtils框架、分页】

1.数据库连接池

什么是数据库连接池

简单来说:数据库连接池就是提供连接的。。。

为什么我们要使用数据库连接池

数据库的连接的建立和关闭是非常消耗资源的

频繁地打开、关闭连接造成系统性能低下

编写连接池

编写连接池需实现java.sql.DataSource接口

创建批量的Connection用LinkedList保存【既然是个池,当然用集合保存、、LinkedList底层是链表,对增删性能较好】

实现getConnetion(),让getConnection()每次调用,都是在LinkedList中取一个Connection返回给用户

调用Connection.close()方法,Connction返回给LinkedList

private static LinkedList list = new LinkedList<>();

//获取连接只需要一次就够了,所以用static代码块

static {

//读取文件配置

InputStream inputStream = Demo1.class.getClassLoader().getResourceAsStream("db.properties");

Properties properties = new Properties();

try {

properties.load(inputStream);

String url = properties.getProperty("url");

String username = properties.getProperty("username");

String driver = properties.getProperty("driver");

String password = properties.getProperty("password");

//加载驱动

Class.forName(driver);

//获取多个连接,保存在LinkedList集合中

for (int i = 0; i < 10; i++) {

Connection connection = DriverManager.getConnection(url, username, password);

list.add(connection);

}

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (SQLException e) {

e.printStackTrace();

}

}

//重写Connection方法,用户获取连接应该从LinkedList中给他

@Override

public Connection getConnection() throws SQLException {

System.out.println(list.size());

System.out.println(list);

//先判断LinkedList是否存在连接

return list.size() > 0 ? list.removeFirst() : null;

}

我们已经完成前三步了,现在问题来了。我们调用Conncetion.close()方法,是把数据库的物理连接关掉,而不是返回给LinkedList的

解决思路:

写一个Connection子类,覆盖close()方法

写一个Connection包装类,增强close()方法

用动态代理,返回一个代理对象出去,拦截close()方法的调用,对close()增强

分析第一个思路:

Connection是通过数据库驱动加载的,保存了数据的信息。写一个子类Connection,new出对象,子类的Connction无法直接继承父类的数据信息,也就是说子类的Connection是无法连接数据库的,更别谈覆盖close()方法了。

分析第二个思路:

写一个Connection包装类。

写一个类,实现与被增强对象的相同接口【Connection接口】

定义一个变量,指向被增强的对象

定义构造方法,接收被增强对象

覆盖想增强的方法

对于不想增强的方法,直接调用被增强对象的方法

这个思路本身是没什么毛病的,就是实现接口时,方法太多了!,所以我们也不使用此方法

分析第三个思路代码实现:

@Override

public Connection getConnection() throws SQLException {

if (list.size() > 0) {

final Connection connection = list.removeFirst();

//看看池的大小

System.out.println(list.size());

//返回一个动态代理对象

return (Connection) Proxy.newProxyInstance(Demo1.class.getClassLoader(), connection.getClass().getInterfaces(), new InvocationHandler() {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//如果不是调用close方法,就按照正常的来调用

if (!method.getName().equals("close")) {

return method.invoke(connection, args);

} else {

//进到这里来,说明调用的是close方法

list.add(connection);

//再看看池的大小

System.out.println(list.size());

}

return null;

}

});

}

return null;

}

我们上面已经能够简单编写一个线程池了。下面我们来使用一下开源数据库连接池

DBCP

使用DBCP数据源的步骤:

导入两个jar包【Commons-dbcp.jar和Commons-pool.jar】

读取配置文件

获取BasicDataSourceFactory对象

创建DataSource对象

private static DataSource dataSource = null;

static {

try {

//读取配置文件

InputStream inputStream = Demo3.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");

Properties properties = new Properties();

properties.load(inputStream);

//获取工厂对象

BasicDataSourceFactory basicDataSourceFactory = new BasicDataSourceFactory();

dataSource = basicDataSourceFactory.createDataSource(properties);

} catch (IOException e) {

e.printStackTrace();

} catch (Exception e) {

e.printStackTrace();

}

}

public static Connection getConnection() throws SQLException {

return dataSource.getConnection();

}

//这里释放资源不是把数据库的物理连接释放了,是把连接归还给连接池【连接池的Connection内部自己做好了】

public static void release(Connection conn, Statement st, ResultSet rs) {

if (rs != null) {

try {

rs.close();

} catch (Exception e) {

e.printStackTrace();

}

rs = null;

}

if (st != null) {

try {

st.close();

} catch (Exception e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

C3P0

C3P0数据源的性能更胜一筹,并且它可以使用XML配置文件配置信息!

步骤:

导入开发包【c3p0-0.9.2-pre1.jar】和【mchange-commons-0.2.jar】

导入XML配置文件【可以在程序中自己一个一个配,C3P0的doc中的Configuration有XML文件的事例】

new出ComboPooledDataSource对象

private static ComboPooledDataSource comboPooledDataSource = null;

static {

//如果我什么都不指定,就是使用XML默认的配置,这里我指定的是oracle的

comboPooledDataSource = new ComboPooledDataSource("oracle");

}

public static Connection getConnection() throws SQLException {

return comboPooledDataSource.getConnection();

}

Tomcat数据源

Tomcat服务器也给我们提供了连接池,内部其实就是DBCP

步骤:

在META-INF目录下配置context.xml文件【文件内容可以在tomcat默认页面的 JNDI Resources下Configure Tomcat's Resource Factory找到】

导入Mysql或oracle开发包到tomcat的lib目录下

初始化JNDI->获取JNDI容器->检索以XXX为名字在JNDI容器存放的连接池

context.xml文件的配置:

auth="Container"

type="javax.sql.DataSource"

username="root"

password="root"

driverClassName="com.mysql.jdbc.Driver"

url="jdbc:mysql://localhost:3306/zhongfucheng"

maxActive="8"

maxIdle="4"/>

try {

//初始化JNDI容器

Context initCtx = new InitialContext();

//获取到JNDI容器

Context envCtx = (Context) initCtx.lookup("java:comp/env");

//扫描以jdbc/EmployeeDB名字绑定在JNDI容器下的连接池

DataSource ds = (DataSource)

envCtx.lookup("jdbc/EmployeeDB");

Connection conn = ds.getConnection();

System.out.println(conn);

}

使用dbutils框架

dbutils它是对JDBC的简单封装,极大简化jdbc编码的工作量

DbUtils类

提供了关闭连接,装载JDBC驱动,回滚提交事务等方法的工具类【比较少使用,因为我们学了连接池,就应该使用连接池连接数据库】

QueryRunner类

该类简化了SQL查询,配合ResultSetHandler使用,可以完成大部分的数据库操作,重载了许多的查询,更新,批处理方法。大大减少了代码量

ResultSetHandler接口

该接口规范了对ResultSet的操作,要对结果集进行什么操作,传入ResultSetHandler接口的实现类即可。

ArrayHandler:把结果集中的第一行数据转成对象数组。

ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。

BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。

BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。

ColumnListHandler:将结果集中某一列的数据存放到List中。

KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。

MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。

MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List

ScalarHandler 将ResultSet的一个列到一个对象中。

使用DbUtils框架对数据库的CRUD

/*

* 使用DbUtils框架对数据库的CRUD

* 批处理

*

* */

public class Test {

@org.junit.Test

public void add() throws SQLException {

//创建出QueryRunner对象

QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());

String sql = "INSERT INTO student (id,name) VALUES(?,?)";

//我们发现query()方法有的需要传入Connection对象,有的不需要传入

//区别:你传入Connection对象是需要你来销毁该Connection,你不传入,由程序帮你把Connection放回到连接池中

queryRunner.update(sql, new Object[]{"100", "zhongfucheng"});

}

@org.junit.Test

public void query()throws SQLException {

//创建出QueryRunner对象

QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());

String sql = "SELECT * FROM student";

List list = (List) queryRunner.query(sql, new BeanListHandler(Student.class));

System.out.println(list.size());

}

@org.junit.Test

public void delete() throws SQLException {

//创建出QueryRunner对象

QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());

String sql = "DELETE FROM student WHERE id='100'";

queryRunner.update(sql);

}

@org.junit.Test

public void update() throws SQLException {

//创建出QueryRunner对象

QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());

String sql = "UPDATE student SET name=? WHERE id=?";

queryRunner.update(sql, new Object[]{"zhongfuchengaaa", 1});

}

@org.junit.Test

public void batch() throws SQLException {

//创建出QueryRunner对象

QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());

String sql = "INSERT INTO student (name,id) VALUES(?,?)";

Object[][] objects = new Object[10][];

for (int i = 0; i < 10; i++) {

objects[i] = new Object[]{"aaa", i + 300};

}

queryRunner.batch(sql, objects);

}

}

分页

分页技术是非常常见的,在搜索引擎下搜索页面,不可能把全部数据都显示在一个页面里边。所以我们用到了分页技术。

Oracle实现分页

/*

Oracle分页语法:

@lineSize---每页显示数据行数

@currentPage----当前所在页

*/

SELECT *FROM (

SELECT 列名,列名,ROWNUM rn

FROM 表名

WHERE ROWNUM<=(currentPage*lineSize)) temp

WHERE temp.rn>(currentPage-1)*lineSize;

Oracle分页原理简单解释:

/*

Oracle分页:

Oracle的分页依赖于ROWNUM这个伪列,ROWNUM主要作用就是产生行号。

分页原理:

1:子查询查出前n行数据,ROWNUM产生前N行的行号

2:使用子查询产生ROWNUM的行号,通过外部的筛选出想要的数据

例子:

我现在规定每页显示5行数据【lineSize=5】,我要查询第2页的数据【currentPage=2】

注:【对照着语法来看】

实现:

1:子查询查出前10条数据【ROWNUM<=10】

2:外部筛选出后面5条数据【ROWNUM>5】

3:这样我们就取到了后面5条的数据

*/

Mysql实现分页

/*

Mysql分页语法:

@start---偏移量,不设置就是从0开始【也就是(currentPage-1)*lineSize】

@length---长度,取多少行数据

*/

SELECT *

FROM 表名

LIMIT [START], length;

/*

例子:

我现在规定每页显示5行数据,我要查询第2页的数据

分析:

1:第2页的数据其实就是从第6条数据开始,取5条

实现:

1:start为5【偏移量从0开始】

2:length为5

*/

总结:

Mysql从(currentPage-1)*lineSize开始取数据,取lineSize条数据

Oracle先获取currentPagelineSize条数据,从(currentPage-1)lineSize开始取数据

使用JDBC连接数据库实现分页

下面是常见的分页图片

XiVdAWv.png

配合图片,看下我们的需求是什么:

算出有多少页的数据,显示在页面上

根据页码,从数据库显示相对应的数据。

分析:

算出有多少页数据这是非常简单的【在数据库中查询有多少条记录,你每页显示多少条记录,就可以算出有多少页数据了】

使用Mysql或Oracle的分页语法即可

通过上面分析,我们会发现需要用到4个变量

currentPage--当前页【由用户决定的】

totalRecord--总数据数【查询表可知】

lineSize--每页显示数据的数量【由我们开发人员决定】

pageCount--页数【totalRecord和lineSize决定】

//每页显示3条数据

int lineSize = 3;

//总记录数

int totalRecord = getTotalRecord();

//假设用户指定的是第2页

int currentPage = 2;

//一共有多少页

int pageCount = getPageCount(totalRecord, lineSize);

//使用什么数据库进行分页,记得要在JdbcUtils中改配置

List list = getPageData2(currentPage, lineSize);

for (Person person : list) {

System.out.println(person);

}

}

//使用JDBC连接Mysql数据库实现分页

public static List getPageData(int currentPage, int lineSize) throws SQLException {

//从哪个位置开始取数据

int start = (currentPage - 1) * lineSize;

QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());

String sql = "SELECT name,address FROM person LIMIT ?,?";

List persons = (List) queryRunner.query(sql, new BeanListHandler(Person.class), new Object[]{start, lineSize});

return persons;

}

//使用JDBC连接Oracle数据库实现分页

public static List getPageData2(int currentPage, int lineSize) throws SQLException {

//从哪个位置开始取数据

int start = (currentPage - 1) * lineSize;

//读取前N条数据

int end = currentPage * lineSize;

QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());

String sql = "SELECT " +

" name, " +

" address " +

"FROM ( " +

" SELECT " +

" name, " +

" address , " +

" ROWNUM rn " +

" FROM person " +

" WHERE ROWNUM <= ? " +

")temp WHERE temp.rn>?";

List persons = (List) queryRunner.query(sql, new BeanListHandler(Person.class), new Object[]{end, start});

return persons;

}

public static int getPageCount(int totalRecord, int lineSize) {

//简单算法

//return (totalRecord - 1) / lineSize + 1;

//此算法比较好理解,把数据代代进去就知道了。

return totalRecord % lineSize == 0 ? (totalRecord / lineSize) : (totalRecord / lineSize) + 1;

}

public static int getTotalRecord() throws SQLException {

//使用DbUtils框架查询数据库表中有多少条数据

QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());

String sql = "SELECT COUNT(*) FROM person";

Object o = queryRunner.query(sql, new ScalarHandler());

String ss = o.toString();

int s = Integer.parseInt(ss);

return s;

}

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/534959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python读写文件操作_详解Python文件读写操作

读文件 打开文件&#xff08;文件需要存在&#xff09;#打开文件 f open("data.txt","r") #设置文件对象 print(f)#文件句柄 f.close() #关闭文件 #为了方便&#xff0c;避免忘记close掉这个文件对象&#xff0c;可以用下面这种方式替代 with open(data.t…

【cloud Alibaba】(三)流量控制、熔断降级(下)——Sentinel

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的spring cloud专栏&#xff0c;在这个系列专栏中我对B站尚硅谷阳哥的spring cloud教程进行一个总结&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波依然是血赚 ┗|&#xff40;O′|┛ &#x1f4a1;Sen…

python gui入门的例子_Python GUI编程之Tkinter入门之道

相信刚学习使用Python进行GUI编程的时候&#xff0c;肯定都会听过Tkinter&#xff0c;毕竟是standard Python interface to the Tk GUI toolkit.用来写一些小程序还是很方便的。但如果是刚接触GUI编程的话肯定是被官方文档搞的有些懵&#xff0c;毕竟还没弄清楚套路。之前使用过…

@async 默认线程池_SpringBoot 线程池的使用

Java大联盟帮助万千Java学习者持续成长关注作者&#xff5c;Musclehengblog.csdn.net/Muscleheng/article/details/81409672前言最近在做订单模块&#xff0c;用户购买服务类产品之后&#xff0c;需要进行预约&#xff0c;预约成功之后分别给商家和用户发送提醒短信。考虑发短信…

mysql 横向扩展 中间件_mysql-proxy数据库中间件架构 | 架构师之路

一、mysql-proxy简介mysql-proxy是mysql官方提供的mysql中间件服务&#xff0c;上游可接入若干个mysql-client&#xff0c;后端可连接若干个mysql-server。它使用mysql协议&#xff0c;任何使用mysql-client的上游无需修改任何代码&#xff0c;即可迁移至mysql-proxy上。mysql-…

python selenium对象怎么序列化_python selenium爬取斗鱼

不加延迟报错selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {“method”:”xpath”,”selector”:”.//span[class”DyListCover-hot”]”}(Session info: chrome80.0.3987.122)最开始以为是版本问题&#xff0c;不…

神经网络的全连接层_深度神经网络全连接层

一、概念全连接层一般在网络的最后部分做分类输出&#xff0c;全连接层的有m个输入和n个输出&#xff0c;每一个输出都和所有的输入相连&#xff0c;相连的权重w都是不一样的&#xff0c;同时每一个输出还有一个bias。二、前向全连接假设输入是4&#xff0c;输出是4&#xff0c…

vs 选定内容没有属性页_从智能单品,到全屋智能:2019中国智能家居发展白皮书【附82页PPT】...

2019年&#xff0c;智能家居行业在技术、市场和行业的变革中迎接新的挑战和机遇。一方面&#xff0c;AI、IoT、边缘计算全面赋能智能家居&#xff1b;另一方面&#xff0c;中国的房地产行业正在从上半场的“增量开发”&#xff0c;切换到下半场的“存量经营”、“楼盘精装化”政…

python决策树的应用_机器学习-决策树实战应用

1.下载2.安装&#xff1a;双击3.创建桌面快捷方式安装目录\bin文件夹\&#xff1a;找到gvedit.exe文件右键 发送到桌面快捷方式&#xff0c;如下图&#xff1a;4.配置环境变量将graphviz安装目录下的bin文件夹添加到Path环境变量中&#xff1a;5.验证是否安装并配置成功进入win…

【SSM面向CRUD编程专栏 3】关于黑马程序员最全SSM框架教程视频,P37集老师跳过的模块创建以及tomcat下载安装配置和运行等诸多问题

写在前面&#xff1a;​ 本人是在学习B站黑马程序员SSM框架教程视频的时候在P37集遇到了问题&#xff0c;如果不解决还没办法往下接着听&#xff0c;老师跳过的模块创建以及tomcat下载安装配置和运行等诸多问题&#xff0c;全在这篇博客中得到了解决 &#x1f622;解决上…

python人脸识别源码_Python 抖音机器人,让你找到漂亮小姐姐

本项目作者沉迷于抖音无法自拔&#xff0c;常常花好几个小时在抖音漂亮小姐姐身上。本着高效、直接地找到漂亮小姐姐的核心思想&#xff0c;我用 Python ADB 做了一个 Python 抖音机器人 Douyin-Bot。特性自动翻页颜值检测人脸识别自动点赞自动关注随机防 Ban自动评论原理打开…

thinkphp josn mysql_ThinkPHP:JSON字段类型的使用(ORM)

ThinkPHP5.1版本正式发布已经有一段时间了&#xff0c;我会陆续给大家介绍其中的新特性。今天要给大家介绍的是一个可能很多用户还不了解的一个特性&#xff1a;JSON字段数据支持。不过首先注意一点&#xff0c;本篇内容中描述的JSON字段数据的支持是从V5.1.4版本引入的。由于包…

获取http地址如何从上面抓取图片_用 Python 自动抓取妹子图

目录前言Media Pipeline启用Media Pipeline使用 ImgPipeline抓取妹子图瞎比比与送书后话前言我们在抓取数据的过程中&#xff0c;除了要抓取文本数据之外&#xff0c;当然也会有抓取图片的需求。那我们的 scrapy 能爬取图片吗&#xff1f;答案是&#xff0c;当然的。说来惭愧&a…

错误代码0x800f0950怎么解决_解决win10安装net framework 3.5失败(错误代码 0x800F0950)...

视频教程&#xff1a;Win10教程 安装net framework 3.5失败(错误代码 0x800F0950)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.com一&#xff1a;出现问题&#xff1a;报错代码二&#xff1a;解决步骤1.通过命令提示符明确自己系统版本Windows键X ,打开&#xff08;命…

python 日志不会按照日期分割_django实现日志按日期分割

settings文件中配置&#xff1a; LOGGING { version:1, disable_existing_logger:False, formatters:{ verbose:{ format:%(asctime)s \"%(pathname)s&#xff1a;%(module)s:%(funcName)s:%(lineno)d\" [%(levelname)s]-%(message)s }, }, # 处理器 handlers:{ # 输…

exe打包工具哪个最好_一键分发工具哪个最好用?这款30万人都在用,很优秀!...

现代化媒体对于传播越来越重要&#xff0c;16年到如今&#xff0c;视频内容产业实在有话题度&#xff0c;其高效的粉丝互动机制、低资金投入高额回报等等亮点&#xff0c;强烈吸引着数以百万计的创造者&#xff0c;为了达到极其出色的阅读量&#xff0c;这些人往往会运用到所有…

date转timestamp格式_技术分享 | MySQL:timestamp 时区转换导致 CPU %sy 高的问题

作者&#xff1a;高鹏文章末尾有他著作的《深入理解 MySQL 主从原理 32 讲》&#xff0c;深入透彻理解 MySQL 主从&#xff0c;GTID 相关技术知识。本文为学习记录&#xff0c;可能有误请谅解。本文建议PC端观看&#xff0c;效果更佳。这个问题是一个朋友遇到的风云&#xff0c…

mysql架构组成_第 2 章 MySQL 架构组成

麻雀虽小&#xff0c;五脏俱全。MySQL 虽然以简单著称&#xff0c;但其内部结构并不简单。本章从MySQL物理组成、逻辑组成&#xff0c;以及相关工具几个角度来介绍 MySQL 的整体架构组成&#xff0c;希望能够让读者对 MySQL 有一个更全面深入的了解。2&#xff0e;1 MySQL物理文…

win2008 mysql端口_使用自定义端口连接SQL Server 2008的方法

使用过SQL Server的人大多都知道&#xff0c;SQL Server服务器默认监听的端口号是1433&#xff0c;但是我今天遇到的问题是我的机器上有三个数据库实例&#xff0c;这样使用TCP/IP远程连接时就产生了问题。如何在Microsoft SQL Server Management Studio里加入端口号连接呢&…

python基本命令range_Python的Range()函数(指南)

当需要执行特定次数的操作时&#xff0c;Python内置的range函数十分方便。 读罢本文&#xff0c;你将&#xff1a; 理解Python的range函数是如何工作的 了解Python 2和Python 3中的实现方式有何不同 看过了不少range()函数操作实例 有能力解决它的一些局限性 让我们开始吧&…