《Pro Spring》学习笔记之声明式事务
来源:互联网 发布:处cp什么意思网络用语 编辑:程序博客网 时间:2024/04/19 13:08
本文数据库环境为mysql,orm环境为ibatis
数据库脚本:
create table account(id varchar(20) primary key,name varchar(20));
create table history(id varchar(20) primary key,name varchar(20),accountid varchar(20),
constraint foreign key(accountid) references account(id));
create table history(id varchar(20) primary key,name varchar(20),accountid varchar(20),
constraint foreign key(accountid) references account(id));
我们的事务控制,就是想让account表和history同步,也就是account和history的数据必须同时更新,同时插入
DAO接口:
package ch12.transaction.declare;
import java.util.List;
public interface IDAO ...{
public void insertAccount(Account account);
public void insertHistory(History history,int count) throws MyException ;
public List getAllAccount();
public List getAllHistory();
}
import java.util.List;
public interface IDAO ...{
public void insertAccount(Account account);
public void insertHistory(History history,int count) throws MyException ;
public List getAllAccount();
public List getAllHistory();
}
Service接口:
package ch12.transaction.declare;
import java.util.List;
public interface AccountManager ...{
public void createAccount(Account account,History history,int count) throws MyException;
public List getAllAccount();
public List getAllHistory();
}
import java.util.List;
public interface AccountManager ...{
public void createAccount(Account account,History history,int count) throws MyException;
public List getAllAccount();
public List getAllHistory();
}
Domain:
package ch12.transaction.declare;
public class Account ...{
private String id;
private String name;
public Account()...{
}
public String getId() ...{
return id;
}
public void setId(String id) ...{
this.id = id;
}
public Account(String id, String name) ...{
super();
this.id = id;
this.name = name;
}
public String getName() ...{
return name;
}
public void setName(String name) ...{
this.name = name;
}
}
package ch12.transaction.declare;
public class History ...{
private String id;
private String name;
private Account account;
public History()...{
}
public History(String id, String name, Account account) ...{
super();
this.id = id;
this.name = name;
this.account = account;
}
public String getId() ...{
return id;
}
public void setId(String id) ...{
this.id = id;
}
public String getName() ...{
return name;
}
public void setName(String name) ...{
this.name = name;
}
public Account getAccount() ...{
return account;
}
public void setAccount(Account account) ...{
this.account = account;
}
}
public class Account ...{
private String id;
private String name;
public Account()...{
}
public String getId() ...{
return id;
}
public void setId(String id) ...{
this.id = id;
}
public Account(String id, String name) ...{
super();
this.id = id;
this.name = name;
}
public String getName() ...{
return name;
}
public void setName(String name) ...{
this.name = name;
}
}
package ch12.transaction.declare;
public class History ...{
private String id;
private String name;
private Account account;
public History()...{
}
public History(String id, String name, Account account) ...{
super();
this.id = id;
this.name = name;
this.account = account;
}
public String getId() ...{
return id;
}
public void setId(String id) ...{
this.id = id;
}
public String getName() ...{
return name;
}
public void setName(String name) ...{
this.name = name;
}
public Account getAccount() ...{
return account;
}
public void setAccount(Account account) ...{
this.account = account;
}
}
ibatis配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<sqlMap resource="ch12/transaction/declare/Account.xml" />
<sqlMap resource="ch12/transaction/declare/History.xml" />
</sqlMapConfig>
<!DOCTYPE sqlMapConfig
PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<sqlMap resource="ch12/transaction/declare/Account.xml" />
<sqlMap resource="ch12/transaction/declare/History.xml" />
</sqlMapConfig>
ibatis sql map:
history.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap >
<typeAlias type="ch12.transaction.declare.History" alias="history"/>
<resultMap id="historyTest" class="history" >
<result column="id" property="id" jdbcType="VARCHAR" />
<result column="name" property="name" jdbcType="VARCHAR" />
</resultMap>
<insert id="insertHistory" parameterClass="history">
insert into history (id,name,accountid) values (#id#,#name#,#account.id#)
</insert>
<select id="getAllHistory" resultMap="historyTest">
select * from history
</select>
</sqlMap>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap >
<typeAlias type="ch12.transaction.declare.History" alias="history"/>
<resultMap id="historyTest" class="history" >
<result column="id" property="id" jdbcType="VARCHAR" />
<result column="name" property="name" jdbcType="VARCHAR" />
</resultMap>
<insert id="insertHistory" parameterClass="history">
insert into history (id,name,accountid) values (#id#,#name#,#account.id#)
</insert>
<select id="getAllHistory" resultMap="historyTest">
select * from history
</select>
</sqlMap>
account.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap >
<typeAlias type="ch12.transaction.declare.Account" alias="account"/>
<resultMap id="accountTest" class="account" >
<result column="id" property="id" jdbcType="VARCHAR" />
<result column="name" property="name" jdbcType="VARCHAR" />
</resultMap>
<select id="getAllAccount" resultMap="accountTest">
select * from account
</select>
<insert id="insertAccount" parameterClass="account">
insert into account (id,name) values (#id#,#name#)
</insert>
</sqlMap>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap >
<typeAlias type="ch12.transaction.declare.Account" alias="account"/>
<resultMap id="accountTest" class="account" >
<result column="id" property="id" jdbcType="VARCHAR" />
<result column="name" property="name" jdbcType="VARCHAR" />
</resultMap>
<select id="getAllAccount" resultMap="accountTest">
select * from account
</select>
<insert id="insertAccount" parameterClass="account">
insert into account (id,name) values (#id#,#name#)
</insert>
</sqlMap>
自定义异常:
package ch12.transaction.declare;
public class MyException extends Exception ...{
public MyException(String msg)...{
super(msg);
}
}
public class MyException extends Exception ...{
public MyException(String msg)...{
super(msg);
}
}
DAO实现:
package ch12.transaction.declare;
import java.sql.SQLException;
import java.util.List;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
public class TestDAO extends SqlMapClientDaoSupport implements IDAO ...{
public List getAllHistory() ...{
return this.getSqlMapClientTemplate().queryForList("getAllHistory");
}
public void insertAccount(Account account) ...{
this.getSqlMapClientTemplate().insert("insertAccount",account);
}
public void insertHistory(History history,int count) throws MyException ...{
if(count%3==0)...{
//当count能被三整除时,模拟错误,促使事务回滚
throw new MyException("divide by 3");
//如果使用RuntimeException,则可以直接抛出,并不需要再配置文件中配置"-MyException"参数
//因为RuntimeException Spring会自动进行回滚,而非RuntimeException出现,如果不配置参数,spring则会提交
}else...{
this.getSqlMapClientTemplate().insert("insertHistory",history);
}
}
public List getAllAccount() ...{
return this.getSqlMapClientTemplate().queryForList("getAllAccount");
}
}
import java.sql.SQLException;
import java.util.List;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
public class TestDAO extends SqlMapClientDaoSupport implements IDAO ...{
public List getAllHistory() ...{
return this.getSqlMapClientTemplate().queryForList("getAllHistory");
}
public void insertAccount(Account account) ...{
this.getSqlMapClientTemplate().insert("insertAccount",account);
}
public void insertHistory(History history,int count) throws MyException ...{
if(count%3==0)...{
//当count能被三整除时,模拟错误,促使事务回滚
throw new MyException("divide by 3");
//如果使用RuntimeException,则可以直接抛出,并不需要再配置文件中配置"-MyException"参数
//因为RuntimeException Spring会自动进行回滚,而非RuntimeException出现,如果不配置参数,spring则会提交
}else...{
this.getSqlMapClientTemplate().insert("insertHistory",history);
}
}
public List getAllAccount() ...{
return this.getSqlMapClientTemplate().queryForList("getAllAccount");
}
}
service实现:
package ch12.transaction.declare;
import java.util.List;
public class AccountManagerImpl implements AccountManager ...{
public List getAllHistory() ...{
return testDAO.getAllHistory();
}
private TestDAO testDAO;
public List getAllAccount() ...{
return testDAO.getAllAccount();
}
public TestDAO getTestDAO() ...{
return testDAO;
}
public void setTestDAO(TestDAO testDAO) ...{
this.testDAO = testDAO;
}
public void createAccount(Account account,History history,int count) throws MyException...{
testDAO.insertAccount(account);
testDAO.insertHistory(history,count);
}
}
import java.util.List;
public class AccountManagerImpl implements AccountManager ...{
public List getAllHistory() ...{
return testDAO.getAllHistory();
}
private TestDAO testDAO;
public List getAllAccount() ...{
return testDAO.getAllAccount();
}
public TestDAO getTestDAO() ...{
return testDAO;
}
public void setTestDAO(TestDAO testDAO) ...{
this.testDAO = testDAO;
}
public void createAccount(Account account,History history,int count) throws MyException...{
testDAO.insertAccount(account);
testDAO.insertHistory(history,count);
}
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>1234</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/spring</value>
</property>
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<!-- 此处应注入ibatis配置文件,而非sqlMap文件,否则会出现“there is no statement.....异常” -->
<property name="configLocation">
<value>ch12/transaction/declare/sqlMapConfig.xml</value>
</property>
</bean>
<bean id="testDAO" class="ch12.transaction.declare.TestDAO">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="sqlMapClient">
<ref bean="sqlMapClient"/>
</property>
</bean>
<bean id="managerTarget" class="ch12.transaction.declare.AccountManagerImpl">
<property name="testDAO">
<ref local="testDAO"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="manager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target">
<ref bean="managerTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="create*">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,-MyException</prop>
</props>
</property>
</bean>
</beans>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>1234</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/spring</value>
</property>
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<!-- 此处应注入ibatis配置文件,而非sqlMap文件,否则会出现“there is no statement.....异常” -->
<property name="configLocation">
<value>ch12/transaction/declare/sqlMapConfig.xml</value>
</property>
</bean>
<bean id="testDAO" class="ch12.transaction.declare.TestDAO">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="sqlMapClient">
<ref bean="sqlMapClient"/>
</property>
</bean>
<bean id="managerTarget" class="ch12.transaction.declare.AccountManagerImpl">
<property name="testDAO">
<ref local="testDAO"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="manager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target">
<ref bean="managerTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="create*">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,-MyException</prop>
</props>
</property>
</bean>
</beans>
特别说明:我们在指定目标方法中允许抛出异常,同时我们也定义当异常发生时捕获代理应该进行何种操作,默认情况下,如果RuntimeException抛出,事务管理器进行回滚,如果checked exception抛出,则提交事务,但我们可以通过声明改变这以腥味,如果在异常前追加“-”则代理铺货异常时会自动回滚,如果前缀时"+"则代理将提交事务,如本文中的-MyException,默认情况下MyException会促使事务提交,我们加了前缀“-”,则代理捕获此异常时会进行回滚
测试代码:
package ch12.transaction.declare;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.sql.SQLException;
public class Test ...{
/** *//**
* @param args
*/
public static void main(String[] args) ...{
ApplicationContext context=new ClassPathXmlApplicationContext("ch12/transaction/declare/applicationContext.xml");
AccountManager manager=(AccountManager)context.getBean("manager");
int count=0;
for (int i = 1; i <= 10; i++) ...{
count=i;
Account account=new Account(String.valueOf(count),"name1");
History history=new History(String.valueOf(count),"name1",account);
try ...{
manager.createAccount(account, history,count);
} catch (MyException e) ...{
System.out.println(e.getMessage());
}
}
System.out.println("account data:");
List result=manager.getAllAccount();
for (Object acc : result) ...{
System.out.println(((Account)acc).getId());
}
System.out.println("history data:");
List result1=manager.getAllHistory();
for (Object acc1 : result1) ...{
System.out.println(((History)acc1).getId());
}
}
}
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.sql.SQLException;
public class Test ...{
/** *//**
* @param args
*/
public static void main(String[] args) ...{
ApplicationContext context=new ClassPathXmlApplicationContext("ch12/transaction/declare/applicationContext.xml");
AccountManager manager=(AccountManager)context.getBean("manager");
int count=0;
for (int i = 1; i <= 10; i++) ...{
count=i;
Account account=new Account(String.valueOf(count),"name1");
History history=new History(String.valueOf(count),"name1",account);
try ...{
manager.createAccount(account, history,count);
} catch (MyException e) ...{
System.out.println(e.getMessage());
}
}
System.out.println("account data:");
List result=manager.getAllAccount();
for (Object acc : result) ...{
System.out.println(((Account)acc).getId());
}
System.out.println("history data:");
List result1=manager.getAllHistory();
for (Object acc1 : result1) ...{
System.out.println(((History)acc1).getId());
}
}
}
结果:
divide by 3
divide by 3
divide by 3
account data:
1
10
2
4
5
7
8
history data:
1
10
2
4
5
7
8
可以看到,能被三整除的操作,account虽然正确,但由于history失败,所以,两边数据保持了一致性
- 《Pro Spring》学习笔记之声明式事务
- 《Pro Spring》学习笔记之JMS的事务控制
- spring学习笔记(21)——声明式事务
- spring声明式事务策略 aop拦截-学习笔记
- Spring 学习笔记(八) 声明式事务
- Spring事务之声明式事务
- spring hibernate 声明式事务配置笔记
- 《Pro Spring》学习笔记之集合注入
- 《Pro Spring》学习笔记之依赖解析
- 《Pro Spring》学习笔记之自动装配
- 《Pro Spring》学习笔记之依赖检查
- 《Pro Spring》学习笔记之InitializingBean
- 《Pro Spring》学习笔记之PropertyEditor
- 《Pro Spring》学习笔记之ApplicationContext国际化
- Spring声明式事务之MathAlwaysTransactionAtttirbuteSource使用
- Spring声明式事务之NameMatchAtttirbuteSource使用
- Spring声明式事务之NameMatchAtttirbuteSource使用
- Spring 源代码阅读之声明式事务
- 丁磊:那时候我们除了会写软件 什么也不会做
- javaw和* Could not find the main class. Program will exit!
- Hooking into NDIS and TDI-part 1
- 自己写的加密字符串、数字、日期的类(VB.net)
- css学习笔记(1)加入方法 文本属性 颜色和背景
- 《Pro Spring》学习笔记之声明式事务
- AOP的四种主要Java实现方式
- Struts原理与实践
- Hibernate Gossip: 複合主鍵(二)
- .Net 2.0 新功能:Parital Classes(分部类)
- 报名网络考试了
- G.711编码
- linux的c编程技巧
- 8月份开基飙升 股票基金最赚钱