在数据库操作中事务管理是一个重要的概念,例如银行转账。
Spring的事务管理简化了传统的数据库事务管理流程,提高了开发效率。
1.编程式事务管理
在代码中显示调用beginTransaction、commit、rollback 等与事务处理相关的方法,这就是编程式事务管理。当只有少数事务操作时,编程式事务管理才比较合适。
基于底层API的编程式事务管理
基于 TransactionTemplate 的编程式事务管理
2.声明式事务管理
Spring的声明式事务管理是通过AOP技术实现的事务管理,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或加入一个事务,在执行完目标方法之后根据执行情况提交或回滚事务。
声明式事务管理最大的优点是不需要通过编程的方式管理事务,因而不需要在业务逻辑代码中掺杂事务处理的代码,只需相关的事务规则声明便可以将事务规则应用到业务逻辑中。
使用声明式事务管理不仅因为其简单,更主要的是可以使得纯业务代码不被污染,极大的方便了后期的代码维护。
与编程式事务管理相比,唯一不足的是:最细粒度只能作用到方法级别,无法像编程式那样可以作用到代码块级别。(不过可以通过变通的方法解决,比如将需要进行事务处理的代码块独立为方法等)。
Spring的声明式事务管理通过两种方式实现:XML、@Transactional 注解
2.1 基于XML
创建Dao层
package com.statement.dao;
public interface TestDao {
public int save(String sql, Object param[]);
public int delete(String sql, Object param[]);
}
package com.statement.dao;
@Repository("TestDao")
public class TestDaoImpl implements TestDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int save(String sql, Object[] param) {
return jdbcTemplate.update(sql, param);
}
@Override
public int delete(String sql, Object[] param) {
return jdbcTemplate.update(sql, param);
}
}
创建Service层,依赖注入数据访问层。
package com.statement.service;
public interface TestService {
public int save(String sql, Object param[]);
public int delete(String sql, Object param[]);
}
package com.statement.service;
@Service("testService")
public class TestServiceImpl implements TestService {
@Autowired
private TestDao testDao;
@Override
public int save(String sql, Object[] param) {
return testDao.save(sql, param);
}
@Override
public int delete(String sql, Object[] param) {
return testDao.delete(sql, param);
}
}
创建Controller层,依赖注入Service层。
package com.statement.controller;
@Controller("statementController")
public class StatementController {
@Autowired
private TestService testService;
public String test() {
String message="";
String deleteSql="delete from user";
String saveSql="insert into user values(?,?,?)";
Object param[]={1,"chen","男"};
try{
testService.delete(deletSql, null);
testService.save(saveSql, param);
testService.save(saveSql, param);
}catch(Exception e) {
message="主键重复,事务回滚!";
e.printStackTrace();
}
return message;
}
}
创建配置文件
<!-- 为数据源添加事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 编写通知声明事务 -->
<tx:advice id="myAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- *表示任意方法 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 编写AOP,让Spring自动对目标对象生成代理,需要使用AspectJ的表达式 -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut expression="execution(* com.statement.sservice.*.*())" id="txPointCut"/>
<!-- 切面:将切入点与通知关联 -->
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPointCut"/>
</aop:config>
创建测试类
package com.statement.test;
public class Test {
public static void main(String[] args) {
ApplicationContext appCon=new ClassPathXmlApplicationContext("/com/statement/applicationContext.xml");
StatementController ct=(StatementController)appCon.getBean("statementController");
String result=ct.test();
System.out.println(result);
}
}
运行结果:
主键重复,事务回滚!
2.2 基于@Transactional
@Transactional 可以作用于接口、接口方法、类、类的方法上。
当作用于类上时,该类的所有public方法都将具有该类型的事务属性,同时也可以在方法级别使用该注解来覆盖类级别的定义。
Spring小组不建议在接口或接口方法上使用该注解,因为它只有在使用基于接口的代理时才会生效。
Dao、Service、Controller层相同,仅展示修改的部分代码。
配置文件
<!-- 为数据源添加事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 为事务管理器注册注解驱动器 -->
<tx:annotation-driven transaction-manager="txManager"/>
Spring MVC通常在Service层进行事务管理。
package com.statement.service;
@Service("testService")
@Transactional
// 指定这个类需要接受Spring的事务管理
// 只能针对public属性范围内的方法
public class TestServiceImpl implements TestService {