文章转至http://zhou137520.iteye.com/blog/1675199
Spring对事务的解决办法其实分为2种:编程式实现事务,AOP配置声明式解决方案。
http://jinnianshilongnian.iteye.com/blog/1496953Spring框架支持事务管理的核心是事务管理器抽象,对于不同的数据访问框架(如Hibernate)通过实现策略接口PlatformTransactionManager,从而能支持各种数据访问框架的事务管理,PlatformTransactionManager接口定义如下:
public interface PlatformTransactionManager { //返回一个已经激活的事务或创建一个新的事务 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
Spring声明式事务
在日常开发中,用的最多的就是声明式事务了,下面将介绍SpringJdbc的声明式事务的配置方法:
<context:component-scan base-package="com.chou.spring.jdbc"/> <!-- 配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!-- Connection Info --> <property name="driverClass" value="${db.driverClass}" /> <property name="jdbcUrl" value="${db.url}" /> <property name="user" value="${db.username}" /> <property name="password" value="${db.password}" /> <!-- Connection Pooling Info --> <property name="initialPoolSize" value="1" /> <property name="minPoolSize" value="1" /> <property name="maxPoolSize" value="15" /> <property name="maxIdleTime" value="1800" /> <property name="maxStatements" value="0" /> </bean> <bean id="jdbcTemplateDao" class="com.chou.spring.jdbc.dao.JdbcTemplateDao" > <property name="dataSource" ref="dataSource" /> </bean> <!-- JDBC事务管理器 --> <bean id="jdbctTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:advice id="txAdvice" transaction-manager="jdbctTxManager"> <tx:attributes> <tx:method name="domain*"/> </tx:attributes> </tx:advice> <aop:config proxy-target-class="true"> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.chou.spring.jdbc.service.JdbcTemplateService.*(..))"/> </aop:config>
public class JdbcTemplateDao extends JdbcDaoSupport{ public void save() { String insertSql = "insert into tab_item values(?,?,?)"; Assert.isTrue(getJdbcTemplate().update(insertSql, new Object[]{6, "HP", "PT540"}) == 1, "插入失败"); } public void delete() { String deleteSql = "delete tab_item where id = ?"; Assert.isTrue(getJdbcTemplate().update(deleteSql, new Object[]{6}) == 1, "删除失败"); } public void update() { String updateSql = "update tab_item set itemno = ?, itemname = ? where id = ?"; Assert.isTrue(getJdbcTemplate().update(updateSql, new Object[]{"HP", "PT555", 6}) == 1, "修改失败"); } }
/** * * @author Chou * @since 2012-9-9 * 把事务定义在Service层是为了避免报错: * All calls to this method via a proxy will be routed directly to the proxy. * 这是是事务转移问题,你如果在控制层加入事务就不会有提示了,也没有警告, * 一般很多人在final DAO里加入事务那是有警告的, * 如果配置文件定义了AOP获取代理对象是proxy-target-class="true"即采用CGLIB方式 * 而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来, * 通过修改其字节码生成子类并继承你写的类,然后在你的基础上加事物管理, * 而JdbcDaoSupport中的setDataSource是final的他继承不了 * 当然你可以无视它,也没有问题。 */ @Service public class JdbcTemplateService { @Autowired private JdbcTemplateDao jdbcTemplateDao; public void domain(){ jdbcTemplateDao.save(); int i = 2/0;//这里出错了,事务就会回滚,之前的save就无效了 jdbcTemplateDao.update(); jdbcTemplateDao.delete(); } } //main方法 String[] configLocations = new String[] {"applicationContext.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations); JdbcTemplateService j = ctx.getBean(JdbcTemplateService.class); j.domain();
<tx:advice id="……" transaction-manager="……"> <tx:attributes> <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" timeout="-1" read-only="true" no-rollback-for="" rollback-for="java.lang.Exception"/> </tx:attributes> </tx:advice> <!-- 最常用的配置 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="merge*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="put*" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> <tx:method name="count*" propagation="SUPPORTS" read-only="true" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="list*" propagation="SUPPORTS" read-only="true" /> <tx:method name="*" propagation="SUPPORTS" read-only="true" /> <tx:method name="batchSaveOrUpdate" propagation="REQUIRES_NEW" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* cn.javass..service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /> </aop:config>
属性
|
类型
|
默认值
|
说明
|
propagation | Propagation枚举 | REQUIRED | 事务传播属性 |
isolation | isolation枚举 | DEFAULT(所用数据库默认级别) | 事务隔离级别 |
readOnly | boolean | false | 是否才用优化的只读事务 |
timeout | int | -1 | 超时(秒) |
rollbackFor | Class[] | {} | 需要回滚的异常类 |
rollbackForClassName | String[] | {} | 需要回滚的异常类名 |
noRollbackFor | Class[] | {} | 不需要回滚的异常类 |
noRollbackForClassName | String[] | {} | 不需要回滚的异常类名 |
<!-- 事务管理器配置 --> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
@Transactional//放在这里表示所有方法都加入事务管理 public class AnnotationUserServiceImpl implements IUserService { private IUserDao userDao; private IAddressService addressService; @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED) public void save(UserModel user) { userDao.save(user); user.getAddress().setUserId(user.getId()); addressService.save(user.getAddress()); } @Transactional(propagation=Propagation.REQUIRED, readOnly=true, isolation=Isolation.READ_COMMITTED) public int countAll() { return userDao.countAll(); } //setter... }