spring 事务实现方式有哪些?
事务的使用场景
一个用户操作下包含多个数据库修改操作(增、删、改)时, 必须确保这些修改操作要么同时执行,要么同时不执行, 那么这个用户操作涉及到的代码块必须要加事务。
spring 事务实现方式
-
编程式事务管理(对基于 POJO 的应用来说是唯一选择) 我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法
-
声明式事务
基于 TransactionProxyFactoryBean的声明式事务管理
基于 注解@Transactional 的声明式事务管理
基于 Aspectj AOP 配置(注解)事务
-
编程式事务管理
在Spring中,编程式事务管理可以通过
TransactionTemplate
或者PlatformTransactionManager
接口来实现。-
使用
TransactionTemplate
:TransactionTemplate
是一个模板类,提供了一种回调机制,允许你在一个事务中执行多个操作。
@Autowired private TransactionTemplate transactionTemplate; @Autowired public MyService(PlatformTransactionManager transactionManager, MyRepository myRepository) { this.transactionTemplate = new TransactionTemplate(transactionManager); this.myRepository = myRepository; // 定制事务属性 this.transactionTemplate.setPropagationBehavior(Propagation.REQUIRES_NEW.value()); this.transactionTemplate.setIsolationLevel(Isolation.DEFAULT.value()); this.transactionTemplate.setTimeout(30); // 设置超时时间,单位为秒 } // 编程式事务管理实现 public void createEntityByTemplate(MyEntity myEntity) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { myRepository.save(myEntity); } }); }
-
使用
PlatformTransactionManager
:这个接口提供了更低层次的事务控制,允许你显式地开始、提交和回滚事务。@Autowired private PlatformTransactionManager transactionManager; public void createEntityByTransactionManager(MyEntity myEntity) { TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); try { myRepository.save(myEntity); transactionManager.commit(status); } catch (DataAccessException e) { transactionManager.rollback(status); throw e; } }
我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法
package constxiong.interview.transaction; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TransactionTest { public static void main(String[] args) throws Exception { testManualTransaction();//测试函数式控制事务 } private static void testManualTransaction() throws SQLException { ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml"); DataSource ds = (DataSource)context.getBean("datasource"); Connection conn = ds.getConnection(); try { initTable(conn);//初始化表 conn.setAutoCommit(false);//设置不自动提交事务 queryUsers(conn);//查询打印用户表 deleteUser(conn);//删除 id=1 用户 conn.rollback();//回滚 queryUsers(conn);//查询打印用户表 } finally { conn.close(); } } private static void initTable(Connection conn) throws SQLException { conn.createStatement().execute("drop table if exists user"); conn.createStatement().execute("create table user(id int, username varchar(60)) ENGINE=InnoDB DEFAULT CHARSET=utf8 ");//是否支持事务与数据库引擎有关,此处删除 ENGINE=InnoDB DEFAULT CHARSET=utf8 可能不支持事务 conn.createStatement().execute("insert into user values(1, 'user1')"); conn.createStatement().execute("insert into user values(2, 'user2')"); } private static void deleteUser(Connection conn) throws SQLException { conn.createStatement().execute("delete from user where id = 1"); } private static void queryUsers(Connection conn) throws SQLException { Statement st = conn.createStatement(); st.execute("select * from user"); ResultSet rs = st.getResultSet(); while (rs.next()) { System.out.print(rs.getString("id")); System.out.print(" "); System.out.print(rs.getString("username")); System.out.println(); } } }
手动事务管理可以在用JDBC操作数据库时使用。
-
-
基于 TransactionProxyFactoryBean的声明式事务管理
修改 spring 配置文件,添加事务管理器 DataSourceTransactionManager 和事务代理类 TransactionProxyFactoryBean
测试代码:
package constxiong.interview.transaction; import java.util.Map; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TransactionTest { static ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml"); public static void main(String[] args) throws Exception { testUseTransactionProxy(); //测试使用 spring TransactionProxyFactoryBean } private static void testUseTransactionProxy() { final UserDao userDao = (UserDao)context.getBean("userProxy"); printUsers(userDao);//打印用户 userDao.deleteUser(1);//删除 id=1 用户 } private static void printUsers(UserDao userDao) { for (Map<String, Object> user : userDao.getUsers()) { System.out.println(user); } } }
-
基于 注解@Transactional 的声明式事务管理
这种方式比较简单,被注解@Transactional声明的方法内,只要有一个数据库修改操作出现异常,之前执行过的修改操作也会回滚。
测试代码:
package constxiong.interview.transaction; import java.util.Map; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TransactionTest { static ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml"); public static void main(String[] args) throws Exception { testAnnotationTransaction(); } private static void testAnnotationTransaction() { UserDao userDao = (UserDao)context.getBean("userDao"); printUsers(userDao); userDao.deleteUser(1); } private static void printUsers(UserDao userDao) { for (Map<String, Object> user : userDao.getUsers()) { System.out.println(user); } } }
-
基于 Aspectj AOP 配置(注解)事务