Spring 為程式設計式的事務管理,提供了相應的模板類 org.springframework.transaction.support.TransactionTemplate,可以應對一些特殊場合的需要。
TransactionTemplate 是執行緒安全的,所以可以在多個類中共享 TransactionTemplate 例項,實現事務管理 。
TransactionTemplate 繼承了 DefaultTransactionDefinition,所以也擁有多種設定事務屬性的方法:
TransactionTemplate 類的主要方法:
方法 | 說明 |
---|---|
public void setTransactionManager(PlatformTransactionManager transactionManager) |
設定事務管理器。 |
public <T> T execute(TransactionCallback<T> action) |
在 TransactionCallback 回撥介面中,編寫需要以事務方式執行的資料訪問邏輯程式碼。 |
TransactionCallback 介面只定義了一個方法 doInTransaction(TransactionStatus status)
。Spring 還定義了一個抽象類 TransactionCallbackWithoutResult,用於只執行,但不需要返回結果的場景。
Spring 配置檔案:
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 掃描包含註解定義的類包-->
<context:component-scan base-package="net.deniro.xxx.transaction"/>
<!-- 資料來源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://127.0.0.1:3306/xxx"
p:username="root"
p:password="xxx"/>
<!-- JDBC 模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"
/>
<!-- 事務管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!-- 事務模板 -->
<bean id="TransactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate"
p:transactionManager-ref="transactionManager"/>
</beans>
複製程式碼
User 類:
public class User {
private long id;
private String name;
public User(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
複製程式碼
UserDao 類:
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 儲存賬號
*
* @param user
* @throws SQLException
*/
public void save(User user) {
String sql = "insert into t_user(user_name) values(?)";
jdbcTemplate.update(sql, user.getName());
String sql2 = "insert into t_log(user_name) values(?)";
jdbcTemplate.update(sql2, user.getName());
}
}
複製程式碼
為了實驗事務是否生效,這裡的第一個 SQL 是正確的,而第二個 SQL 是錯誤的(找不到表)。
UserService 類:
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private TransactionTemplate template;
public void save(final User user) {
template.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
userDao.save(user);
}
});
}
}
複製程式碼
單元測試:
public class UserServiceTest {
ApplicationContext context;
@BeforeMethod
public void setUp() throws Exception {
context = new ClassPathXmlApplicationContext("spring.xml");
}
@Test
public void test() {
UserService userService = (UserService) context.getBean("userService");
final User user = new User("deniro");
userService.save(user);
}
}
複製程式碼
為了看到 Spring 的事務日誌,我們可以修改 log4j 事務配置,級別改為 DEBUG:
log4j.logger.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG
log4j.logger.org.springframework.transaction.interceptor=DEBUG
log4j.logger.org.springframework.transaction=DEBUG
複製程式碼
執行結果分析:
Spring 首先建立一個新的事務。
在執行到第二個 SQL 語句時,丟擲異常;Spring 執行回滾操作。說明事務生效咯O(∩_∩)O~