一、事務管理
1.1、回顧事務
- 事務:一組業務操作ABCD,要麼全部成功,要麼全部不成功。
- 特性:ACID 原子性:整體 一致性:完成 隔離性:併發 持久性:結果
- 隔離問題: 髒讀:一個事務讀到另一個事務沒有提交的數據。讀到的是假的數據。 不可重複讀:一個事務讀到另一個事務已提交的數據(update)。每次讀到的結果不一樣。 虛讀(幻讀):一個事務讀到另一個事務已提交的數據(insert)。讀到的數據變多了。
- 隔離級別: read uncommitted:讀未提交。存在3個問題。 read committed:讀已提交。解決髒讀,存在2個問題。 repeatable read:可重複讀。解決髒讀、不可重複讀,存在1個問題。 serializable:串行化。都解決,單事務。
- mysql 事務操作(簡單)
ABCD 是一個事務,有4個業務 Connection conn = null; try { // 1、獲得連接 conn = ...; // 2、開啓事務 conn.setAutoCommit(false); A B C D // 3、提交事務 conn.commit(); } catch() { // 4、回滾事務 conn.rollback(); }
- mysql 事務操作 => Savepoint
需求:AB(必須業務),CD(可選業務) Connection conn = null; Savepoint savepoint = null; // 定義保存點,記錄操作的當前位置,之後可以回滾到指定的位置。(可以回滾一部分) try { // 1、獲得連接 conn = ...; // 2、開啓事務 conn.setAutoCommit(false); A B savepoint = conn.setSavepoint(); C D // 3、提交事務 conn.commit(); } catch() { if (savepoint != null) { // 說明CD異常 // 回滾到CD之前 conn.rollback(savepoint); // 提交AB conn.commit(); } else { // 說明AB異常 // 回滾AB之前 conn.rollback(); } }
1.2、事務管理介紹
1.2.1、導入jar包
transaction --> tx
1.2.2、三個頂級接口
- PlatformTransactionManager 平臺事務管理器,
spring要管理事務,必須使用事務管理器
進行事務配置時,必須配置事務管理器。 - TransactionDefinition 事務詳情(事務定義、事務屬性),spring用於確定事務的具體詳情 例如:隔離級別、是否只讀、超時時間 等等。 進行事務配置時,必須配置事務詳情。spring將配置項封裝到該對象實例。
- TransactionStatus 事務狀態,spring用於記錄當前事務的運行狀態。 例如:是否有保存點,事務是否完成。 spring底層根據不同的運行狀態進行相應操作。跟我們沒有關係,我們只需要知道即可。
1.2.3、PlatformTransactionManager 事務管理器
- 導入jar包:我們需要的是平臺事務管理器的實現類
- 常見的事務管理器(必須記住) DataSourceTransactionManager jdbc開發時使用的事務管理器,採用JdbcTemplate HibernateTransactionManager hibernate開發時使用的事務管理器,整合hibernate時使用
- api詳解 TransactionStatus getTransaction(TransactionDefinition definition) “事務管理器”通過“事務詳情”,獲得“事務狀態”,從而管理事務。 void commit(TransactionStatus status) 根據狀態提交 void rollback(TransactionStatus status) 根據狀態回滾
1.2.4、TransactionStatus 事務狀態(瞭解)
1.2.5、TransactionDefinition 事務詳情
傳播行爲:在兩個業務之間如何共享事務
。每個值的詳解如下:
- PROPAGATION_REQUIRED , required , 必須【默認值】
- 支持當前事務,A如果有事務,B將使用該事務。
- 如果A沒有事務,B將創建一個新的事務。即B永遠處在事務中。
- PROPAGATION_SUPPORTS , supports , 支持
- 支持當前事務,A如果有事務,B將使用該事務。
- 如果A沒有事務,B將以非事務執行。
- PROPAGATION_MANDATORY , mandatory , 強制
- 支持當前事務,A如果有事務,B將使用該事務。
- 如果A沒有事務,B將拋出異常。
- PROPAGATION_REQUIRES_NEW , requires_new , 必須新的
- 如果A有事務,將A的事務掛起,B將創建一個新的事務。
- 如果A沒有事務,B將創建一個新的事務。
- PROPAGATION_NOT_SUPPORTED , not_supported , 不支持
- 如果A有事務,將A的事務掛起,B將以非事務執行。
- 如果A沒有事務,B將以非事務執行。
- PROPAGATION_NEVER , never , 從不
- 如果A有事務,B將拋出異常。
- 如果A沒有事務,B將以非事務執行。
- PROPAGATION_NESTED , nested , 嵌套
- A和B底層採用保存點機制,形成嵌套事務。
掌握:PROPAGATION_REQUIRED
、PROPAGATION_REQUIRES_NEW
、PROPAGATION_NESTED
1.3、事務案例:轉賬
1.3.1、搭建環境
1.3.1.1、創建表
CREATE DATABASE day35; USE day35; CREATE TABLE account( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), money INT ); INSERT INTO account(username, money) VALUES('jack', '10000'); INSERT INTO account(username, money) VALUES('rose', '10000');
1.3.1.2、導入jar包
- 核心:4 + 1
- aop:4 (aop 聯盟、spring aop、aspectj 規範、spring aspect)
- 數據庫:2(jdbc/tx)
- 驅動:mysql
- 連接池:c3p0
1.3.1.3、dao層
AccountDao.java
package com.itheima.dao; public interface AccountDao { /** * 匯款 * * @param outer * @param money */ public void out(String outer, Integer money); /** * 收款 * * @param inner * @param money */ public void in(String inner, Integer money); }
AccountDaoImpl.java
package com.itheima.dao.Impl; import org.springframework.jdbc.core.support.JdbcDaoSupport; import com.itheima.dao.AccountDao; public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void out(String outer, Integer money) { this.getJdbcTemplate().update("update account set money=money-? where username=?", money, outer); } @Override public void in(String inner, Integer money) { this.getJdbcTemplate().update("update account set money=money+? where username=?", money, inner); } }
1.3.1.4、service層 AccountService.java
package com.itheima.service; public interface AccountService { /** * 轉賬 * * @param outer * @param inner * @param money */ public void transfer(String outer, String inner, Integer money); }
AccountServiceImpl.java
package com.itheima.service.impl; import com.itheima.dao.AccountDao; import com.itheima.service.AccountService; public class AccountServiceImpl implements AccountService{ private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void transfer(String outer, String inner, Integer money) { accountDao.out(outer, money); // 斷電 // int i = 1/0; // 斷電會出現事務問題 accountDao.in(inner, money); } }
1.3.1.5、spring配置 爲了更加接近實際開發,配置文件的名稱改爲 applicationContext.xml,配置文件的位置放在 src目錄下。 applicationContext.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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- datasource --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day35"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!-- dao --> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- service --> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> </beans>
1.3.1.6、測試 TestApp.java
package com.itheima; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.itheima.service.AccountService; public class TestApp { @Test public void demo01() { String xmlPath = "applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); AccountService accountService = (AccountService) applicationContext.getBean("accountService"); accountService.transfer("jack", "rose", 100); } }
1.3.2、手動管理事務(瞭解)
- spring底層使用 TransactionTemplate事務模板 來進行操作的。
- 如何操作呢?步驟如下:
- 1、service層需要獲得 TransactionTemplate事務模板
- 2、spring就需要配置模板,並注入給service層
- 3、配置模板又需要注入事務管理器
- 4、配置事務管理器 DataSourceTransactionManager,又需要注入DataSource
1.3.2.1、修改service層代碼 AccountServiceImpl.java
package com.itheima.service.impl; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import com.itheima.dao.AccountDao; import com.itheima.service.AccountService; public class AccountServiceImpl implements AccountService{ private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } // 需要Spring注入模板 private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void transfer(final String outer, final String inner, final Integer money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus arg0) { accountDao.out(outer, money); // 斷電 int i = 1/0; // 斷電會出現事務問題 accountDao.in(inner, money); } }); } }
1.3.2.2、修改spring配置 applicationContext.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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- datasource --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day35"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!-- dao --> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- service --> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> <property name="transactionTemplate" ref="transactionTemplate"></property> </bean> <!-- 創建模板 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="txManager"></property> </bean> <!-- 配置事務管理器,注意:事務管理器需要事務,而事務從 連接Connection 獲得,而 連接Connection 從 連接池DataSource 處獲得 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> </beans>
1.3.3、使用工廠bean 生成代理:半自動
- spring提供了管理事務的代理工廠bean:TransactionProxyFactoryBean,操作步驟如下:
- 1、getBean() 獲得代理對象
- 2、在spring中配置一個代理
1.3.3.1、spring配置 applicationContext.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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- datasource --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day35"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!-- dao --> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- service --> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- service 的代理對象 4.1 proxyInterfaces 接口 4.2 target 目標類 4.3 transactionManager 事務管理器 4.4 transactionAttributes 事務屬性(事務詳情) prop.key :確定哪些方法使用當前事務配置 prop.text :用於配置事務詳情 格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception 傳播行爲 隔離級別 是否只讀 發生異常後仍然異常回滾事務 發生異常後仍然提交事務 例如: <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> 默認傳播行爲,和默認隔離級別 <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop> 只讀 <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.ArithmeticException</prop> 發生異常後仍然提交事務 --> <bean id="proxyAccountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="preInterceptors" value="com.itheima.service.AccountService"></property> <property name="target" ref="accountService"></property> <property name="transactionManager" ref="txManager"></property> <property name="transactionAttributes"> <props> <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> <!-- 默認傳播行爲,和默認隔離級別 --> </props> </property> </bean> <!-- 事務管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> </beans>
1.3.3.2、測試 TestApp.java
package com.itheima; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.itheima.service.AccountService; public class TestApp { @Test public void demo01() { String xmlPath = "applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); AccountService accountService = (AccountService) applicationContext.getBean("proxyAccountService"); accountService.transfer("jack", "rose", 100); } }
1.3.4、AOP 配置基於xml:全自動【掌握】
- 在spring xml 配置了aop,就會自動生成代理,之後就可以進行事務的管理,操作步驟如下:
- 1、配置管理器
- 2、配置事務詳情
- 3、配置aop
applicationContext.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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- datasource --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day35"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!-- dao --> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- service --> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 事務管理 --> <!-- 4.1 事務管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 4.2 事務詳情(事務通知),在 aop編程 篩選的基礎上,對ABC三個確定使用什麼樣的事務。例如:AC讀寫、B只讀 等等。 <tx:attributes> 用於配置事務詳情(屬性屬性) <tx:method name=""/> 詳情具體配置 propagation 傳播行爲 , REQUIRED:必須; REQUIRES_NEW:必須是新的 isolation 隔離級別 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/> </tx:attributes> </tx:advice> <!-- 4.3 AOP編程,例如:我們的目標類有ABCD(4個連接點),使用切入點表達式,確定需要增強的連接點,從而獲得切入點:ABC --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/> </aop:config> </beans>
1.3.5、AOP 配置基於註解:全自動【掌握】
- 操作步驟如下:
- 1、配置事務管理器,並將事務管理器交予spring管理
- 2、在目標類或目標方法添加註解即可 @Transactional
1.3.5.1、spring配置 applicationContext.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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- datasource --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day35"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!-- dao --> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- service --> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 事務管理 --> <!-- 4.1 事務管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 4.2 將事務管理器交予spring管理 * transaction-manager 配置事務管理器 * proxy-target-class true : 底層強制使用 cglib代理 false :默認的值爲false --> <tx:annotation-driven transaction-manager="txManager" proxy-target-class="false"/> </beans>
1.3.5.2、service 層 AccountServiceImpl.java
package com.itheima.service.impl; import org.springframework.transaction.annotation.Transactional; import com.itheima.dao.AccountDao; import com.itheima.service.AccountService; @Transactional public class AccountServiceImpl implements AccountService{ private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void transfer(String outer, String inner, Integer money) { accountDao.out(outer, money); // 斷電 // int i = 1/0; // 斷電會出現事務問題 accountDao.in(inner, money); } }
1.3.5.3、事務詳情配置
AccountServiceImpl.java
package com.itheima.service.impl; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.itheima.dao.AccountDao; import com.itheima.service.AccountService; @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.DEFAULT) public class AccountServiceImpl implements AccountService{ private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void transfer(String outer, String inner, Integer money) { accountDao.out(outer, money); // 斷電 // int i = 1/0; // 斷電會出現事務問題 accountDao.in(inner, money); } }
二、整合 Junit
步驟如下:
- 導入jar包
- 基本 :4 + 1
- 測試:spring-test…jar
- 1、讓Junit去通知spring加載配置文件
- 2、讓spring容器自動進行注入
TestApp.java
package com.itheima; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.itheima.service.AccountService; // 1、讓Junit去通知spring加載配置文件 // 2、讓spring容器自動進行注入 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class TestApp { @Autowired // 這是與junit整合,不需要在spring xml中進行配置掃描 private AccountService accountService; @Test public void demo01() { // String xmlPath = "applicationContext.xml"; // ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); // AccountService accountService = (AccountService) applicationContext.getBean("accountService"); accountService.transfer("jack", "rose", 100); } }
三、整合 web
步驟如下:
0、導入jar包 spring-web-3.2.0.RELEASE.jar 1、tomcat啓動時就加載配置文件的方案: 方案1:servlet --> init(ServletConfig) --> <load-on-startup>2 方案2:filter --> init(FilterConfig) --> web.xml註冊過濾器後,就會自動調用初始化 方案3:listener --> ServletContextListener --> servletContext對象監聽 方案4:spring提供了一個監聽器 ContextLoaderListener --> web.xml (<listener><listener-class>...) 如果只配置了監聽器,則默認加載xml文件的位置爲:/WEB-INF/applicationContext.xml 2、確定配置文件位置,通過系統初始化參數 ServletContext的初始化參數配,在web.xml文件中進行配置: <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
3、從servletContext作用域中獲得spring容器(瞭解即可,很少用)
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>day35_04_Spring_tx</display-name> <!-- 確定配置文件位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 配置spring 監聽器,用於加載xml配置文件 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.itheima.web.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/HelloServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> </web-app>
HelloServlet.java
package com.itheima.web.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.context.ApplicationContext; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import com.itheima.service.AccountService; public class HelloServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 從application作用域(ServletContext)獲得spring容器 // 方式1: 手動從作用域獲取 ApplicationContext applicationContext = (ApplicationContext) this.getServletContext() .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); // 方式2:通過工具類獲取 ApplicationContext apppApplicationContext2 = WebApplicationContextUtils .getWebApplicationContext(this.getServletContext()); // 轉賬操作 AccountService accountService = (AccountService) applicationContext.getBean("accountService"); accountService.transfer("jack", "rose", 1000); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
四、SSH 整合
4.1、jar包 整合
- struts :2.3.15.3
- spring : 3.2.0
- hibernate : 3.6.10
4.1.1、struts
- struts-2.3.15.3\apps\struts2-blank\WEB-INF\lib
- 模板技術,一般用於頁面的靜態化
- 1、jsp : *.jsp
- 2、freemarker :擴展名 :*.ftl
- 3、velocity :擴展名 :*.vm
4.1.2、spring
- 基礎 :4 + 1 :beans、core、context、expression + commons-logging (struts中已經導入了)
- AOP :aop聯盟、spring aop 、aspect規範、spring aspect
- db :jdbc、tx
- 測試 :test
- web開發 :spring web
- 驅動 :mysql
- 連接池 :c3p0
- spring整合hibernate :spring orm
4.1.3、hibernate
- %h%\hibernate3.jar 核心
- %h%\lib\required 必須
- %h%\lib\jpa jpa規範(java persistent api:java持久api) 用於hibernate註解開發(注意:Hibernate3中很少用,Hibernate4中推薦使用註解開發),例如:@Entity、@Id 等等。
- 整合log4j
- 導入 log4j…jar (struts中已經導入了)
- 整合(過渡):slf4j-log4j12-1.7.5.jar
- 二級緩存
- 核心:ehcache-1.5.0.jar
- 依賴:
- backport-util-concurrent-2.1.jar
- commons-logging (struts中已經導入了)
4.1.4、整合包
- spring 整合hibernate :spring orm
- struts 整合spring :struts2-spring-plugin-2.3.15.3.jar
- 刪除重複jar包:
4.2、spring整合hibernate:有hibernate.cfg.xml(最熟悉)
4.2.1、創建表
create table t_user( id int primary key auto_increment, username varchar(50), password varchar(32), age int );
4.2.2、PO 類(javabean)
User.java
package com.itheima.domain; public class User { /* * CREATE TABLE t_user( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), PASSWORD VARCHAR(32), age INT ); */ private Integer id; private String username; private String password; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
映射文件User.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.itheima.domain.User" table="t_user"> <id name="id"> <generator class="native"></generator> </id> <property name="username"></property> <property name="password"></property> <property name="age"></property> </class> </hibernate-mapping>
4.2.3、dao層
- spring提供了 HibernateTemplate對象,用於操作PO對象,類似於之前學習Hibernate時的 Session對象。
UserDao.java
package com.itheima.dao; import com.itheima.domain.User; public interface UserDao { /** * 保存 * * @param user */ public void save(User user); }
UserDaoImpl.java
package com.itheima.dao.impl; import org.springframework.orm.hibernate3.HibernateTemplate; import com.itheima.dao.UserDao; import com.itheima.domain.User; public class UserDaoImpl implements UserDao { // 需要Spring注入模板 private HibernateTemplate hibernateTemplate; public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; } @Override public void save(User user) { this.hibernateTemplate.save(user); } }
4.2.4、service層
UserService.java
package com.itheima.service; import com.itheima.domain.User; public interface UserService { /** * 註冊 * * @param user */ public void register(User user); }
UserServiceImpl.java
package com.itheima.service.impl; import com.itheima.dao.UserDao; import com.itheima.domain.User; import com.itheima.service.UserService; public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void register(User user) { userDao.save(user); } }
4.2.5、Hibernate的配置文件 hibernate.cfg.xml
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 1、基本四項 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost/day35</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <!-- 2、配置方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <!-- 3、sql語句 --> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <!-- 4、自動生成表結構(一般沒用,因爲真正的開發中是先建模,然後通過工具自動生成表結構、SQL語句 等) --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 5、本地線程綁定(用處不大,因爲事務我們交給Spring管理了) --> <property name="hibernate.current_session_context_class">thread</property> <!-- 6、導入映射文件 --> <mapping resource="com/itheima/domain/User.hbm.xml"/> </session-factory> </hibernate-configuration>
4.2.6、Spring的配置文件 applicationContext.xml
applicationContext.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1、加載hibenrate.cfg.xml,獲得 SessionFactory(小結:jdbc開發需要數據源DataSource,hibernate開發需要SessionFactory) * configLocation 確定配置文件位置 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> </bean> <!-- 2、先創建模板 * 需要Spring注入模板,該底層使用的就是session,而session是由SessionFactory獲得的 --> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 3、dao --> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"> <property name="hibernateTemplate" ref="hibernateTemplate"></property> </bean> <!-- 4、service --> <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> <!-- 5、事務管理 5.1、事務管理器 :HibernateTransactionManager --> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" > <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 5.2、事務詳情 ,給ABC進行具體的事務設置 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="register"/> </tx:attributes> </tx:advice> <!-- 5.3、AOP編程,從 ABCD 業務中 篩選出 ABC --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/> </aop:config> </beans>
4.2.7、測試
TestApp.java
package com.itheima; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.itheima.domain.User; import com.itheima.service.UserService; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class TestApp { @Autowired private UserService userService; @Test public void demo01(){ User user = new User(); user.setUsername("bruce"); user.setPassword("123456"); user.setAge(26); userService.register(user); } }
4.3、spring整合hibernate:沒有hibernate.cfg.xml【最常用】
- 刪除hibernate.cfg.xml文件,但需要保存文件內容,將其配置到spring中
- 修改dao層,繼承HibernateDaoSupport,spring中刪除模板,給dao注入SessionFactory
applicationContext.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.1、加載properties文件 --> <!-- 1.2、配置數據源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///day35"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!-- 1.3、配置 LocalSessionFactoryBean,獲得SessionFactory * configLocation確定配置文件位置 <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> 1)dataSource 數據源 2)hibernateProperties hibernate其他配置項 3)導入映射文件 mappingLocations ,確定映射文件位置,需要加“classpath:”。支持通配符 【常使用】 <property name="mappingLocations" value="classpath:com/itheima/domain/User.hbm.xml"></property> 或者 <property name="mappingLocations" value="classpath:com/itheima/domain/*.hbm.xml"></property> mappingResources ,加載指定的映射文件,默認從src下開始,不需要加“classpath:” 。不支持通配符* <property name="mappingResources" value="com/itheima/domain/User.hbm.xml"></property> mappingDirectoryLocations ,加載指定目錄下的,所有配置文件 <property name="mappingDirectoryLocations" value="classpath:com/itheima/domain/"></property> mappingJarLocations ,從jar包中獲得映射文件 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.current_session_context_class">thread</prop> </props> </property> <property name="mappingLocations" value="classpath:com/itheima/domain/*.hbm.xml"></property> </bean> <!-- 3、dao spring中刪除模板,給dao注入SessionFactory--> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 4、service --> <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> <!-- 5 、事務管理 5.1、 事務管理器 :HibernateTransactionManager --> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" > <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 5.2 、事務詳情 ,給ABC進行具體的事務設置 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="register"/> </tx:attributes> </tx:advice> <!-- 5.3、AOP編程,從 ABCD 業務中 篩選出 ABC --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/> </aop:config> </beans>
UserDaoImpl.java
package com.itheima.dao.impl; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import com.itheima.dao.UserDao; import com.itheima.domain.User; // 底層需要SessionFactory,會自動創建HibernateTemplate模板 public class UserDaoImpl extends HibernateDaoSupport implements UserDao { @Override public void save(User user) { this.getHibernateTemplate().save(user); } }
4.4、struts整合spring:由spring去創建action
操作步驟如下:
- 編寫action類,並將其配置給spring,由spring去創建action,並使spring注入service
- 編寫struts.xml
- 編寫表單jsp頁面
- web.xml 配置
- 確定Spring xml配置文件位置 contextConfigLocation
- 配置spring 的監聽器 ContextLoaderListener
- 配置struts 的前端控制器 StrutsPrepareAndExecuteFilter
4.4.1、action類
UserAction.java
package com.itheima.web.action; import com.itheima.domain.User; import com.itheima.service.UserService; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class UserAction extends ActionSupport implements ModelDriven<User> { // 1、封裝數據 private User user = new User(); @Override public User getModel() { return user; } // 2、service private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } /** * 註冊功能 * * @return */ public String register() { userService.register(user); return "success"; } }
4.4.2、spring配置
applicationContext.xml
...... <!-- 6、配置action,並配置多例 --> <bean id="userAction" class="com.itheima.web.action.UserAction" scope="prototype"> <property name="userService" ref="userService"></property> </bean> ......
4.4.3、struts配置
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- 開發模式 --> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <!-- 底層自動從spring容器中通過名稱獲得內容, getBean("userAction") --> <action name="userAction_*" class="userAction" method="{1}"> <result name="success">/message.jsp</result> </action> </package> </struts>
4.4.4、jsp表單
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="${pageContext.request.contextPath}/userAction_register" method="post"> 用戶名:<input type="text" name="username"/><br/> 密碼:<input type="password" name="password"/><br/> 年齡:<input type="text" name="age"/><br/> <input type="submit" /> </form> </body> </html>
4.4.5、配置web.xml
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <!-- 1、確定Spring xml的位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 2、spring 的監聽器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 3、struts 的前端控制器 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
4.5、struts整合spring:由struts去創建action【最常用】
操作步驟如下:
- 刪除spring的action配置
- struts的< action class="全限定類名">
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- 開發模式 --> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <!-- 底層自動從spring容器中通過名稱獲得內容, getBean("userAction") --> <action name="userAction_*" class="com.itheima.web.action.UserAction" method="{1}"> <result name="success">/message.jsp</result> </action> </package> </struts>
- 要求:在Action類中,必須提供service名稱與spring配置文件一致。(如果名稱一致,將自動注入)
- 1、struts 的配置文件
- default.properties ,常量配置文件
- struts-default.xml ,默認核心配置文件
- struts-plugins.xml ,插件配置文件
- struts.xml ,自定義核心配置文件
- 常量的使用時,後面配置項,將覆蓋前面的。
- 2、default.properties ,此配置文件中確定了按照【名稱】自動注入,如下圖所示:
- 位置:struts2-core-2.3.15.3.jar/org/apache/struts2/default.properties
- 3、struts-plugins.xml ,struts整合spring
打開struts-plugins.xml文件後,有如下一句代碼:
< constant name="struts.objectFactory" value="spring" /> 該配置說明:struts的action將由spring創建
綜上所述:之後的action由spring創建,並按照名稱自動注入
。