簡單來講:數據庫鏈接池就是提供鏈接的。。。java
private static LinkedList<Connection> 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的**mysql
解決思路:算法
分析第一個思路:sql
分析第二個思路:數據庫
分析第三個思路代碼實現:數組
@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")) {
method.invoke(connection, args);
} else {
//進到這裏來,說明調用的是close方法
list.add(connection);
//再看看池的大小
System.out.println(list.size());
}
return null;
}
});
}
return null;
}
複製代碼
咱們上面已經可以簡單編寫一個線程池了。下面咱們來使用一下開源數據庫鏈接池tomcat
使用DBCP數據源的步驟:服務器
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數據源的性能更勝一籌,而且它能夠使用XML配置文件配置信息!微信
步驟:oracle
private static ComboPooledDataSource comboPooledDataSource = null;
static {
//若是我什麼都不指定,就是使用XML默認的配置,這裏我指定的是oracle的
comboPooledDataSource = new ComboPooledDataSource("oracle");
}
public static Connection getConnection() throws SQLException {
return comboPooledDataSource.getConnection();
}
複製代碼
Tomcat服務器也給咱們提供了鏈接池,內部其實就是DBCP
步驟:
context.xml文件的配置:
<Context>
<Resource name="jdbc/EmployeeDB"
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"/>
</Context>
複製代碼
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它是對JDBC的簡單封裝,極大簡化jdbc編碼的工做量
提供了關閉鏈接,裝載JDBC驅動,回滾提交事務等方法的工具類【比較少使用,由於咱們學了鏈接池,就應該使用鏈接池鏈接數據庫】
該類簡化了SQL查詢,配合ResultSetHandler使用,能夠完成大部分的數據庫操做,重載了許多的查詢,更新,批處理方法。大大減小了代碼量
該接口規範了對ResultSet的操做,要對結果集進行什麼操做,傳入ResultSetHandler接口的實現類便可。
使用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分頁語法: @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分頁語法: @start---偏移量,不設置就是從0開始【也就是(currentPage-1)*lineSize】 @length---長度,取多少行數據 */
SELECT *
FROM 表名
LIMIT [START], length;
/* 例子: 我如今規定每頁顯示5行數據,我要查詢第2頁的數據 分析: 1:第2頁的數據其實就是從第6條數據開始,取5條 實現: 1:start爲5【偏移量從0開始】 2:length爲5 */
複製代碼
總結:
下面是常見的分頁圖片
配合圖片,看下咱們的需求是什麼:
分析:
經過上面分析,咱們會發現須要用到4個變量
//每頁顯示3條數據
int lineSize = 3;
//總記錄數
int totalRecord = getTotalRecord();
//假設用戶指定的是第2頁
int currentPage = 2;
//一共有多少頁
int pageCount = getPageCount(totalRecord, lineSize);
//使用什麼數據庫進行分頁,記得要在JdbcUtils中改配置
List<Person> list = getPageData2(currentPage, lineSize);
for (Person person : list) {
System.out.println(person);
}
}
//使用JDBC鏈接Mysql數據庫實現分頁
public static List<Person> 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<Person> persons = (List<Person>) queryRunner.query(sql, new BeanListHandler(Person.class), new Object[]{start, lineSize});
return persons;
}
//使用JDBC鏈接Oracle數據庫實現分頁
public static List<Person> 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<Person> persons = (List<Person>) 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。