声明式事务(配置文件定义切面)
dao
package com.ffcs.wlan.dao;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class RainDao {
@Resource
private JdbcTemplate jdbcTemplate;
private Logger log = Logger.getLogger(RainDao.class);
public void update1() {
log.info("begin update1");
String sql= "UPDATE t_weak_password SET USER_ACCOUNT='ttt' where PWDSTR='111111'";
int updateCount = jdbcTemplate.update(sql);
log.info("updayte1 count:" + updateCount);
log.info("end update1");
}
/**
* dao模拟一个异常,异常必须要抛出去。如果不抛出去 外面的AOP不能捕获异常,事务不会回滚
* @throws Exception
*/
public void update2() throws Exception {
log.info("begin update2");
try {
String sql= "UPDATE1 t_weak_password SET USER_ACCOUNT='ooo' where PWDSTR='222222'";
int updateCount = jdbcTemplate.update(sql);
log.info("updayte2 count:" + updateCount);
} catch (Exception e) {
log.error(e.getMessage());
throw e;
}
}
public void select() {
String sql= "select USER_ACCOUNT from t_weak_password";
List<Map<String, Object>> updateCount = jdbcTemplate.queryForList(sql);
for (Map<String, Object> map : updateCount)
log.info(map.get("USER_ACCOUNT"));
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
service
package com.ffcs.wlan.service;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.ffcs.wlan.dao.RainDao;
@Service("rainService")
public class RainService {
@Resource
private RainDao dao;
/**
* 要把异常抛出去。如果使用trycatch 捕获了异常,spring的AOP就无法捕获异常,事务就无法生效
* @throws Exception
*/
public void updateTest() throws Exception {
dao.update1();
dao.update2();
dao.select();
}
public void setDao(RainDao dao) {
this.dao = dao;
}
}
test
package com.ffcs.wlan_jt;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ffcs.wlan.service.RainService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:spring.xml","classpath*:spring-redis.xml","classpath*:spring-jdbc.xml" })
public class RainTest extends AbstractJUnit4SpringContextTests {
@Resource
private RainService servies;
@Test
public void update(){
try {
servies.updateTest();
} catch (Exception e) {
logger.error(e.getMessage());
}
}
public void setServies(RainService servies) {
this.servies = servies;
}
}
配置文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_username}" />
<property name="password" value="${jdbc_password}" />
</bean>
<!-- 定义事务管理 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 注解方式配置事物 在service中@Transactional -->
<!--<tx:annotation-driven transaction-manager="transactionManager" /> -->
<!-- 拦截器方式配置事物-->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="append*" propagation="REQUIRED" />
<tx:method name="init" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="delAndInit" propagation="REQUIRED" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="load*" propagation="REQUIRED" read-only="true" />
<tx:method name="search*" propagation="REQUIRED"
read-only="true" />
<tx:method name="datagrid*" propagation="REQUIRED"
read-only="true" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- 第一个*代表所有的返回值类型 ,第二个*代表所有的类,第三个*代表类所有方法,..代表所有的参数,(*sy.service..*Impl.*(..)) 包及子包" -->
<aop:config>
<aop:pointcut id="transactionPointcut"
expression="execution(* com.ffcs.wlan.service.*.*(..))" />
<aop:advisor pointcut-ref="transactionPointcut"
advice-ref="transactionAdvice" />
</aop:config>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
编程式事务
在配置文件中开启注解支持
<!-- 用注解来实现事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
1 @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
2 默认情况下,一个有事务方法, 遇到RuntiomeException 时会回滚 . 遇到 Checked Exception(受检查的异常) 是不会回滚 的. 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .
proxy-target-class:表示将使用的代码机制,默认false表示使用JDK代理,如果为true将使用CGLIB
- 建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是因为如果使用JDK代理机制是没问题,因为其使用基于接口的代理;而使用使用CGLIB代理机制时就会遇到问题,因为其使用基于类的代理而不是接口,这是因为接口上的@Transactional注解是“不能继承的”;
混合事务管理最大问题在于如果我们使用第三方ORM框架,如Hibernate,会遇到一级及二级缓存问题,尤其是二级缓存可能造成如使用Spring JDBC和Hibernate查询出来的数据不一致等。
因此不建议使用这种混合使用和混合事务管理。
propagation:事务传播属性
isolation:事务隔离级别
http://jinnianshilongnian.iteye.com/blog/1442376
http://jinnianshilongnian.iteye.com/blog/1441271