Spring事务管理
springMVC已经越来越流行了。以下是对spring事务的一些个人总结。我们先了解下事务:数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。
那么在spring框架中怎么使用尼?
1、dataSource,jdbcTemplate配置(默认已经了解spring)
<!-- 配置jdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置数据源 --> <!-- 以dataSource方式使用proxool连接池 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" init-method="init" destroy-method="close"> <property name="name" value="${jdbc.username}" /> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="initialSize" value="${ds.initialSize}" /> <property name="minIdle" value="${ds.minIdle}" /> <property name="maxActive" value="${ds.maxActive}" /> <property name="maxWait" value="${ds.maxWait}" /> <property name="timeBetweenEvictionRunsMillis" value="${ds.timeBetweenEvictionRunsMillis}" /> <property name="validationQuery" value="SELECT 'x' FROM dual" /> <property name="connectionProperties" value="oracle.jdbc.ReadTimeout=${oracle.jdbc.ReadTimeout};oracle.net.CONNECT_TIMEOUT=${oracle.net.CONNECT_TIMEOUT}" /> </bean>
为了方便修改,采取配置文件的形式。
# 数据库类型设置(oracle) ds.dialect=oracle # Oracle数据库 jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl jdbc.driver=oracle.jdbc.driver.OracleDriver jdbc.username=dreamer jdbc.password=123qwe # SQL执行时间超过一定时间则记录为慢SQL ds.slowSqlMillis=3000 # 慢SQL统计日志输出 ds.logSlowSql=false # 合并SQL统计 ds.mergeSql=false # 初始化时建立物理连接的个数 ds.initialSize=1 # 最小连接数 ds.minIdle=1 # 允许最大连接数,超过了这个连接,再有请求时,就排在队列中等候,最大的等待请求数由maximum-new-connections决定 ds.maxActive=20 # 获取连接时最大等待时间 ds.maxWait=5000 # 检测需要关闭的空闲连接的间隔时间, 单位是毫秒 ds.timeBetweenEvictionRunsMillis=120000 #oracle jdbc驱动socket超时 oracle.jdbc.ReadTimeout=600000 #oracle jdbc建立新连接超时时间 oracle.net.CONNECT_TIMEOUT=6000
然后就是如果简单的操作数据库了。示例代码
public class JdbcDemo { @Autowired public JdbcTemplate jdbcTemplate; public void callP(){ //调用存储过程 jdbcTemplate.execute("{}", new CallableStatementCallback<String>() { @Override public String doInCallableStatement(CallableStatement stat) throws SQLException, DataAccessException { //填参数 stat.setString(0, "hello"); ResultSet rs = stat.executeQuery(); while( rs.next()){ rs.getString(0); //....取值 } return null; } }); } public void query(){ //查询 jdbcTemplate.query("sql", new RowMapper<Object>(){ @Override public Object mapRow(ResultSet rs, int arg1) throws SQLException { rs.getString(0); //..... return null; }}); } }
上面就是spring操作数据库了。此时就涉及到事务管理。如果使用spring事务管理尼。我们可以通过依赖注入@Transactional来使用提醒两个注意点:
1.只有通过spring方式实例化才有事务。通过new方式实例化将不包含事务
2.当调用的第一个方法有事务时,里面调用的其他方法也将包含在同一事务里面,反之如果第一个方法没有配置事务,方法内部平级调用方法(此方法配置了事务)。事务也将无效。
public class Test { @Transactional public void delData(){ //有事务 delTabA(); //本身配置事务无效,事务类型与delData()一致 delTabB(); } public void delTabA(){ } @Transactional(propagation=Propagation.REQUIRES_NEW) public void delTabB(){ } } class TestDemo{ @Autowired private Test test; public void test() { //有事务 test.delData(); Test test2 = new Test(); //无事务 test2.delData(); } }
3.当方法中抛出异常时,如果声明了抛出异常,事务是不回滚的。如果抛出异常时未检查的。事务将会回滚。
如果需要回滚需要增加配置@Transactional(rollbackFor=Exception.class)指定异常,可同时配置多个异常
import org.springframework.transaction.annotation.Transactional; public class Test2 { //出现异常将不会回滚 @Transactional public void test ()throws Exception{ throw new Exception(); } //将会回滚 @Transactional(rollbackFor=Exception.class) public void test2()throws Exception{ throw new Exception(); } //将会回滚 @Transactional public void test3(){ throw new RuntimeException("例外"); } }
通过依赖注入可以选着注入的事务类型 @Transactional(propagation=Propagation.REQUIRES_NEW)
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
上面就是对单个方法进行事务控制。适合需要精细化处理的项目。但但部分项目不需要这么精细。就可以通过配置对某个包下方法进行IOC事务配置。