JDBC声明事务管理
Spring的声明式事务管理依赖他的aop框架来完成。施工声明式事务管理的好处是事务管理不能侵入我们开发的组件,Dao对象不会意识到正在事务管理之中。
例子:
#
packagecom.springframework.sample.jdbc.dao;
import java.util.List;
importcom.springframework.sample.jdbc.pojo.Banzu;
public interface DaoInterface {
publicvoid saveBanzu(Banzu banzu);
publicList
}
#
package com.springframework.sample.jdbc.dao;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import com.springframework.sample.jdbc.pojo.Banzu;
import com.springframework.sample.jdbc.pojo.BanzuRowMapper;
public classDaoServiceImpl2 implements DaoInterface {
private JdbcTemplate jdbcTemplate;
public voidsetDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public void saveBanzu(Banzu banzu) {
// TODO Auto-generated method stub
jdbcTemplate.update("insert intobanzu(BANZU_NAME,FUZEREN,BANZUCHENGYUAN) values(?,?,?)", newObject[]{banzu.getBanZu(),banzu.getFuZeRen(),banzu.getChengYuan()});
}
@Override
public List
// TODO Auto-generated method stub
List
return list;
}
}
#
package com.springframework.sample.jdbc.pojo;
public classBanzu {
private String banZu;
private String fuZeRen;
private String chengYuan;
public Banzu(){}
public Banzu(String banZu,String fuZeRen,String chengYuan){
this.banZu = banZu;
this.fuZeRen = fuZeRen;
this.chengYuan = chengYuan;
}
//set get
}
#
package com.springframework.sample.jdbc.pojo;
import java.sql.ResultSet;
import java.sql.SQLException;
importorg.springframework.jdbc.core.RowMapper;
public class BanzuRowMapperimplements RowMapper
@Override
publicBanzu mapRow(ResultSet rs, int rowNum) throws SQLException {
//TODO Auto-generated method stub
Banzubanzu = newBanzu(rs.getString("BANZU_NAME"),rs.getString("FUZEREN"),rs.getString("BANZUCHENGYUAN"));
returnbanzu;
}
}
#test
public static void main(String []args){
ApplicationContextcontext= newClassPathXmlApplicationContext("spring-config.xml");
Banzubanzu= newBanzu();
banzu.setBanZu("ban3301");
banzu.setChengYuan("du331,zhao332,long333");
banzu.setFuZeRen("dudu333");
DaoInterfaceserv=(DaoInterface) context.getBean("userDAOProxy");
serv.saveBanzu(banzu);;
List
for(int i=0;i<list.size();i++){
Banzutemp_banzu= list.get(i);
System.out.println("banzu name:"+temp_banzu.getBanZu()+" ,fuzeren:"+temp_banzu.getFuZeRen()+" ,chengyuan:"+temp_banzu.getChengYuan());
}
}
#
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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName" value ="oracle.jdbc.driver.OracleDriver"/>
<property name="url"value ="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name= "username"value = "scott" />
<property name= "password"value = "adu636"/>
bean>
<bean id= "jdbcTemplate2" class ="com.springframework.sample.jdbc.dao.DaoServiceImpl2">
<property name="dataSource"ref = "dataSource"/>
bean>
<bean id="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name = "dataSource" ref = "dataSource" />
bean>
<bean id="userDAOProxy" class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>com.springframework.sample.jdbc.dao.DaoInterfacevalue>
list>
property>
<property name="target" ref="jdbcTemplate2"/>
<property name="transactionManager" ref ="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key ="save*" >PROPAGATION_REQUIREDprop>
props>
property>
bean>
beans>
TransactionPRoxyFactoryBean需要一个transactionManager,由于这里使用的DataSourceTransactionManager,TransactionProxyFactoryBean是一个代理对象,target属性指明被代理的对象也就是id为jdbcTemplate2的类,事务管理会自动的介入指定的方法前后,transactionAttributes属性指定”save*”表示指定的方法名称已save开头的都要纳入事务管理中,如果发生错误,则所有先前的操作自动回撤,否则正常提交。
在save*等方法上指定了PROPAGATION_REQUIRED,表示在目前的事务中执行操作,如果事务不存在,就新建一个。这个常数在之前的TransactionDefinition中已经介绍过了。
这里也可以加入多个中间用逗号分开,如
PROPAGATION_REQUIRED,readOnly,-MyCheckedException
MyCheckedException前面加入了-号,表示发生指定异常时撤销操作,如果前面是+号,表示发生异常时立即提交。
由于jdbcTemplate2被usersDAOProxy代理了,所以要做的是取得userDAOProxy
我们可以通过设置不同的TransactionInterceptor来得到更多的管理细节。
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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName" value ="oracle.jdbc.driver.OracleDriver"/>
<property name="url"value ="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name= "username"value = "scott" />
<property name= "password"value = "adu636"/>
bean>
<bean id= "jdbcTemplate" class ="com.springframework.sample.jdbc.dao.DaoServiceImpl">
<property name="dataSource"ref = "dataSource"/>
bean>
<bean id= "jdbcTemplate2" class ="com.springframework.sample.jdbc.dao.DaoServiceImpl2">
<property name="dataSource"ref = "dataSource"/>
bean>
<bean id="service1" class="com.springframework.sample.jdbc.service.ServiceSample1">
<property name="daoIntBanzu"ref ="jdbcTemplate" />
bean>
<bean id="service2"class="com.springframework.sample.jdbc.service.ServiceSample2">
<property name="daoIntBanzu"ref ="jdbcTemplate2" />
bean>
<bean id="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name = "dataSource" ref = "dataSource" />
bean>
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name ="transactionManager" ref ="transactionManager"/>
<property name ="transactionAttributeSource" value="com.springframework.sample.jdbc.dao.DaoInterface.select*=PROPAGATION_REQUIRED"/>
bean>
<bean id="userDAOProxy" class ="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>com.springframework.sample.jdbc.dao.DaoInterfacevalue>
list>
property>
<property name="target" ref="jdbcTemplate2"/>
<property name ="interceptorNames" >
<list>
<value>transactionInterceptorvalue>
list>
property>
bean>
beans>
这样也就是将sql操作和事务完全分开了,需要的时候只需要设置一下配置文件,不需要的时候可以直接修改配置文件,耦合性大大降低。
一个dataSource,一个DAOImpl,(JDBCTemplate)
这里首先需要一个transactionManager(相当于advice);然后利用一个TransactionInterceptor拦截器(advisor),加入相应的pointcut,并且注入事务;最后是有proxyfactorybean,proxyInterface,target,interceptorNames等设置代理,之后只需要通过该代理即可获得被代理的对象。
5.3.5TransactionAttributeSource、TransactionAttribute
在transactionProxyFactoryBean上有setTransactionAttributeSource与方法setTransactionAttribute()方法,他们是用来设置事务属性。
Method的key和transactionattribute的相对应。
<property name="transactionAttributes">
<props>
<prop key ="save*" >PROPAGATION_REQUIREDprop>
<prop key ="select*" >PROPAGATION_REQUIREDprop>
props>
property>
可以根据传递给它的method的实例,与class实例,决定返回一个transactionattribute,这里有一个实现org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource,它对于每一个方法指定都会应用事务,transactionattribute实例的默认传播行为时PROPAGATION_REQUIRED,隔离层级为ISOLATION_DEFAULT,为默认底层数据库的隔离层级。
这里如:
也可以使用org.springframework.transaction.interceptor.DefaultTransactionAttribute,并设置自己的策略,之后设置给TransactionAttributeSource
如:
其他设置如上
也可以使用如下来指定某些方法要应用事务,以及应用事务的策略。如org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource
K这里只要是save开头的方法都会使用事务。
在指定事务策略时,指定的格式如下:
传播行为,隔离层级,只读,+异常,-异常
传播行为必须要设置,其他的可以省略。
简单的设置是仅设置TransactionProxyFactoryBean,并在他的transactionAttributes中直接设置应用事务的方法及事务策略。
如:
<bean id="userDAOProxy2" class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>com.springframework.sample.jdbc.dao.DaoInterfacevalue>
list>
property>
<property name="target" ref="jdbcTemplate2"/>
<property name ="transactionManager" ref ="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIREDprop>
<prop key ="select*" >PROPAGATION_REQUIREDprop>
props>
property>
bean>
也可以直接指定TransactionInterceptor,以便获得更多的控制。
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name ="transactionManager" ref ="transactionManager"/>
<property name ="transactionAttributeSource" value="com.springframework.sample.jdbc.dao.DaoInterface.select*=PROPAGATION_REQUIRED"/>
bean>
<bean id="userDAOProxy" class ="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>com.springframework.sample.jdbc.dao.DaoInterfacevalue>
list>
property>
<property name="target" ref="jdbcTemplate2"/>
<property name ="interceptorNames" >
<list>
<value>transactionInterceptorvalue>
list>
property>
bean>
究竟选择哪种方式实现事务,可以根据实际情况选择。
5.3.6 spring2.0声明式事务管理
声明式事务管理可以分为基于xmlschema的和基于annotation注解形式的两种。
(一)基于xmlschema的方式
(1) 基于xmlschema的声明式事务管理,可以依赖于
Dhi
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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
….
加粗的部分需要注意,这里涉及到相应的内容aop,tx的名称空间声明。
对于事务是系统层面的服务,也就是一个Aspect,具体来说就是一个advice(一个服务),可以使用
具体的配置如下:
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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName" value ="oracle.jdbc.driver.OracleDriver"/>
<property name="url"value ="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name= "username"value = "scott" />
<property name= "password"value = "adu636"/>
bean>
<bean id= "jdbcTemplate2" class ="com.springframework.sample.jdbc.dao.DaoServiceImpl2">
<property name="dataSource"ref = "dataSource"/>
bean>
<bean id="service2"class="com.springframework.sample.jdbc.service.ServiceSample2">
<property name="daoIntBanzu"ref ="jdbcTemplate2" />
bean>
<bean id="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name = "dataSource" ref = "dataSource" />
bean>
<tx:advice id="txAdvice"transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name ="select*" read-only="true"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="userDAOPointcut" expression="execution(*com.springframework.sample.jdbc.dao.DaoInterface.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="userDAOPointcut"/>
aop:config>
beans>
这里配置了一个数据源DataSource,两个DAO,(jdbcTemplate),两个service,一个transactionManager,另外是一个
这里需要还需要aspectJweaver.jar需要会报错,关于pointcut的错误。
这里只需要如下操作即可获得相应的数据库操作和相应的事务处理
ApplicationContext context = newClassPathXmlApplicationContext("spring-config2.xml");
ServiceSample2serv=(ServiceSample2) context.getBean("service2");
List
for(int i=0;i<list.size();i++){
Banzutemp_banzu= list.get(i);
System.out.println("banzu name:"+temp_banzu.getBanZu()+" ,fuzeren:"+temp_banzu.getFuZeRen()+" ,chengyuan:"+temp_banzu.getChengYuan());
}
。
在
(二)基于注解annotation的方式
1方法是使用@Transactional来标示,例如可以直接改写
#DAO:
package com.springframework.sample.jdbc.dao;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.springframework.sample.jdbc.pojo.Banzu;
import com.springframework.sample.jdbc.pojo.BanzuRowMapper;
public classDaoServiceImpl3 implements DaoInterface {
private JdbcTemplate jdbcTemplate;
public voidsetDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Transactional(propagation=Propagation.REQUIRED)
@Override
public void saveBanzu(Banzu banzu) {
// TODO Auto-generated method stub
jdbcTemplate.update("insert intobanzu(BANZU_NAME,FUZEREN,BANZUCHENGYUAN) values(?,?,?)", newObject[]{banzu.getBanZu(),banzu.getFuZeRen(),banzu.getChengYuan()});
}
@Transactional(readOnly=true)
@Override
public List
// TODO Auto-generated method stub
List
return list;
}
}
#spring-config.xml
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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName" value ="oracle.jdbc.driver.OracleDriver"/>
<property name="url"value ="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name= "username"value = "scott" />
<property name= "password"value = "adu636"/>
bean>
<bean id= "jdbcTemplate3" class ="com.springframework.sample.jdbc.dao.DaoServiceImpl3">
<property name="dataSource"ref = "dataSource"/>
bean>
<bean id="service2"class="com.springframework.sample.jdbc.service.ServiceSample2">
<property name="daoIntBanzu"ref ="jdbcTemplate3" />
bean>
<bean id="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name ="dataSource" ref ="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
beans>
测试的时候可以直接获得service2,然后进行相应业务处理。
对@Transactional(isolation=Isolation.DEFAULT)
@Transactionl(timeout=-1)
具体可以参考设置 ( TransactionDefinition 中定义)