一、简述Spring中事务管理的两种方式
Spring中事务管理有两种方式,分别是编程式事务管理和声明式事务管理。编程式事务管理就是在代码中手动控制事务的开启、提交和回滚;而声明式事务管理则是通过配置文件或注解的方式来声明哪些方法需要开启事务,并自动实现事务的管理。
二、Spring事务管理方式
1. Spring事务管理接口
Spring事务管理接口是org.springframework.transaction
包中定义的事务管理的基本接口。
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
getTransaction
方法用于获取事务的状态,commit
方法用于提交事务,rollback
方法用于回滚事务。这三个方法是Spring事务机制中最基本的方法。
2. Spring事务管理的核心接口
Spring事务管理的核心接口是TransactionDefinition
和TransactionStatus
这两个接口。
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int ISOLATION_DEFAULT = -1;
int TIMEOUT_DEFAULT = -1;
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
}
TransactionDefinition
接口定义了事务的传播属性、隔离级别、超时时间、只读属性和事务名称等属性。TransactionStatus
接口则定义了事务的状态,比如是否是新事务、是否有保存点、是否只回滚、是否已经完成等。
三、Spring中的事务是如何实现的
在Spring事务管理中,需要对数据源进行事务管理的方法被标注为@Transactional
,Spring将会在方法执行前开启一个事务,方法执行后,如果出现异常,则回滚事务,否则提交事务。
1. Spring事务管理的两种方式
事务管理有两种方式:编程式事务管理和声明式事务管理。
2. Spring事务的实现方式
Spring提供了几种不同的实现事务的方式。
(1)编程式事务管理
编程式事务管理就是在代码中手动控制事务的开启、提交和回滚。
public class AccountServiceImpl implements AccountService {
// 使用@Resource注解注入DataSource对象
@Resource(name = "dataSource")
private DataSource dataSource;
@Override
public void transfer(String fromUser, String toUser, double money) throws Exception {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
conn = dataSource.getConnection();
// 开启事务
conn.setAutoCommit(false);
String sql1 = "update account set balance = balance - ? where username = ?";
String sql2 = "update account set balance = balance + ? where username = ?";
pstmt1 = conn.prepareStatement(sql1);
pstmt1.setDouble(1, money);
pstmt1.setString(2, fromUser);
pstmt1.executeUpdate();
pstmt2 = conn.prepareStatement(sql2);
pstmt2.setDouble(1, money);
pstmt2.setString(2, toUser);
pstmt2.executeUpdate();
// 提交事务
conn.commit();
} catch (Exception e) {
// 回滚事务
conn.rollback();
throw e;
} finally {
if (pstmt1 != null) {
pstmt1.close();
}
if (pstmt2 != null) {
pstmt2.close();
}
if (conn != null) {
conn.close();
}
}
}
}
(2)声明式事务管理
声明式事务管理则是通过配置文件或注解的方式来声明哪些方法需要开启事务,并自动实现事务的管理。 在XML配置文件中声明事务管理:
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager" />
在Java类中使用@Transactional
注解声明事务管理:
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
@Transactional
public void transfer(String fromUser, String toUser, double money) throws Exception {
accountDao.update(fromUser, -money);
//int i = 1 / 0;
accountDao.update(toUser, money);
}
}
3. Spring事务实现过程的示例
以Spring注解方式实现转账为例,下面是完整的代码示例:
Account类:
public class Account {
private int id;
private String username;
private double balance;
// getter/setter方法省略
}
AccountDao接口:
public interface AccountDao {
public void update(String username, double money) throws Exception;
public Account findByUsername(String username) throws Exception;
}
AccountDao实现类:
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void update(String username, double money) throws Exception {
String sql = "update account set balance = balance + ? where username = ?";
jdbcTemplate.update(sql, money, username);
}
@Override
public Account findByUsername(String username) throws Exception {
String sql = "select * from account where username = ?";
List<Account> list = jdbcTemplate.query(sql, new Object[]{username}, new AccountRowMapper());
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
private class AccountRowMapper implements RowMapper<Account> {
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setUsername(rs.getString("username"));
account.setBalance(rs.getDouble("balance"));
return account;
}
}
}
AccountService接口:
public interface AccountService {
public void transfer(String fromUser, String toUser, double money) throws Exception;
public Account findByUsername(String username) throws Exception;
}
AccountService实现类:
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
@Transactional
public void transfer(String fromUser, String toUser, double money) throws Exception {
Account account1 = accountDao.findByUsername(fromUser);
Account account2 = accountDao.findByUsername(toUser);
double balance1 = account1.getBalance() - money;
double balance2 = account2.getBalance() + money;
accountDao.update(fromUser, -money);
// 手动制造一个异常,测试事务管理是否起作用
int i = 1 / 0;
accountDao.update(toUser, money);
}
@Override
public Account findByUsername(String username) throws Exception {
return accountDao.findByUsername(username);
}
}
测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void transfer() throws Exception {
accountService.transfer("user1", "user2", 100);
}
}
结语
Spring的事务管理是非常重要的功能,在实际开发中,经常需要处理涉及到数据库操作的事务问题。通过理解Spring事务管理的方式和实现机制,在实现事务管理的过程中就能提高效率,避免出现大量的重复代码,同时也可以简化代码的复杂度。