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 |
不容许 |
不容许 |
不容许 |
不容许 |
不容许 |
默认状况下,当发生运行异常时,事务将被回滚,发生检查型异常时,既不回滚也不提交,控制权交给外层调用。因此,带负号的异常设置仅对检查型异常有意义。