Java應用要連接數據庫需要先通過jdbc與數據庫之間產生connection,然后通過sql語句產生statment,再執行這個statment查詢的到ResultSet返回給應用,應用解析ResultSet獲得Java支持類型的結果。
這里存在以下幾個問題:
- 產生連接本身需要,而且這個延時比起常規的查詢操作來說是較高的,對於有響應時限的操作來說這是一個致命問題。
- 建立連接需要消耗數據庫資源,數據庫本身開放的連接數量是有限的,即使不斷的建立與關閉連接保證總數的穩定,也會極大消耗數據庫資源影響性能。而數據庫資源比起應用服務器來說又是非常寶貴的,數據庫的分流比應用要困難很多。
所以要避免這種情況就有了連接池。連接池有幾個基本屬性:初始連接數、最大連接數、最小空閑數、最大空閑數、最大等待毫秒數,分別假設為5 10 1 5 60。連接池可以想象為一個池子,先建立5個連接放入池子中。應用的一個線程需要與數據庫交互時,向連接池要一個連接,然后去執行,執行完后會將連接還給連接池。當並發量很高時,連接池內的連接會被取完,此時又有線程要連接,就會檢查是否達到了最大連接數,如果沒達到就會繼續新建連接,將連接交給線程。如果達到上限,則讓線程進行等待,知道有線程把連接還回來。
當連接池內的連接數超過了最大空閑數時,當這個連接被歸還連接池,它就會被強制關閉。而當連接池內的連接數小於最小空閑數時,連接池會自動去新建連接來補充到這個數量。為什么連接數量自己會變化呢?因為數據庫存在一個連接的等待時間,超過這個時間始終沒有活動的話,連接會被數據庫關閉,連接池會周期性的去探知所有連接是否存活,以管理連接的數量。
所謂持久層,是指將數據長期存儲到硬盤當中。因為在webapp開發中數據通過數據庫存儲到硬盤中,所以持久層可以簡單的認為就是負責對數據庫的增刪改查。用過Java原始jdbc的查詢的話都知道ResultSet要轉換成Java Bean中間的重復操作還是挺多的;要把一個List<T>轉換成SQL語句也挺麻煩的,持久層框架的好處之一就是省略掉這中間的重復操作,根據寫好的映射關系,直接完成數據庫與Java代碼之間交互。
常用的持久層框架有兩個:MyBatis和Hibernate。MyBatis最大的特點是SQL語句基本就是沒有任何封裝的原生SQL。缺點當然是開發起來工作量較大,同時不同數據庫之間的遷移性收到影響。優點是學習簡單,SQL自由性大,也就有更大的優化空間。畢竟正常情況下你能夠控制的東西越多,開發就會越復雜,但是性能極限會更高,當然這里的前提是開發者足夠資深,畢竟一般人寫的代碼不如編譯器優化出來的。
下面開始SSM框架下的這個M的搭建。首先,pom.xml里面引入相關的依賴,包括mybatis本身、Spring的支持插件、mysql驅動,以及連接池創建工具這里采用dbcp
<!--mysql數據庫驅動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <!-- 連接池創建 --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency>
然后配置數據源的話有兩種方式,一種是直接配置數據源,還有一種是基於容器的數據源比如tomcat下的jndi連接。
直接配置的話,在applicationContext.xml,即通過ContextLoaderListener監聽的配置文件里面添加如下:
<!-- 配置jdbc文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations" value="classpath:jdbc.properties" /> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <!-- 初始化連接大小 --> <property name="initialSize" value="${initialSize}" /> <!-- 連接池最大數量 --> <property name="maxActive" value="${maxActive}" /> <!-- 連接池最大空閑 --> <property name="maxIdle" value="${maxIdle}" /> <!-- 連接池最小空閑 --> <property name="minIdle" value="${minIdle}" /> <!-- 獲取連接最大等待時間 --> <property name="maxWait" value="${maxWait}" /> </bean> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自動掃描mapping.xml文件,**表示迭代查找 --> <property name="mapperLocations" value="classpath:com/web/**/*.xml" /> </bean> <!-- DAO接口所在包名,Spring會自動查找其下的類 ,包下的類需要使用@MapperScan注解,否則容器注入會失敗 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.web" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean> <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
這里采用外部讀入參數的方式加載用戶名信息,便於統一管理。resources目錄下添加jdbc.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8 username=root password=123456 initialSize=5 maxActive=10 maxIdle=5 minIdle=1 maxWait=60
然后添加dao層Bean層與對應的xml映射文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.web.dao.TestMapper"> <select id="getTest" resultType="com.web.bean.HelloBean"> select id,txt from test </select> </mapper>
package com.web.dao; import java.util.List; import org.mybatis.spring.annotation.MapperScan; import com.web.bean.HelloBean; @MapperScan public interface TestMapper { public List<HelloBean> getTest(); }
package com.web.bean; public class HelloBean { private String id; private String txt; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTxt() { return txt; } public void setTxt(String txt) { this.txt = txt; } }
全部添加完后,項目的路徑如下:
然后通過注入dao層類之后執行testMapper.getTest(),表與插入的測試數據可以參見我上一篇文章。結果下:
說明數據已經直接映射到了結果的bean上面。
第二種方法,就是利用tomcat來創建連接池,然后mybatis直接只用tomcat的數據源。先配置context.xml
<Resource name="jdbc/mybatis-jndi" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="root" password="123456" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/demo" />
然后在applicationContext.xml文件上添加jndi數據源,並修改mybatis使用的數據源java:comp/env/這里是固定字段,后面的jdbc/mybatis-jndi對應context里面配置的name屬性
<bean id="jndiDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>java:comp/env/jdbc/mybatis-jndi</value> </property> </bean> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- ref是使用的數據源 --> <property name="dataSource" ref="jndiDataSource" /> <!-- 自動掃描mapping.xml文件,**表示迭代查找 --> <property name="mapperLocations" value="classpath:com/web/**/*.xml" /> </bean>
MyBatis的集成至此完成。