簡單來講:數據庫鏈接池就是提供鏈接的。。。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
分析第二個思路:數據庫
寫一個Connection包裝類。數組
分析第三個思路代碼實現:tomcat
@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; }
咱們上面已經可以簡單編寫一個線程池了。下面咱們來使用一下開源數據庫鏈接池服務器
使用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。