事務:是一組原子操作的工作單元,要麼全部成功,要麼全部失敗
Spring管理事務方式:
可以清楚的控制事務的邊界,事務控制粒度化細(編程的方式)
事務相關API不用介入程序之中,將事務管理與實際業務代碼解耦合(配置XML的方式)
Spring提供兩種方式實現編程式的事務管理:
大致步驟:
package com.pb.transaction.demo; import javax.sql.DataSource; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; /** * 使用TransactionManager事務管理 * 缺點:侵入代碼 * 優點:控制度細粒度 */ public class TransactionManagerDemo { public static void main(String[] args) { ClassPathXmlApplicationContext cpx=new ClassPathXmlApplicationContext("applicationContext.xml"); //獲取platform對象 PlatformTransactionManager ptm=(PlatformTransactionManager) cpx.getBean("transactionManager"); //事務定義器 DefaultTransactionDefinition dtd=new DefaultTransactionDefinition(); //設置事務定義器的行為 dtd.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); //事務狀態通過事務管理器創建 TransactionStatus ts=ptm.getTransaction(dtd); //進行事務 try { //獲取數據源 DataSource ds=(DataSource) cpx.getBean("dataSource"); //創建JDBCTemplacte JdbcTemplate jt=new JdbcTemplate(ds); //執行更新或者插入等操作 jt.update("insert into person values(11,'TTM',23)"); jt.update("update person set name='張王八' where id=7"); ptm.commit(ts); System.out.println("==========="); } catch (Exception e) { ptm.rollback(ts); System.out.println("撤消======="); e.printStackTrace(); } } }
大致步驟:
package com.pb.transaction.demo; import javax.sql.DataSource; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; /** * 使用TransactionTemplate事務管理 缺點:侵入代碼 優點:控制度細粒度 */ public class TransactionTeplateDemo { public static void main(String[] args) { ClassPathXmlApplicationContext cpx = new ClassPathXmlApplicationContext( "applicationContext.xml"); // 獲取platform對象 PlatformTransactionManager ptm = (PlatformTransactionManager) cpx .getBean("transactionManager"); // 事務模版 TransactionTemplate tt = new TransactionTemplate(ptm); // 獲取數據源 DataSource ds = (DataSource) cpx.getBean("dataSource"); // 創建JDBCTemplacte final JdbcTemplate jt = new JdbcTemplate(ds); // 進行事務回調函數 tt.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus arg0) { // 執行更新或者插入等操作 jt.update("insert into person values(17,'TOM',23)"); jt.update("update person set name='李四3' where id=4"); } }); } }
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <!-- 聲明數據源 org.springframework.jdbc.datasource.DriverManagerDataSource/com.mchange.v2.c3p0.ComboPooledDataSource--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!--驅動 --> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <!--url --> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> <!--用戶名 --> <property name="username" value="accp"/> <!--密碼 --> <property name="password" value="accp"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> </beans>
主要通過AOP功能實現
不需要修改原有的類
使用TransationProxyFactoryBean指定要介入的事務以及方法
實體類:數據庫中有與之相對應的表
package com.pb.entity; public class Person { private Long id; private String name; private Integer age; 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; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
dao和實現類
package com.pb.dao; import java.util.List; import com.pb.entity.Person; public interface PersonDao { public int insert(Person p); public int batchInsert(List<Person> persons); } //實現類 package com.pb.dao.impl; import java.util.List; import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; import com.pb.dao.PersonDao; import com.pb.entity.Person; public class PersonDaoImpl implements PersonDao { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource ds){ jdbcTemplate=new JdbcTemplate(ds); } @Override public int insert(Person p) { String sql="insert into person values(?,?,?)"; Object [] params={p.getId(),p.getName(),p.getAge()}; return jdbcTemplate.update(sql,params); } @Override public int batchInsert(List<Person> persons) { int count=0; for (Person person : persons) { insert(person); count++; } return count; } }
測試類
package com.pb.transation.aop.demo; import java.util.ArrayList; import java.util.List; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.pb.dao.PersonDao; import com.pb.entity.Person; public class FirstAOPTransationDemo { public static void main(String[] args) { ClassPathXmlApplicationContext cpx=new ClassPathXmlApplicationContext("applicationContext.xml"); //這裡調用代理的類 PersonDao personDao=(PersonDao) cpx.getBean("personDaoProxy"); Person p1=new Person(); p1.setId(new Long(28)); p1.setName("朱雀"); p1.setAge(199); Person p2=new Person(); p2.setId(new Long(29)); p2.setName("玄武"); p2.setAge(150); List<Person> persons=new ArrayList<Person>(); persons.add(p1); persons.add(p2); int count=personDao.batchInsert(persons); System.out.println("更新了,"+count+"條記錄"); } }
applicationContext.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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <!-- 聲明數據源 org.springframework.jdbc.datasource.DriverManagerDataSource/com.mchange.v2.c3p0.ComboPooledDataSource--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!--驅動 --> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <!--url --> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> <!--用戶名 --> <property name="username" value="accp"/> <!--密碼 --> <property name="password" value="accp"/> </bean> <!--接口實現類 --> <bean id="personDao" class="com.pb.dao.impl.PersonDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="personDaoProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!--指定接口 --> <property name="proxyInterfaces" > <list> <value>com.pb.dao.PersonDao</value> </list> </property> <!-- 管理的目標 --> <property name="target" ref="personDao"/> <!--注入事務管理 --> <property name="transactionManager" ref="transactionManager"></property> <!--事務管理的方法 和方式 --> <property name="transactionAttributes"> <props> <prop key="batch*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </beans>
聲明式事務以方法為邊界,簡單的講,一個方法被看成一個事務
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: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-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <!-- 聲明數據源 org.springframework.jdbc.datasource.DriverManagerDataSource/com.mchange.v2.c3p0.ComboPooledDataSource--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!--驅動 --> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <!--url --> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> <!--用戶名 --> <property name="username" value="accp"/> <!--密碼 --> <property name="password" value="accp"/> </bean> <!--接口實現類 --> <bean id="personDao" class="com.pb.dao.impl.PersonDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!--事務管理的類 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--指明事務管理 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--指定方法和方式 --> <tx:attributes> <tx:method name="batch*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <!--切入點 --> <aop:pointcut expression="execution(* com.pb.dao.PersonDao.*(..) )" id="mypoint"/> <!--關切入點和切入對象事務 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint"/> </aop:config> </beans>
package com.pb.dao.impl; 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.pb.dao.PersonDao; import com.pb.entity.Person; //在要管理的類下加上@transactional @Transactional public class PersonDaoImpl implements PersonDao { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource ds){ jdbcTemplate=new JdbcTemplate(ds); } @Override public int insert(Person p) { String sql="insert into person values(?,?,?)"; Object [] params={p.getId(),p.getName(),p.getAge()}; return jdbcTemplate.update(sql,params); } //在要管理的方法下加上屬性propagation=Propagation.REQUIRED @Transactional(propagation=Propagation.REQUIRED) public int batchInsert(List<Person> persons) { int count=0; for (Person person : persons) { insert(person); count++; } return count; } }
配置文件中加入一條
<?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: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-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <!-- 聲明數據源 org.springframework.jdbc.datasource.DriverManagerDataSource/com.mchange.v2.c3p0.ComboPooledDataSource--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!--驅動 --> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <!--url --> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> <!--用戶名 --> <property name="username" value="accp"/> <!--密碼 --> <property name="password" value="accp"/> </bean> <!--接口實現類 --> <bean id="personDao" class="com.pb.dao.impl.PersonDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!--事務管理的類 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--指明注解方式的事務管理器 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>