SpringMVC之application-context.xml,了解數據庫相關配置


上一篇SpringMVC之web.xml讓我們了解到配置一個web項目的時候,怎樣做基礎的DispatcherServlet相關配置。作為SpringMVC上手的第一步。而application-context.xml則讓我們了解到怎樣將數據庫信息載入到項目中,包括重要的作用庫連接信息、sqlSessionFactory、事務等關鍵因素。

①、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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <bean class="com.honzh.common.config.EncryptPropertyPlaceholderConfigurer">
         <property name="locations">
            <value>file:C:/properties/ymeng.properties</value>
        </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <!-- Connection Info -->
        <property name="driverClassName" value="${driver}" />
        <property name="url" value="${url}?useUnicode=true&amp;characterEncoding=utf8&amp;" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />

        <!-- Connection Pooling Info -->
        <property name="maxActive" value="${maxActive}" />
        <property name="maxIdle" value="${maxIdle}" />
        <property name="defaultAutoCommit" value="false" />
        <property name="timeBetweenEvictionRunsMillis" value="3600000"/>
        <property name="minEvictableIdleTimeMillis" value="3600000"/>

        <property name="testOnBorrow" value="true" />
        <property name="validationQuery">
            <value>select 1 from DUAL</value>
        </property>
    </bean>

    <!-- 創建SqlSessionFactory,同一時候指定數據源 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
    </bean>

        <!-- Mapper接口所在包名。Spring會自己主動查找其下的Mapper -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.honzh.biz.database.mapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>

    <!-- transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 可通過注解控制事務 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean id="springContextHolder" class="com.honzh.common.spring.SpringContextHolder" />
</beans> 

②、重點內容介紹

1、EncryptPropertyPlaceholderConfigurer

<bean class="com.honzh.common.config.EncryptPropertyPlaceholderConfigurer">
     <property name="locations">
           <value>file:C:/properties/ymeng.properties</value>
       </property>
</bean>

使用了file前綴引導spring從c盤固定的路徑載入數據庫連接信息。

剛看到這個類的時候,你或許會有一種似曾相識的感覺。沒錯,她繼承了PropertyPlaceholderConfigurer類。僅僅只是我為她加了一層神奇的色彩(Encrypt嘛),其作用呢,就是為了不直接在項目執行環境中暴露數據庫連接信息,比方說數據庫用戶名、密碼、URL等,這樣就等於系統多了一層的安全級別。個人認為還是非常實用的,所以我之前總結了一篇SpringMVC使用隱式jdbc連接信息

標題寫的是SpringMVC,相同適用於Spring,那么這里我就不再嘮叨了。

2、dataSource

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <!-- Connection Info -->
    <property name="driverClassName" value="${driver}" />
    <property name="url" value="${url}?useUnicode=true&amp;characterEncoding=utf8&amp;" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />

    <!-- Connection Pooling Info -->
    <property name="maxActive" value="${maxActive}" />
    <property name="maxIdle" value="${maxIdle}" />
    <property name="defaultAutoCommit" value="false" />
    <property name="timeBetweenEvictionRunsMillis" value="3600000"/>
    <property name="minEvictableIdleTimeMillis" value="3600000"/>

    <property name="testOnBorrow" value="true" />
    <property name="validationQuery">
        <value>select 1 from DUAL</value>
    </property>
</bean>

使用了dbcp的數據庫連接池。

DBCP(DataBase connection pool),數據庫連接池。

是 apache 上的一個 java 連接池項目,也是 tomcat 使用的連接池組件。

單獨使用dbcp須要2個包:commons-dbcp.jar,commons-pool.jar因為建立數據庫連接是一個非常耗時耗資源的行為。所以通過連接池預先同數據庫建立一些連接,放在內存中,應用程序須要建立數據庫連接時直接到連接池中申請一個即可。用完后再放回去。

  1. destroy-method=”close”的作用就是當數據庫連接不使用的時候,就把該連接又一次放到數據池中,方便下次使用調用.非常關鍵的一個元素。

  2. 關於數據庫連接信息URL、username等就不解釋了。

  3. 關於數據庫連接池信息我到如今還沒有搞得非常明確,之前也調查了非常多次,不見效果。無奈。。。。

  4. testOnBorrow、validationQuery:通過“select 1 from DUAL”查詢語句來驗證connection的有效性。網上還有非常多資源對這塊有專業的解釋,反正我是沒有看得太明確,之前也曾專門調查過這塊東西,如今也回憶不起來了,以后再碰到的時候再補充進來。

3、sqlSessionFactory

    <!-- 創建SqlSessionFactory。同一時候指定數據源 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
</bean>

sqlSessionFactory對於Spring以及mybatis來說就比較關鍵了,spring在建立sql連接使都會使用到這個。因為我的不專業性,所以關於更深入的解釋,我就不來了。反正對於我來說,這段配置就是為了和數據庫連接鏈接、創建事務管理。

創建sqlSessionFactory時,可能還須要為mybatis配置別名,那么此處改為例如以下格式:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"/>  
        <property name="dataSource" ref="dataSource" />
    </bean>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
       <typeAlias alias='Deals' type='com.honzh.biz.database.entity.Deals' />
    </typeAliases>
</configuration>

這樣在mapper的xml文件中就能夠使用Deals,而不再是com.honzh.biz.database.entity.Deals全名。

<resultMap type="Deals" id="BaseResultMap">

4、transactionManager、tx:annotation-driven

   <!-- transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
    <!-- 可通過注解控制事務 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

transactionManager就是為了開啟事務。

通過tx:annotation-driven就能夠直接在方法或者類上加“@transactional”來開啟事務回滾。關於這段,我也必須誠實的說,我僅僅停留在會用的基礎上。

5、springContextHolder

<bean id="springContextHolder" class="com.honzh.common.spring.SpringContextHolder" />

通過spring的IOC機制(依賴注入),配置springcontext的管理器,該類的詳細內容見例如以下:

package com.honzh.common.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/** * <strong>SpringContextHolder</strong><br> * Spring Context Holder<br> * <strong>Create on : 2011-12-31<br></strong> * <p> * <strong>Copyright (C) Ecointel Software Co.,Ltd.<br></strong> * <p> * @author peng.shi peng.shi@ecointel.com.cn<br> * @version <strong>Ecointel v1.0.0</strong><br> */
public class SpringContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHolder.applicationContext = applicationContext;
    }

    /** * 得到Spring 上下文環境 * @return */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    /** * 通過Spring Bean name 得到Bean * @param name bean 上下文定義名稱 */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }

    /** * 通過類型得到Bean * @param clazz * @return */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(Class<T> clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }

    private static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new IllegalStateException("applicaitonContext未注入,請在application-context.xml中定義SpringContextHolder");
        }
    }

}

如此,我們就能夠輕松的通過SpringContextHolder.getBean方法獲取相應的bean類。就不再通過new關鍵字來創建一個類了。當然該類必須有注解標識,比方說@Service、@Component等。

6、MapperScannerConfigurer

        <!-- Mapper接口所在包名,Spring會自己主動查找其下的Mapper -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.honzh.biz.database.mapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>

該段配置的目的就是掃描mapper接口。也就是你sql語句的地方。

當系統啟動執行時,spring會載入你的mapper類,然后檢查相應的sql語句是否正確。比方字段名是否匹配等等。若不匹配系統自然會報錯。另外特別注意的是basePackage的value值一定要正確,我就曾深受其害。

ps:
這里請注意。當mybatis-3.1.1-SNAPSHOT.jar的版本號為3.0以上時,這種配置就可能會引發這種錯誤

org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class ‘${driver}’

有同仁解釋了一下這個道理,見例如以下

在spring里使用org.mybatis.spring.mapper.MapperScannerConfigurer 進行自己主動掃描的時候,設置了sqlSessionFactory 的話。可能會導致PropertyPlaceholderConfigurer失效,也就是用${jdbc.username}這樣之類的表達式,將無法獲取到properties文件中的內容。

導致這一原因是因為,MapperScannerConigurer實際是在解析載入bean定義階段的。這個時候要是設置sqlSessionFactory的話,會導致提前初始化一些類。這個時候,PropertyPlaceholderConfigurer還沒來得及替換定義中的變量。導致把表達式當作字符串復制了。 但假設不設置sqlSessionFactory 屬性的話,就必須要保證sessionFactory在spring中名稱一定要是sqlSessionFactory ,否則就無法自己主動注入。

又或者直接定義 MapperFactoryBean ,再或者放棄自己主動代理接口方式。

那么此時的簡單解決的方法就是將xml改為例如以下格式:

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.honzh.biz.database.mapper" />
    </bean>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM