Spring的早期版本用戶必須經過TransactionProxyFactoryBean代理對須要事務管理的業務類進行代理,便於實施事務功能的加強。
讓咱們先看代碼吧!
業務層代碼:
java
public interface UserScoreService { public UserScore getUserSocore(String userNo); public void addUserScore(UserScore us); public int getUsableScore(String userNo); }
public class UserScoreServiceImpl implements UserScoreService { private UserScoreRepository userScoreRepository; public void setUserScoreRepository(UserScoreRepository userScoreRepository) { this.userScoreRepository = userScoreRepository; } @Override public UserScore getUserSocore(String userNo) { return userScoreRepository.getUserSocore(userNo); } @Override public void addUserScore(UserScore us) { userScoreRepository.addUserScore(us); } @Override public int getUsableScore(String userNo) { return userScoreRepository.getUsableScore(userNo); } }
持久層代碼: mysql
public interface UserScoreRepository { public UserScore getUserSocore(String userNo); public void addUserScore(UserScore us); public int getUsableScore(String userNo); }
public class UserScoreRepositoryImpl implements UserScoreRepository { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public UserScore getUserSocore(String userNo) { final UserScore us = new UserScore(); StringBuffer sql = new StringBuffer(); sql.append("select * from userscore where userNo = ?"); jdbcTemplate.query(sql.toString(), new Object[]{userNo}, new RowCallbackHandler() { @Override public void processRow(ResultSet rs) throws SQLException { us.setId(rs.getInt("id")); us.setHonourScore(rs.getInt("honourScore")); us.setUsableScore(rs.getInt("usableScore")); us.setUserName(rs.getString("userName")); us.setUserNo(rs.getString("userNo")); } }); return us; } @Override public void addUserScore(UserScore us) { } @Override public int getUsableScore(String userNo) { return 0; } }
Spring配置文件: web
<!-- 定義一個數據源 --> <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/spring_test" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> <!-- 定義JdbcTemplate的Bean --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSource"> </bean> <bean id="userScoreRepository_jdbc" class="net.hingyi.springDemo.transaction.repository.UserScoreRepositoryImpl" p:jdbcTemplate-ref="jdbcTemplate" /> <!-- 聲明事務管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 須要實施事務加強的目標業務Bean --> <bean id="userScoreTarget" class="net.hingyi.springDemo.transaction.service.UserScoreServiceImpl" p:userScoreRepository-ref="userScoreRepository_jdbc" /> <!-- 使用事務代理工廠類爲目標業務Bean提供事務加強 --> <!-- p:transactionManager-ref="txManager" 指定事務管理器 --> <!-- p:target-ref="userScoreTarget" 指定目標業務Bean --> <bean id="userScore" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" p:transactionManager-ref="txManager" p:target-ref="userScoreTarget"> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <!-- 只讀事務 --> <prop key="*">PROPAGATION_REQUIRED</prop> <!-- 可寫事務 --> </props> </property> </bean>
web.xml配置
spring
<context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j.properties</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
異常回滾/提交規則
上面spring配置中的<prop>內的值爲事務屬性信息,匹配格式爲: sql
PROPAGATION 數據庫 (傳播行爲) apache |
, tomcat |
ISOLATION app (隔離級別(可選)) ide |
, |
readOnly (是否爲只讀事務(可選)) |
, |
-Exceptions (發生這些異常時回滾事務(可選))
|
, |
+Exceptions (發生這些異常時照樣提交事務(可選)) |
Spring事務的傳播類型
Spring在TransactionProxyFactory接口中規定了7種類型的事務傳播行爲,它們規定了事務方法和事務發生嵌套調用時候是怎麼傳播的。如:
事務傳播行爲類型 |
說明 |
PROPAGATION_REQUIRED |
若是當前沒有事務,就新建一個事務;若是已經存在一個事務,加入到這個事務中。(這個是最多見的選擇) |
PROPAGATION_SUPPORTS |
支持當前事務。若是當前沒有事務,就以非事務方式執行 |
PROPAGATION_MANDATORY |
使用當前的事務。若是當前沒有事務,就拋出異常 |
PROPAGATION_REQUIRES_NEW |
新建事務。若是當前存在事務,就把當前事務掛起 |
PROPAGATION_NOT_SUPPORTED |
以非事務的方式執行操做。若是當前存在事務,就把當前事務掛起 |
PROPAGATION_NEVER |
以非事務方式執行。若是當前存在事務,則拋出異常 |
PROPAGATION_NESTED |
若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行與 PROPAGATION_REQUIRED相似的操做 |
隔離級別
隔離級別是可選的,默認的爲ISOLATION_DEFAULT,表示數據庫的默認隔離級別。隔離級別的值以下:
隔離級別 |
髒讀 |
不可重複讀 |
幻象讀 |
第一類丟失更新 |
第二類丟失更新 |
ISOLATION_READ_UNCOMMITED |
容許 |
容許 |
容許 |
不容許 |
容許 |
ISOLATION_READ_COMMITED |
不容許 |
容許 |
容許 |
不容許 |
容許 |
ISOLATION_REPEATABLE_READ |
不容許 |
不容許 |
容許 |
不容許 |
不容許 |
ISOLATION_SERIALIZABLE |
不容許 |
不容許 |
不容許 |
不容許 |
不容許 |
默認狀況下,當發生運行異常時,事務將被回滾,發生檢查型異常時,既不回滾也不提交,控制權交給外層調用。因此,帶負號的異常設置僅對檢查型異常有意義。