Spring對(duì)事務(wù)的管理有豐富的支持,Spring提供了編程式配置事務(wù)和聲明式配置事務(wù):
聲明式事務(wù)有以下兩種方式
一種是使用Annotation注解的方式(官方推薦)
一種是基于Xml的方式
Annotation注解:
bean.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 連接池啟動(dòng)時(shí)的初始值 -->
<property name="initialSize" value="${initialSize}" />
<!-- 連接池的最大值 -->
<property name="maxActive" value="${maxActive}" />
<!-- 最大空閑值.當(dāng)經(jīng)過(guò)一個(gè)高峰時(shí)間后,連接池可以慢慢將已經(jīng)用不到的連接慢慢釋放一部分,一直減少到maxIdle為止 -->
<property name="maxIdle" value="${maxIdle}" />
<!-- 最小空閑值.當(dāng)空閑的連接數(shù)少于閥值時(shí),連接池就會(huì)預(yù)申請(qǐng)去一些連接,以免洪峰來(lái)時(shí)來(lái)不及申請(qǐng) -->
<property name="minIdle" value="${minIdle}" />
</bean>
<bean id="personService"
class="com.royzhou.jdbc.PersonServiceImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager" /> <!--這句話的作用是注冊(cè)事務(wù)注解處理器-->
</beans>
jdbc.properties :
driverClassName=org.gjt.mm.mysql.Driver
url=jdbc:mysql://localhost:3306/royzhou?useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
initialSize=1
maxActive=500
maxIdle=2
minIdle=1
然后對(duì)要進(jìn)行事務(wù)的方法名上寫(xiě)@Transactional就行了。
對(duì)于一些查詢工作,因?yàn)椴恍枰渲檬聞?wù)支持,我們配置事務(wù)的傳播屬性:
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
readOnly=true表示事務(wù)中不允許存在更新操作.
關(guān)于事務(wù)的傳播屬性有下面幾種配置:
REQUIRED:業(yè)務(wù)方法需要在一個(gè)事務(wù)中運(yùn)行,如果方法運(yùn)行時(shí),已經(jīng)處于一個(gè)事務(wù)中,那么加入到該事務(wù)中,否則自己創(chuàng)建一個(gè)新的事務(wù).(Spring默認(rèn)的事務(wù)傳播屬性)
NOT_SUPPORTED:聲明方法不需要事務(wù),如果方法沒(méi)有關(guān)聯(lián)到一個(gè)事務(wù),容器不會(huì)為它開(kāi)啟事務(wù),如果方法在一個(gè)事務(wù)中被調(diào)用,該事務(wù)被掛起,在方法調(diào)用結(jié)束后,原先的事務(wù)便會(huì)恢復(fù)執(zhí)行
REQUIRESNEW:不管是否存在事務(wù),業(yè)務(wù)方法總會(huì)為自己發(fā)起一個(gè)新的事務(wù),如果方法運(yùn)行時(shí)已經(jīng)存在一個(gè)事務(wù),則該事務(wù)會(huì)被掛起,新的事務(wù)被創(chuàng)建,知道方法執(zhí)行結(jié)束,新事務(wù)才結(jié)束,原先的事務(wù)才恢復(fù)執(zhí)行.
MANDATORY:指定業(yè)務(wù)方法只能在一個(gè)已經(jīng)存在的事務(wù)中執(zhí)行,業(yè)務(wù)方法不能自己發(fā)起事務(wù),如果業(yè)務(wù)方法沒(méi)有在事務(wù)的環(huán)境下調(diào)用,則容器會(huì)拋出異常
SUPPORTS:如果業(yè)務(wù)方法在事務(wù)中被調(diào)用,則成為事務(wù)中的一部分,如果沒(méi)有在事務(wù)中調(diào)用,則在沒(méi)有事務(wù)的環(huán)境下執(zhí)行
NEVER:指定業(yè)務(wù)方法絕對(duì)不能在事務(wù)范圍內(nèi)運(yùn)行,否則會(huì)拋出異常.
NESTED:如果業(yè)務(wù)方法運(yùn)行時(shí)已經(jīng)存在一個(gè)事務(wù),則新建一個(gè)嵌套的事務(wù),該事務(wù)可以有多個(gè)回滾點(diǎn),如果沒(méi)有事務(wù),則按REQUIRED屬性執(zhí)行. 注意:業(yè)務(wù)方法內(nèi)部事務(wù)的回滾不會(huì)對(duì)外部事務(wù)造成影響,但是外部事務(wù)的回滾會(huì)影響內(nèi)部事務(wù)
PersonServiceImpl.java
package com.royzhou.jdbc;
import java.util.List;
import javax.sql.DataSource;
import java.sql.Types;
import org.springframework.jdbc.core.JdbcTemplate;
public class PersonServiceImpl implements PersonService {
private JdbcTemplate jdbcTemplate;
/**
* 通過(guò)Spring容器注入datasource
* 實(shí)例化JdbcTemplate,該類(lèi)為主要操作數(shù)據(jù)庫(kù)的類(lèi)
* @param ds
*/
public void setDataSource(DataSource ds) {
this.jdbcTemplate = new JdbcTemplate(ds);
}
public void addPerson(PersonBean person) {
/**
* 第一個(gè)參數(shù)為執(zhí)行sql
* 第二個(gè)參數(shù)為參數(shù)數(shù)據(jù)
* 第三個(gè)參數(shù)為參數(shù)類(lèi)型
*/
jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
}
public void deletePerson(int id) {
jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
}
@SuppressWarnings("unchecked")
public PersonBean queryPerson(int id) {
/**
* new PersonRowMapper()是一個(gè)實(shí)現(xiàn)RowMapper接口的類(lèi),
* 執(zhí)行回調(diào),實(shí)現(xiàn)mapRow()方法將rs對(duì)象轉(zhuǎn)換成PersonBean對(duì)象返回
*/
List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
PersonBean pb = null;
if(pbs.size()>0) {
pb = pbs.get(0);
}
return pb;
}
@SuppressWarnings("unchecked")
public List<PersonBean> queryPersons() {
List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
return pbs;
}
public void updatePerson(PersonBean person) {
jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
}
}
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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 連接池啟動(dòng)時(shí)的初始值 -->
<property name="initialSize" value="${initialSize}" />
<!-- 連接池的最大值 -->
<property name="maxActive" value="${maxActive}" />
<!-- 最大空閑值.當(dāng)經(jīng)過(guò)一個(gè)高峰時(shí)間后,連接池可以慢慢將已經(jīng)用不到的連接慢慢釋放一部分,一直減少到maxIdle為止 -->
<property name="maxIdle" value="${maxIdle}" />
<!-- 最小空閑值.當(dāng)空閑的連接數(shù)少于閥值時(shí),連接池就會(huì)預(yù)申請(qǐng)去一些連接,以免洪峰來(lái)時(shí)來(lái)不及申請(qǐng) -->
<property name="minIdle" value="${minIdle}" />
</bean>
<bean id="personService"
class="com.royzhou.jdbc.PersonServiceImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 定義事務(wù)傳播屬性 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 對(duì)查詢方法不進(jìn)行事務(wù)-->
<tx:method name="query*" propagation="NOT_SUPPORTED" read-only="true"/>
<!-- 對(duì)剩余的方法進(jìn)行事務(wù)-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="transactionPointCut" expression="execution(* com.royzhou.jdbc..*.*(..))"/>
<aop:advisor pointcut-ref="transactionPointCut" advice-ref="txAdvice"/>
</aop:config>
</beans>
聯(lián)系客服