事务的基本原理
Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交,那在没有Spring帮我们管理事务之前,我们要怎么做。
Connection conn = DriverManager.getConnection();
try {
conn.setAutoCommit(false); //将自动提交设置为false
执行CRUD操作
conn.commit(); //当两个操作成功后手动提交
} catch (Exception e) {
conn.rollback(); //一旦其中一个操作出错都将回滚,所有操作都不成功
e.printStackTrace();
} finally {
conn.colse();
}
事务是一系列的动作,一旦其中有一个动作出现错误,必须全部回滚,系统将事务中对数据库的所有已完成的操作全部撤消,滚回到事务开始的状态,避免出现由于数据不一致而导致的接下来一系列的错误。事务的出现是为了确保数据的完整性和一致性,在目前企业级应用开发中,事务管理是必不可少的。
Spring事务管理
Spring事务管理的核心接口是PlatformTransactionManager
事务管理器接口通过getTransaction(TransactionDefinition definition)方法根据指定的传播行为返回当前活动的事务或创建一个新的事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。在TransactionDefinition接口中定义了它自己的传播行为和隔离级别。
除去常量,主要的方法有:
int getIsolationLevel();// 返回事务的隔离级别
String getName();// 返回事务的名称
int getPropagationBehavior();// 返回事务的传播行为
int getTimeout(); // 返回事务必须在多少秒内完成
boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
@Transactional的使用
回滚规则:
Spring事务的传播属性
由上图可知,Spring定义了7个以PROPAGATION_开头的常量表示它的传播属性。
Spring事务的隔离级别
调用PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一个实现
TransactionStatus接口
主要的方法有:
void flush();//如果适用的话,这个方法用于刷新底层会话中的修改到数据库,例如,所有受影响的Hibernate/JPA会话。
boolean hasSavepoint(); // 是否有恢复点
boolean isCompleted();// 是否已完成
boolean isNewTransaction(); // 是否是新的事务
boolean isRollbackOnly(); // 是否为只回滚
void setRollbackOnly(); // 设置为只回滚
可以看出返回的结果是一些事务的状态,可用来检索事务的状态信息。
编程式事务:
所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
声明式事务:
管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。
声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。
配置类:
@Configuration
@ComponentScan("com.enjoy.cap11")
@EnableTransactionManagement //开启事务管理功能,对@Transactional起作用 EnableXXXX
public class Cap11MainConfig {
//创建数据源
@Bean
public DataSource dataSource() throws PropertyVetoException{
//这个c3p0封装了JDBC, dataSource接口的实现
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/t_test");
return dataSource;
}
//jdbcTemplate模板能简化增删改查的操作
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException{
return new JdbcTemplate(dataSource());
}
//注册事务管理器
@Bean
public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException{
return new DataSourceTransactionManager(dataSource());
}
}
service层:
package com.enjoy.cap11.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.enjoy.cap11.dao.OrderDao;
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Transactional
public void addOrder(){
orderDao.insert();
System.out.println("操作完成.........");
int a = 1/0;
}
}
Dao层:
package com.enjoy.cap11.dao;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class OrderDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//操作数据的方法
public void insert(){
String sql = "insert into `cst_customer` (cust_name) values(?)";
jdbcTemplate.update(sql,"xiaoyan");
}
}
测试类:
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import com.enjoy.cap10.aop.Calculator;
import com.enjoy.cap10.config.Cap10MainConfig;
import com.enjoy.cap11.config.Cap11MainConfig;
import com.enjoy.cap11.service.OrderService;
import com.enjoy.cap7.config.Cap7MainConfigOfLifeCycle;
import com.enjoy.cap8.bean.Bird;
import com.enjoy.cap8.config.Cap8MainConfig;
import com.enjoy.cap9.bean.Moon;
import com.enjoy.cap9.bean.Sun;
import com.enjoy.cap9.config.Cap9MainConfig;
import com.enjoy.cap9.dao.TestDao;
import com.enjoy.cap9.service.TestService;
public class Cap11Test {
@Test
public void test01(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap11MainConfig.class);
OrderService bean = app.getBean(OrderService.class);
bean.addOrder();
app.close();
}
}
结果: