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.pswp.cn/news/534959.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/534959.shtml
英文地址,請注明出處:http://en.pswp.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…

keyloadtool_phoenix 利用CsvBulkLoadTool 批量帶入數據并自動創建索引

需要先創建表&#xff1a;CREATE TABLE IF NOT EXISTS population (state CHAR(2) NOT NULL, city VARCHAR NOT NULL, population BIGINTCONSTRAINT my_pk PRIMARY KEY (state, city));在phoenix 目錄下執行hadoop jar /home/phoenix-4.6.0-HBase-1.0-bin/phoenix-4.6.0-HBase-…

【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…

MySQL摘要_mysql摘要

2011-04-15(1)mysqld關閉命令&#xff1a;mysqladmin -u root shutdown。注意&#xff1a;windows命令以enter結束不是;&#xff0c;mysql命令行才是(2)mysql終端接入&#xff0c;修改mysql.user表內容&#xff0c;添加授權用戶。insert into mysql.user(Host,User,Password,ss…

錯誤代碼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;命…

java mysql dump_Java 調用Mysql dump 備份數據庫

SimpleDateFormat sdf new SimpleDateFormat("yyyyMMddHHmmss");try {String name sdf.format(new Date());String filePath System.getProperty("user.dir") "//" name ".sql";// 系統執行器Runtime rt Runtime.getRuntime();…

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:{ # 輸…

mysql事務隔離最高_Mysql事務隔離級別

mysql官方文檔顯示&#xff1a;InnoDB中每個隔離級別的詳細描述如下&#xff1a; READ UNCOMMITTEDSELECT語句以非鎖定方式被執行&#xff0c;但是一個可能更早期版本的記錄會被用到。因此&#xff0c;使用這個隔離級別&#xff0c;比如&#xff0c;讀是不連貫的。著也被稱為“…