Spring(九)Spring对事务的支持
一、对事务的支持
事务:是一组原子操作的工作单元,要么全部成功,要么全部失败
Spring管理事务方式:
- JDBC编程事务管理:--可以控制到代码中的行
可以清楚的控制事务的边界,事务控制粒度化细(编程的方式)
- JDBC声明事务管理---可以控制到方法
事务相关API不用介入程序之中,将事务管理与实际业务代码解耦合(配置XML的方式)
二、JDBC编程事务管理
Spring提供两种方式实现编程式的事务管理:
- 实现PlatformTransactionManager接口
- 使用TransactionTemplate模式
2.1、实现PlatformTransactionManager接口
大致步骤:
- 指定PlatformTransactionManager的实现类
- 定义事务TransactionDefinition
- 将事务定义传送给TransactionStatus
- 将欲进行的事务用try..catch语句封起来
- 如果事务出错,调用PlatformTransactionManager的rollback方法
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(); } } }
2.2、使用TransactionTemplate模式
大致步骤:
- 需要封装一个TransactionManager
- 创建事务回滚类
- 执行TransactionManager的execute()方法
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"); } }); } }
2.3、编程事务配置
<?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>
三、JDBC声明事务管理
主要通过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中事务的属性:
- 传播行为(Propagation Behavior)
- 隔离级别(Lsolation Level)
- 只读提示(Rean-only Hints)
- 事务超时期限(The Transaction Timeout period)
4.1、传播行为
4.2、隔离级别
五、Spring2.0后声明式事务管理:基于XMLSchema
步骤:
- 加入相关的XML命名空间
- 使用<tx:advice>标签指定Advice
- 使用<aop:config>标签配置事务管理
<?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>