1.Spring JDBC
1.1applicationContext.xml內(nèi)配置好數(shù)據(jù)庫相關(guān)信息
<!-- 指定需要掃描的包(包括子包),使注解生效 -->
<context:component-scan base-package="com.ch5"/>
<!-- 配置數(shù)據(jù)源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- MySQL數(shù)據(jù)庫驅(qū)動 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!-- 連接數(shù)據(jù)庫的URL -->
<property name="url" value="jdbc:mysql://localhost:3306/springtest?characterEncoding=utf8"/>
<!-- 連接數(shù)據(jù)庫的用戶名 -->
<property name="username" value="root"/>
<!-- 連接數(shù)據(jù)庫的密碼 -->
<property name="password" value="363316495"/>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
1.2創(chuàng)建實體類MyUser
public class MyUser {
private Integer uid;
private String uname;
private String usex;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUsex() {
return usex;
}
public void setUsex(String usex) {
this.usex = usex;
}
public String toString() {
return "myUser [uid=" + uid +", uname=" + uname + ", usex=" + usex + "]";
}
}
1.3創(chuàng)建數(shù)據(jù)庫訪問層TestDao
接口類:
package ch5;
import java.util.List;
public interface TestDao {
public int update(String sql, Object[] param);
public List<MyUser> query(String sql, Object[] param);
}
實現(xiàn)類:
@Repository("testDao")
public class TestDaoImpl implements TestDao{
//自動裝配
@Autowired
//使用配置文件中的JDBC(相當(dāng)于依賴注入了)
private JdbcTemplate jdbcTemplate;
//更新方法
@Override
public int update(String sql, Object[] param) {
return jdbcTemplate.update(sql, param);
}
//查詢方法
@Override
public List<MyUser> query(String sql, Object[] param) {
RowMapper<MyUser> rowMapper = new BeanPropertyRowMapper<MyUser>(MyUser.class);
return jdbcTemplate.query(sql, rowMapper, param);
}
}
1.4測試:
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
//從容器中獲取增強后的目標(biāo)對象
TestDao td = (TestDao)appCon.getBean("testDao");
//插入的sql
//暫時沒有在這里發(fā)現(xiàn)問題:
//UID為主鍵,這里設(shè)置為空,不會出現(xiàn)問題,原因是:mysql數(shù)據(jù)庫里面可以勾選主鍵自動增長
String insertSql = "insert into user values(null,?,?)";
//數(shù)組param的值與insertSql語句一一對應(yīng)
//此處我的mysql不支持中文字符,改成了英文字符,不影響
Object param1[] = {"chenheng1", "nan"};
Object param2[] = {"chenheng2", "nv"};
Object param3[] = {"chenheng3", "nan"};
Object param4[] = {"chenheng4", "nv"};
//添加用戶
td.update(insertSql, param1);
td.update(insertSql, param2);
td.update(insertSql, param3);
td.update(insertSql, param4);
//查詢用戶的sql
String selectSql ="select * from user";
List<MyUser> list = td.query(selectSql, null);
for(MyUser mu : list) {
System.out.println(mu);
}
}
}

2.編程式事務(wù)管理
(1)基于底層API的編程式事務(wù)管理
2.1.1 applicationContext.xml內(nèi)配置事務(wù)管理器
<!-- 為數(shù)據(jù)源添加事務(wù)管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" <property name="dataSource" ref="dataSource" />
</bean>
2.1.2 創(chuàng)建數(shù)據(jù)訪問類
//數(shù)據(jù)訪問類
@Repository("codeTransaction")
public class CodeTransaction {
@Autowired
// 使用配置文件中的JDBC模板
private JdbcTemplate jdbcTemplate;
//DataSourceTransactionManager是PlatformTransactionManager接口的實現(xiàn)類
@Autowired
private DataSourceTransactionManager txManager;
//定義test方法
public String test() {
// 默認(rèn)事務(wù)定義,例如隔離級別、傳播行為
TransactionDefinition tf = new DefaultTransactionDefinition();
//開啟事務(wù)ts
TransactionStatus ts = txManager.getTransaction(tf);
String message = "?執(zhí)行成功,沒有事務(wù)回滾";
try {
// 刪除表中數(shù)據(jù)
String sql = " delete from user ";
//添加表中數(shù)據(jù)
String sql1 = " insert into user values(?,?,?) ";
Object param[] = { 1, "topus", "nan" };
// 先刪除數(shù)據(jù)
jdbcTemplate.update(sql);
//添加一條數(shù)據(jù)
jdbcTemplate.update(sql1, param);
// 添加相同的一條數(shù)據(jù)
jdbcTemplate.update(sql1, param);
//提交事務(wù)
txManager.commit(ts);
} catch (Exception e) {
// 出現(xiàn)異常,事務(wù)回滾
txManager.rollback(ts);
message = "主鍵重復(fù),事務(wù)回滾";
e.printStackTrace();
}
//返回的是執(zhí)行成功與否的消息
return message;
}
}
2.2.3測試
public class TestCodeTransaction {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
CodeTransaction ct = (CodeTransaction)appCon.getBean("codeTransaction");
String result = ct.test();
System.out.println(result);
}
}





(2)基于TranesactionTemplate的編程式事務(wù)管理
2.2.1為事務(wù)管理器添加事務(wù)模板
<!-- 為事務(wù)管理器txManager創(chuàng)建transactionTemplate -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"/>
</bean>
2.2.2 創(chuàng)建數(shù)據(jù)訪問類
@Repository("transactionTemplateDao")
public class TransactionTemplateDao {
@Autowired
//使用配置文件中的jdbc
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionTemplate transactionTemplate;
String message = "";
public String test() {
//匿名內(nèi)部類
transactionTemplate.execute(new TransactionCallback<Object>(){
@Override
public Object doInTransaction(TransactionStatus arg0) {
//刪除
String sql = " delete from user ";
//添加
String sql1 = " insert into user values(?,?,?) ";
Object param[] = {
1,
"zyz",
"nan"
};
try{
//先刪除數(shù)據(jù)
jdbcTemplate.update(sql);
//添加一條數(shù)據(jù)
jdbcTemplate.update(sql1, param);
//添加一條重復(fù)數(shù)據(jù)
jdbcTemplate.update(sql1, param);
message = "執(zhí)行成功沒有事務(wù)回滾?";
}catch(Exception e){
message = "主鍵重復(fù),事務(wù)回滾";
e.printStackTrace();
}
return message;
}
});
return message;
}
}
2.2.3 創(chuàng)建測試類
public class TransactionTemplateTest {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
TransactionTemplateDao ct = (TransactionTemplateDao)appCon.getBean("transactionTemplateDao");
String result = ct.test();
System.out.println(result);
}
}





3.聲明式事務(wù)管理
(基于AOP技術(shù)實現(xiàn)的事務(wù)管理,其本質(zhì)是對方法前后進(jìn)行攔截,然后在目標(biāo)方法開始之前創(chuàng)建或者加入一個事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù))
(1)xml
3.1.1創(chuàng)建Dao層
public interface TestDao {
public int save(String sql, Object param[]);
public int delete(String sql, Object param[]);
}
@Repository("TestDao")
public class TestDaoImpl implements TestDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int save(String sql, Object[] param) {
return jdbcTemplate.update(sql,param);
}
@Override
public int delete(String sql, Object[] param) {
return jdbcTemplate.update(sql,param);
}
}
3.1.2創(chuàng)建service層
public class TestServiceImpl implements TestService{
@Autowired
private TestDao testDao;
@Override
// 這里調(diào)用Dao層的save和delete方法,參數(shù)為sql和param,等控制層在傳入sql語句
public int save(String sql, Object[] param) {
return testDao.save(sql, param);
}
@Override
public int delete(String sql, Object[] param) {
return testDao.delete(sql, param);
}
}
3.1.3創(chuàng)建controller層
private TestService testService;
public String test() {
// 此處在加入sql語句
String message = "";
String deleteSql ="delete from user";
String saveSql = "insert into user values(?,?,?)";
Object param[] = {1,"topus","nan"};
try{
testService.delete(deleteSql, null);
testService.save(saveSql, param);
//重復(fù)插入相同主鍵的數(shù)據(jù)
testService.save(saveSql, param);
}catch(Exception e){
message = "主鍵重復(fù),回滾";
e.printStackTrace();
}
return message;
}
}
3.1.4創(chuàng)建配置文件
在xml里面使用<tx:advice>編寫通知聲明事務(wù)
使用<aop:config>編寫AOP讓spring自動對目標(biāo)對象生成代理
<!-- 指定需要掃描的包(包括子包),使注解生效 -->
<context:component-scan base-package="com.statement"/>
<!-- 配置數(shù)據(jù)源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- MySQL數(shù)據(jù)庫驅(qū)動 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!-- 連接數(shù)據(jù)庫的URL -->
<property name="url" value="jdbc:mysql://localhost:3306/springtest?characterEncoding=utf8"/>
<!-- 連接數(shù)據(jù)庫的用戶名 -->
<property name="username" value="root"/>
<!-- 連接數(shù)據(jù)庫的密碼 -->
<property name="password" value="root"/>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 為數(shù)據(jù)源添加事務(wù)管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 編寫通知聲明事務(wù) -->
<tx:advice id="myAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- *表示任意方法 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 編寫AOP,讓Spring自動對目標(biāo)對象生成代理,需要使用AspectJ的表達(dá)式 -->
<aop:config>
<!-- 定義切入點 -->
<aop:pointcut expression="execution(* com.statement.service.*.*())" id="txPointCut"/>
<!-- 切面:將切入點與通知關(guān)聯(lián) -->
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
3.1.6測試
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext appCon = new ClassPathXmlApplicationContext("/com/statement/xml/XMLstatementapplicationContext.xml");
StatementController ct = (StatementController)appCon.getBean("statementController");
String result = ct.test();
System.out.println(result);
}
(2)基于transactional注解的聲明式事務(wù)管理
3.2.1創(chuàng)建配置文件
<!-- 指定需要掃描的包(包括子包),使注解生效 -->
<context:component-scan base-package="com.statement"/>
<!-- 配置數(shù)據(jù)源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- MySQL數(shù)據(jù)庫驅(qū)動 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!-- 連接數(shù)據(jù)庫的URL -->
<property name="url" value="jdbc:mysql://localhost:3306/springtest?characterEncoding=utf8"/>
<!-- 連接數(shù)據(jù)庫的用戶名 -->
<property name="username" value="root"/>
<!-- 連接數(shù)據(jù)庫的密碼 -->
<property name="password" value="root"/>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 為數(shù)據(jù)源添加事務(wù)管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 為事務(wù)管理器注冊注解驅(qū)動 -->
<tx:annotation-driven transaction-manager="txManager" />
</beans>
3.2.2在service層添加注解@Transactional
//加上注解@Transactional,就可以指定這個類需要受Spring的事務(wù)管理
//注意@Transactional智能針對pulic屬性范圍內(nèi)的方法添加
@Transactional
public class TestServiceImpl implements TestService{
@Autowired
private TestDao testDao;
@Override
// 這里調(diào)用Dao層的save和delete方法,參數(shù)為sql和param,等控制層在傳入sql語句
public int save(String sql, Object[] param) {
return testDao.save(sql, param);
}
@Override
public int delete(String sql, Object[] param) {
return testDao.delete(sql, param);
}
}
3.2.3在事務(wù)處理中捕獲異常
修改注解
@Transactional(rollbackFor = (Exception.class))
//指定回滾生效的異常類


其實本質(zhì)上問題在于書內(nèi)的try catch的異常捕獲寫在的service層,但是在默認(rèn)情況下,Spring只在(發(fā)生未被捕獲的RuntimeException時)才回滾事務(wù),此時如果想在事務(wù)處理中捕獲異常就必須指定回滾生效的異常類.