Spring事务管理分为声明式事务管理和编程式事务管理,声明式事务管理又分为xml和注解两种配置方式。应该优先选择声明式事务,因为声明式事务对程序代码的影响最小,因此最符合非侵入式轻量级容器的理想 。只有在进行少量事务操作时,才应该选择编程式事务管理的方式。
声明式事务管理
xml配置方式
Spring配置文件:
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 导入数据库配置文件 --> <context:property-placeholder location="config.properties"/> <!-- 配置数据源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName"><value>${jdbc_driverClassName}</value></property> <property name="url"><value>${jdbc_url}</value></property> <property name="username"><value>${jdbc_username}</value></property> <property name="password"><value>${jdbc_password}</value></property> <!-- ... --> </bean> <!-- 配置jdbcTemplate,使用jdbcTemplate操作数据库 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userService" class="com.springdemo.tx.UserService"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <!-- 配置事务管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- xml方式的配置声明式事务 start--> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.springdemo.tx.UserService.*(..))"/> </aop:config> <!-- xml方式的配置声明式事务 end--> </beans>
config.properties:
jdbc_driverClassName=com.mysql.jdbc.Driver jdbc_url=jdbc:mysql://192.168.1.77:3306/testdb?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true jdbc_username=root jdbc_password=root
UserService.java:
public class UserService { private JdbcTemplate jdbcTemplate; public void addUser(String name, int age){ jdbcTemplate.update("insert into test007 (name,age) values (name,age)", name, age); } public void updateUserName(String name, int id){ jdbcTemplate.update("update test007 set name=? where id=?", name, id); } public void updateUserAge(int age, int id){ jdbcTemplate.update("update test007 set age=? where id=?", age, id); } public void updateUser(String name, int age, int id){ updateUserName(name, id); //模拟异常 Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常"); updateUserAge(age, id); } public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } }
main方法:
public static void main(String[] args) { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml"); UserService userService = (UserService) ac.getBean("userService"); userService.updateUser("小王", 18, 1); }
使用注解方式
Spring配置文件中添加:
<!-- 开启注解配置 --> <tx:annotation-driven transaction-manager="txManager"/>
然后在需要事务管理的方法上添加@Transactional注解
@Transactional public void updateUser(String name, int age, int id){ updateUserName(name, id); //模拟异常 Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常"); updateUserAge(age, id); }
注意:注解方式和xml方式可以二选一,也可以结合使用,两者没有依赖关系。
异常捕获和回滚
异常捕获会导致事务机制失效,继而不会触发回滚。
可以调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()手动回滚。
@Transactional public void updateUser(String name, int age, int id){ try{ updateUserName(name, id); //模拟异常 Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常"); updateUserAge(age, id); }catch(NumberFormatException ex){ //手动回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); ex.printStackTrace(); } }
非RuntimeException时回滚
Spring事务管理机制默认只在抛出RuntimeException时才会触发回滚,可以设置rollbackFor属性来指定其他类型的异常也能回滚。
//rollbackFor指定抛出Exception类型异常时回滚 @Transactional(rollbackFor=Exception.class) public void updateUser(String name, int age, int id) throws Exception{ updateUserName(name, id); if(id == 1){ throw new Exception("Id为1的用户不可修改"); } updateUserAge(age, id); }
编程式事务管理
修改Spring配置文件:
<bean id="userService" class="com.springdemo.tx.UserService"> <property name="jdbcTemplate" ref="jdbcTemplate"/> <property name="transactionTemplate" ref="transactionTemplate"/> </bean> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="txManager"/> </bean> <!-- 注释声明式事务管理配置 --> <!-- <tx:annotation-driven transaction-manager="txManager"/> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.springdemo.tx.UserService.*(..))"/> </aop:config> -->
修改UserService:
private TransactionTemplate transactionTemplate; public void updateUser(final String name, final int age, final int id){ transactionTemplate.execute(new TransactionCallbackWithoutResult() { protected void doInTransactionWithoutResult(TransactionStatus status) { updateUserName(name, id); //模拟异常 Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常"); updateUserAge(age, id); } }); } public TransactionTemplate getTransactionTemplate() { return transactionTemplate; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; }
来源:https://www.cnblogs.com/seve/p/11172223.html