spring-transaction-事务
spring-in-action-jdbc-transaction代码
同时成功,同时失败。事务分为编码式事务和声明式事务。
package com.SimpleJdbcTemplate.Dao; import com.SimpleJdbcTemplate.domian.Family; import java.util.List; /** * Created by cuimiao on 15/12/13. */ public interface FamilyDao { public void insert(Family family); public void update(Family family); public void delete(); public List<Family> selectAll(Family family); public void batchInsert(List<Family> familyList); }
package com.SimpleJdbcTemplate.domian; /** * Created by cuimiao on 15/12/13. */ public class Family { private int id; private String name; private String role; public Family() { } public Family(int id, String name, String role) { this.id = id; this.name = name; this.role = role; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } }
package com.SimpleJdbcTemplate.Impl; import com.SimpleJdbcTemplate.Dao.FamilyDao; import com.SimpleJdbcTemplate.domian.Family; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Created by cuimiao on 15/12/19. */ //@Component //@Transactional public class FamilyDaoImplTransaction implements FamilyDao{ // @Autowired // @Qualifier("jdbc") private JdbcTemplate jdbcTemplate; // @Autowired public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class) public void insert(Family family){ String sql = "insert into famiXXly (name,role) values (?,?)";//这故意写错了,产生异常 jdbcTemplate.update(sql, family.getName(), family.getRole()); } public void delete(){ String sql = "delete from family where 1 order by id DESC limit 1"; jdbcTemplate.update(sql); } public void update(Family family){ String sql = "UPDATE family SET role = ? WHERE 1 ORDER BY id DESC limit 1"; jdbcTemplate.update(sql, family.getRole()); } public List<Family> selectAll(Family family){ String sql = "SELECT * FROM family"; List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>(); return jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(Family.class)); } public void batchInsert(List<Family> familyList){ String sql = "insert into family(name,role)values(?,?)"; List<Object[]> parameters = new ArrayList<Object[]>(); for (Family f : familyList) { parameters.add(new Object[] { f.getName(), f.getRole() }); } jdbcTemplate.batchUpdate(sql, parameters); } }
package com.SimpleJdbcTemplate.service; import com.SimpleJdbcTemplate.Dao.FamilyDao; import com.SimpleJdbcTemplate.domian.Family; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import java.util.List; /** * Created by cuimiao on 15/12/19. */ public class FamilyService { private TransactionTemplate transactionTemplate; private FamilyDao familyDao; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } public void setFamilyDao(FamilyDao familyDao) { this.familyDao = familyDao; } public void batchInsert(final List<Family> familyList){ transactionTemplate.execute(new TransactionCallback<Void>() { public Void doInTransaction(TransactionStatus txStatus) { try { familyDao.batchInsert(familyList); //error familyDao.insert(new Family()); } catch (Exception e) { txStatus.setRollbackOnly(); System.out.println("batchInsert ERROR"); } return null; } }); } public List<Family> selectAll(final Family family){ return transactionTemplate.execute(new TransactionCallback<List<Family>>() { public List<Family> doInTransaction(TransactionStatus txStatus) { try { return familyDao.selectAll(family); } catch (Exception e) { txStatus.setRollbackOnly(); System.out.println("batchInsert ERROR"); } return null; } }); } public void insert(final Family family){ transactionTemplate.execute(new TransactionCallback<Void>() { public Void doInTransaction(TransactionStatus txStatus) { try { familyDao.insert(family); } catch (Exception e) { txStatus.setRollbackOnly(); System.out.println("batchInsert ERROR"); } return null; } }); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--familyService中有impl,有transactionTemplate,transactionTemplate有transactionManager,transactionManager有dataSource--> <bean id="familyService" class="com.SimpleJdbcTemplate.service.FamilyService"> <property name="familyDao" ref="familyDaoImplTransaction"/> <property name="transactionTemplate" ref="transactionTemplate"/> </bean> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--familyDao的impl,有JdbcTemplate,JdbcTemplate有dataSource--> <bean id="familyDaoImplTransaction" class="com.SimpleJdbcTemplate.Impl.FamilyDaoImplTransaction"> <property name="jdbcTemplate" ref="jdbc"/> </bean> <bean id="jdbc" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> <!--<constructor-arg name="dataSource" ref="dataSource"/>--> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="nieyijing214"/> <property name="initialSize" value="5"/> <property name="maxActive" value="10"/> </bean> </beans>
TransactionCallback为回调方法,在方法里进行了TransactionStatus对异常等的处理,包括rollback,如果没有异常就commit了。
package TestTransactionTemplate; import com.SimpleJdbcTemplate.domian.Family; import com.SimpleJdbcTemplate.service.FamilyService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.ArrayList; import java.util.List; /** * Created by cuimiao on 15/12/19. */ public class TestSimpleJdbcTransaction { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-simple-dao-transaction.xml"); FamilyService familyService = (FamilyService) context.getBean("familyService"); List<Family> familyList = new ArrayList<Family>(); familyList.add(new Family(0, "崔淼", "老公")); familyList.add(new Family(0, "聂绎静", "老婆")); familyList.add(new Family(0, "嘿嘿", "小三")); //三条数据是正确的,一条是假的 familyService.batchInsert(familyList); // familyService.insert(new Family(0, "儿子", "崔小淼")); List<Family> resultList = familyService.selectAll(new Family()); for(Family family:resultList){ long id = family.getId(); String name = family.getName(); String role = family.getRole(); System.out.println(id + " " + name + " " + role); } } }
以上是编码式事务,如果为声明式,以下面注释@Transaction为例;
package com.SimpleJdbcTemplate.service; import com.SimpleJdbcTemplate.Dao.FamilyDao; import com.SimpleJdbcTemplate.domian.Family; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.List; /** * Created by cuimiao on 15/12/19. */ //@Component @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public class FamilyAnnotaitonService { // @Autowired // @Qualifier("familyDaoImplTransaction") // @Autowired private FamilyDao familyDao; public void setFamilyDao(FamilyDao familyDao) { this.familyDao = familyDao; } @Transactional(propagation = Propagation.REQUIRED) public void insert(Family family){ familyDao.insert(family); familyDao.insert(family); familyDao.insert(family); // throw new RuntimeException("ASDFDFDF"); } public void delete(){ familyDao.delete(); } public void update(Family family){ familyDao.update(family); } @Transactional(propagation = Propagation.REQUIRED) public void batchInsert(List<Family> familyList){ familyDao.batchInsert(familyList); // try { // familyDao.insert(new Family(0, "1", "2")); // } catch (Exception e) { // System.out.println("ASDFASDF"); // } familyDao.insert(new Family(0, "1", "2")); } public List<Family> selectAll(Family family){ return familyDao.selectAll(family); } }
主要注意一下事务的rollbackfor,因为主要针对的是RuntimeException;
还有边界,如果再@Transaction的方法内部进行了catch则不会回滚,因为transactionManager是靠aop进行实现的,所以要抛出异常才能执行,要不然不会rollback,会commit,所有必须抛出来。下面是xml和测试类。
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:annotation-config/> <context:component-scan base-package="com"/> <tx:annotation-driven transaction-manager="trManager" proxy-target-class="true"/> <bean id="trManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="familyAnnotaitonService" class="com.SimpleJdbcTemplate.service.FamilyAnnotaitonService"> <property name="familyDao" ref="familyDaoImplTransaction"/> </bean> <bean id="familyDaoImplTransaction" class="com.SimpleJdbcTemplate.Impl.FamilyDaoImplTransaction"> <property name="jdbcTemplate" ref="jdbc"/> </bean> <bean id="jdbc" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> <!--<constructor-arg name="dataSource" ref="dataSource"/>--> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="nieyijing214"/> <property name="initialSize" value="5"/> <property name="maxActive" value="10"/> </bean> </beans>
package TestTransactionTemplate; import com.SimpleJdbcTemplate.domian.Family; import com.SimpleJdbcTemplate.service.FamilyAnnotaitonService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.ArrayList; import java.util.List; /** * Created by cuimiao on 15/12/19. */ public class TestSimpleJdbcTransactionAnnotation { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-simple-dao-transaction-annotation.xml"); FamilyAnnotaitonService familyService = (FamilyAnnotaitonService) context.getBean("familyAnnotaitonService"); List<Family> familyList = new ArrayList<Family>(); familyList.add(new Family(0, "崔淼", "老公")); familyList.add(new Family(0, "聂绎静", "老婆")); familyList.add(new Family(0, "嘿嘿", "小三")); //三条数据是正确的,一条是假的 try { familyService.batchInsert(familyList); } catch (Exception e) { System.out.println("BATCH INSERT ERROR"); } // familyService.insert(new Family(0, "儿子", "崔小淼")); List<Family> resultList = familyService.selectAll(new Family()); for(Family family:resultList){ long id = family.getId(); String name = family.getName(); String role = family.getRole(); System.out.println(id + " " + name + " " + role); } } }