Spring事物管理的實現

一、簡述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配置文件中聲明事物管理:



    



在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 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 {
        @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事物管理的方式和實現機制,在實現事物管理的過程中就能提高效率,避免出現大量的重複代碼,同時也可以簡化代碼的複雜度。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/239882.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 12:19
下一篇 2024-12-12 12:19

相關推薦

發表回復

登錄後才能評論