Spring 數(shù)據(jù)庫連接池(JDBC)詳解
數(shù)據(jù)庫連接池
對一個簡單的數(shù)據(jù)庫應(yīng)用,由于對數(shù)據(jù)庫的訪問不是很頻繁,這時可以簡單地在需要訪問數(shù)據(jù)庫時,就新創(chuàng)建一個連接,就完后就關(guān)閉它,這樣做也不會帶來什么性能上的開銷。但是對于一個復(fù)雜的數(shù)據(jù)庫應(yīng)用,情況就完全不同而,頻繁的建立、關(guān)閉連接,會極大地減低系統(tǒng)的性能,因為對于連接的使用成了系統(tǒng)性能的瓶頸。
通過建立一個數(shù)據(jù)庫連接池以及一套連接使用管理策略,可以達到連接復(fù)用的效果,使得一個數(shù)據(jù)庫連接可以得到安全、高效的復(fù)用,避免了數(shù)據(jù)庫連接頻繁建立、關(guān)閉的開銷。
數(shù)據(jù)庫連接池的基本原理是在內(nèi)部對象池中維護一定數(shù)量的數(shù)據(jù)庫連接,并對外暴露數(shù)據(jù)庫連接獲取和返回方法。如:外部使用者可通過getConnection方法獲取連接,使用完畢后再通過releaseConnection方法將連接返回,注意此時連接并沒有關(guān)閉,而是由連接池管理器回收,并為下一次使用做好準備。
數(shù)據(jù)庫連接池技術(shù)帶來的好處:
1、資源重用
由于數(shù)據(jù)庫連接得到重用,避免了頻繁創(chuàng)建、釋放鏈接引起的大量性能開銷。在減少系統(tǒng)消耗的基礎(chǔ)上,另一方面也增進了系統(tǒng)運行環(huán)境的平穩(wěn)性(減少內(nèi)存碎片以及數(shù)據(jù)庫臨時進行/線程數(shù)量)
2、更快地系統(tǒng)響應(yīng)速度
數(shù)據(jù)庫連接池在初始化過程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫連接池置于池中備用。此時連接的初始化工作均已完成,對于業(yè)務(wù)請求處理而言,直接利用現(xiàn)有可用連接,避免了數(shù)據(jù)庫連接初始化和釋放過程的時間開銷,從而縮減了系統(tǒng)整體響應(yīng)時間
3、統(tǒng)一的連接管理,避免數(shù)據(jù)庫連接泄露
在較為完備的數(shù)據(jù)庫連接池實現(xiàn)中,可根據(jù)預(yù)先的連接占用超時設(shè)定,強制收回被占用連接,從而避免了常規(guī)數(shù)據(jù)庫連接操作中可能出現(xiàn)的資源泄露。
目前數(shù)據(jù)庫連接池產(chǎn)品是非常多的,主要有:
1、dbcp
dbcp,即DataBase Connection PoolApache出品,Spring開發(fā)組推薦使用的數(shù)據(jù)庫連接池,開發(fā)較為活躍,是一個使用極為廣泛的數(shù)據(jù)庫連接池產(chǎn)品。不過從網(wǎng)上
2、c3p0
Hibernate開發(fā)組推薦使用的數(shù)據(jù)庫連接池,它實現(xiàn)了數(shù)據(jù)源和JNDI的綁定
3、Proxool
Proxool的口碑較好,沒什么負面評價(比如dbcp就是因為Hibernate認為它BUG太多Hibernate才不推薦使用的),也是Hibernate開發(fā)組推薦使用的數(shù)據(jù)庫連接池,不過使用者不算多,開發(fā)不夠活躍。這個連接池提供了連接池監(jiān)控的功能,方便易用,便于發(fā)現(xiàn)連接池泄露的情況
基于Spring的JDBC基本框架搭建
先講一下使用Spring實現(xiàn)JDBC,數(shù)據(jù)庫連接池就用Spring開發(fā)組推薦的DBCP,DBCP需要三個jar包,先下載一下:
1、commons-dbcp-1.4.jar,官方網(wǎng)站上有,點我下載
2、commons.pool-1.6.jar,官方網(wǎng)站上有,點我下載
3、commons.collections4-4.0.jar,官方網(wǎng)站上有
下載了這三個jar包之后請導(dǎo)入自己的工程中(注意MySql的包別忘記導(dǎo)入了),雖然dbcp和pool都出了dbcp2和pool2的版本,Apache官網(wǎng)上都可以下載,但是這里提供的還是dbcp1和pool1的版本下載地址,一個原因是dbcp2和pool2都只可以在JDK1.7及JDK1.7以上的版本運行,而dbcp1和pool1則可以在JDK1.6的版本運行,考慮到MyEclipse10默認自帶的JRE就是1.6版本的,所以這里下載、使用dbcp1和pool1。想要dbcp2和pool2的可以自己去Apache官網(wǎng)下載,不過要注意,dbcp2必須和pool2一組,dbcp1必須和pool1一組,不可以混著用。
JDBC,我之前寫過一篇文章,數(shù)據(jù)庫建立和實體類都是用的原文章里面的,這里只是把原生的JDBC搬到Spring JDBC下而已,看下最基礎(chǔ)的寫法,再添加功能,學(xué)生管理類為:
public class StudentManager { private JdbcTemplate jdbcTemplate; private static StudentManager instance = new StudentManager(); public static StudentManager getInstance() { return instance; } public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } }
Spring的XML配置文件命名為jdbc.xml,jdbc.xml的寫法為:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <!-- 驅(qū)動包名 --> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <!-- 數(shù)據(jù)庫地址 --> <property name="url" value="jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8;" /> <!-- 用戶名 --> <property name="username" value="root" /> <!-- 密碼 --> <property name="password" value="root" /> <!-- 最大連接數(shù)量 --> <property name="maxActive" value="150" /> <!-- 最小空閑連接 --> <property name="minIdle" value="5" /> <!-- 最大空閑連接 --> <property name="maxIdle" value="20" /> <!-- 初始化連接數(shù)量 --> <property name="initialSize" value="30" /> <!-- 連接被泄露時是否打印 --> <property name="logAbandoned" value="true" /> <!-- 是否自動回收超時連接 --> <property name="removeAbandoned" value="true" /> <!-- 超時等待時間(以秒為單位) --> <property name="removeAbandonedTimeout" value="10" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="studentManager" class="com.xrq.jdbc.StudentManager" factory-method="getInstance"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> </beans>
主函數(shù)為:
public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("jdbc.xml"); System.out.println(StudentManager.getInstance()); System.out.println(StudentManager.getInstance().getJdbcTemplate()); }
運行沒什么問題,得到StudentManager的引用地址和StudentManager中屬性jdbcTemplate的引用地址,說明整個連接、注入都沒問題。
JDBCTemple是Spring里面最基本的JDBC模板,利用JDBC和簡單的索引參數(shù)查詢提供對數(shù)據(jù)庫的簡單訪問。除了JDBCTemplate,Spring還提供了NamedParameterJdbcTemplate和SimpleJdbcTemplate兩個類,前者能夠在執(zhí)行查詢時把值綁定到SQL里的命名參數(shù)而不是使用索引,后者利用Java 5的特性比如自動裝箱、泛型和可變參數(shù)列表來簡化JDBC模板的使用。具體使用哪個看個人喜好,這里使用JdbcTemplate,所以把JdbcTemplate添加到學(xué)生管理類中。
另外:
1、dbcp提供很多參數(shù)給用戶配置,每個參數(shù)的意思都以注釋的形式寫在.xml里面了,更加具體要知道每個參數(shù)的意思可以上網(wǎng)查詢一下
2、注意dbcp的屬性url,url指的是數(shù)據(jù)庫連接地址,遇到特殊字符需要轉(zhuǎn)義,所以這里的"&"變成了"&",不然會報錯
基于Spring的JDBC增刪改查
上面一部分搭建了一個Spring JDBC的基礎(chǔ)框架,下面看一下Java代碼如何實現(xiàn)CRUD,這個過程中jdbc.xml都不需要變化。
1、添加一個學(xué)生信息,代碼為:
// 添加學(xué)生信息 public boolean addStudent(Student student) { try { jdbcTemplate.update("insert into student values(null,?,?,?)", new Object[]{student.getStudentName(), student.getStudentAge(), student.getStudentPhone()}, new int[]{Types.VARCHAR, Types.INTEGER, Types.VARCHAR}); return true; } catch (Exception e) { return false; } }
2、根據(jù)Id刪除指定學(xué)生信息,代碼為:
// 根據(jù)Id刪除單個學(xué)生信息 public boolean deleteStudent(int id) { try { jdbcTemplate.update("delete from student where studentId = ?", new Object[]{id}, new int[]{Types.INTEGER}); return true; } catch (Exception e) { return false; } }
3、根據(jù)Id更新學(xué)生信息,代碼為:
// 根據(jù)Id更新指定學(xué)生信息 public boolean updateStudent(int Id, Student student) { try { jdbcTemplate.update("update student set studentName = ?, studentAge = ?, studentPhone = ? where studentId = ?", new Object[]{student.getStudentName(), student.getStudentAge(), student.getStudentPhone(), Id}, new int[]{Types.VARCHAR, Types.INTEGER, Types.VARCHAR, Types.INTEGER}); return true; } catch (Exception e) { return false; } }
4、根據(jù)Id查詢學(xué)生信息,代碼為:
// 根據(jù)學(xué)生Id查詢單個學(xué)生信息 public Student getStudent(int id) { try { return (Student)jdbcTemplate.queryForObject("select * from student where studentId = ?", new Object[]{id}, new int[]{Types.INTEGER}, new RowMapper<Student>(){ public Student mapRow(ResultSet rs, int arg1) throws SQLException { Student student = new Student(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getString(4)); return student; } }); } // 根據(jù)Id查詢學(xué)生信息拋異常, 不管什么原因, 認為查詢不到該學(xué)生信息, 返回null catch (DataAccessException e) { return null; } }
5、查詢所有學(xué)生信息,代碼為:
// 查詢所有學(xué)生信息 public List<Student> getStudents() { List<Map<String, Object>> resultList = jdbcTemplate.queryForList("select * from student"); List<Student> studentList = null; if (resultList != null && !resultList.isEmpty()) { studentList = new ArrayList<Student>(); Map<String, Object> map = null; for (int i = 0; i < resultList.size(); i++) { map = resultList.get(i); Student student = new Student( (Integer)map.get("studentId"), (String)map.get("studentName"), (Integer)map.get("studentAge"), (String)map.get("studentPhone") ); studentList.add(student); } } return studentList; }
這就是簡單的CRUD操作,有了這5個作為基礎(chǔ),其余都可以在這5個的基礎(chǔ)上做擴展,就不繼續(xù)詳細寫下去了,說幾個注意點:
1、個人使用經(jīng)驗來說,除了最后一個查詢所有的以外,建議給其他的都加上try...catch...塊,因為在操作失敗的時候會拋出異常,捕獲了就可以知道這次的操作失敗了,否則只能程序終止,而自己也不知道操作到底是成功還是失敗
2、添加信息、更新信息不建議把每個待操作的字段都作為形參而建議形參就是一個Student實體類,這樣一來更符合面向?qū)ο蟮脑O(shè)計原則,二來形參列表的字段多很容易導(dǎo)致出錯
3、update、query方法,如果有占位符?的話,建議選擇有參數(shù)類型的重載方法,指定每個占位符的字段類型,就像我上面代碼寫的那樣
最后,這里講的都是jdbcTemplate的基本使用,jdbcTemplate里面還有很多方法,就不一一細說了,可以自己去試一下,也可以查閱Spring API文檔。
讀取配置文件中的數(shù)據(jù)
之前我們都是把數(shù)據(jù)庫連接的一些屬性配置在db.properties里面的,這樣方便修改,而這里卻是在jdbc.xml里面寫死的,所以要想一個辦法怎么可以從db.properties里面讀取出配置,context幫助開發(fā)者實現(xiàn)了這一點,看一下jdbc.xml如何寫:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <!-- 驅(qū)動包名 --> <property name="driverClassName" value="${mysqlpackage}" /> <!-- 數(shù)據(jù)庫地址 --> <property name="url" value="${mysqlurl}" /> <!-- 用戶名 --> <property name="username" value="${mysqlname}" /> <!-- 密碼 --> <property name="password" value="${mysqlpassword}" /> <!-- 最大連接數(shù)量 --> <property name="maxActive" value="150" /> <!-- 最小空閑連接 --> <property name="minIdle" value="5" /> <!-- 最大空閑連接 --> <property name="maxIdle" value="20" /> <!-- 初始化連接數(shù)量 --> <property name="initialSize" value="30" /> <!-- 連接被泄露時是否打印 --> <property name="logAbandoned" value="true" /> <!-- 是否自動回收超時連接 --> <property name="removeAbandoned" value="true" /> <!-- 超時等待時間(以秒為單位) --> <property name="removeAbandonedTimeout" value="10" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="studentManager" class="com.xrq.jdbc.StudentManager" factory-method="getInstance"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> </beans>
重點就是第10行,第14、第16、第18、第20行就是取屬性的寫法,和前端的FTL語言類似。
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!
相關(guān)文章
java中ArrayList和LinkedList的區(qū)別詳解
這篇文章主要介紹了java中ArrayList和LinkedList的區(qū)別詳解,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01Java?synchronized底層實現(xiàn)原理以及鎖優(yōu)化
Synchronized是Java中解決并發(fā)問題的一種最常用的方法,也是最簡單的一種方法,下面這篇文章主要給大家介紹了關(guān)于Java?synchronized底層實現(xiàn)原理以及鎖優(yōu)化的相關(guān)資料,需要的朋友可以參考下2022-02-02IntelliJ IDEA2019實現(xiàn)Web項目創(chuàng)建示例
這篇文章主要介紹了IntelliJ IDEA2019實現(xiàn)Web項目創(chuàng)建示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04淺談SpringBoot 中關(guān)于自定義異常處理的套路
這篇文章主要介紹了淺談SpringBoot 中關(guān)于自定義異常處理的套路,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04