Spring 事务归纳
Spring transaction
什么是事务
A用户向B用户转帐100,第一步要从A帐户扣出100,第二步要将B帐户加上100。其中无论是第一步失败,还是第二步失败。都应该将A、B帐户的余额保持和转帐操作之前一致。
事务就是一系列相关联操作的集合,一个事务可以是多个步骤组成,如果一个步骤失败,那么整个流程都应该回滚到初始状态。
事务的四个特性
- 原子性(Atomicity) 一个事务是一个整体,无论有多少个步骤组成,要么所有步骤都成功,要么所有步骤都失败。
- 一致性(Consistency) 一个事务完成(无论是成功还是失败),所有的业务都应该处于一致的状态,不应该部分步骤成功,部分步骤失败,显示中的数据一致性不会被破坏。
- 隔离性(Isolation) 多个事务处理相同的数据的时候,事务间应该是相互隔离的,防止数据损坏。
- 持久性(Durability) 一旦事务完成,无论系统发生什么异常,结果都不应该受到影响,通常事务的结果被写入到数据库中。
Spring处理事务的核心接口
Spring涉及到事务管理的核心接口相互关系如下
Spring并没有直接提供事务管理的实现,而是提供了一个接口PlatformTransactionManager。具体的实现依赖项目中所使用的持久化接口。
PlatformTransactionManager 定义了所有的具体实现类必须要有的方法
- 通过TransactionDefinition获取TransactionStatus
- commit 提交事务
- rollback 回滚事务
TransactionDefinition接口
TransactionDefinition主要包含的属性和方法
- 事务的传播级别
- 事务的隔离级别
- 事务超时
- 只读状态
TransactionStatus接口
以上可以看到事务的具体实现可以有四种
- 使用JDBC事务,添加配置的方式为
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
- 使用Hibernate事务,添加配置的方式为
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
- 使用JAVA持久化API事务(JPA)
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
- JAVA原生API事务 如果没有使用以上任何一个实现,或者是使用了多个事务管理源(使用了多个数据源)
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:/TransactionManager" />
</bean>
事务属性的定义
事务的传播级别
在上面TransactionDefinition接口中可以看到,一共有7个级别
- PROPAGATION_REQUIRED 当前方法必须运行在事务中,已经有事务,则在当前事务中;没有事务,会新建一个事务。
- PROPAGATION_SUPPORTS 当前方法可以运行在事务中,已经有事务,则在当前事务中;没有事务,不会创建新事务。
- PROPAGATION_MANDATORY 当前方法必须运行在事务中,如果没有事务,会抛出异常。
- PROPAGATION_REQUIRES_NEW 当前方法必须运行在自己的事务中,已经有事务,则将当前事务挂起,新建一个事务;没有事务,会新建一个事务。(如果使用JTATransactionManager的话,则需要访问TransactionManager)
- PROPAGATION_NOT_SUPPORTED 当前方法不支持运行在事务中,已经有事务,将当前事务挂起(如果使用JTATransactionManager的话,则需要访问TransactionManager)
- PROPAGATION_NEVER 当前方法不能运行在事务中,已经有事务,会抛出异常。
- PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样
原生JDBC的事务
代码展示了如何通过将Connection设置成conn.setAutoCommit(false),然后在代码执行成功之后再通过conn.commit()方法来提交,或者是conn.rollback()来回滚操作。
public class Demo {
public static void main(String[] args) {
test1();
}
public static Connection getConn() {
String driver = "oracle.jdbc.OracleDriver";
String url = "jdbc:oracle:thin:@xxxxx";
String username = "username";
String password = "password";
Connection conn = null;
try{
Class.forName(driver);
conn = (Connection) DriverManager.getConnection(url, username, password);
}catch (Exception e){
e.printStackTrace();
}
return conn;
}
public static void test1() {
Connection conn = getConn();
Random random = new Random();
int id = random.nextInt(100);
System.out.println("--------id is "+id+"--------");
String sql = "insert into test (ID,NAME) values(?,?)";
PreparedStatement pstmt;
try {
conn.setAutoCommit(false);
pstmt = (PreparedStatement) conn.prepareStatement(sql);
pstmt.setString(1, id+"");
pstmt.setString(2, "haha");
pstmt.executeUpdate();
if(id%2==0){
System.out.println("--------even num--------");
int error = 9/0;
}else{
System.out.println("--------odd num--------");
}
conn.commit();
pstmt.close();
conn.close();
System.out.println("----------commit-------------");
} catch (Exception e) {
try {
conn.rollback();
System.out.println("----------rollback-------------");
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
事务的传播级别详解—REQUIRED
- 场景1
class Demo{
@Transactional(propagation = Propagation.REQUIRED)
methodB();
}
如果此时单独调用methodB(),刚进入方法的时候,是没有事务的;然后由于注解上的事务传播级别是REQUIRED;所以此时Spring会默认创建一个事务,将methodB()内的所有操作放在一个事务内。
- 场景2
class Demo{
@Transactional(propagation = Propagation.REQUIRED)
methodA(){
methodB();
}
@Transactional(propagation = Propagation.REQUIRED)
methodB();
}
此时如果调用methodA(),Spring同样会为methodA()上新建一个事务,然后再调用methodB()时,由于已经存在事务,此时methodB()将在已有的事务中运行。Spring会保证methodB()内所有操作数据库使用的连接是和methodA()中使用到的数据库连接是同一个。
事务的传播级别详解—SUPPORTS
- 场景1
class Demo{
@Transactional(propagation = Propagation.SUPPORTS)
methodB();
}
单独调用methodB(),由于默认没有事务,所以方法就不会有事务的存在。
- 场景2
class Demo{
@Transactional(propagation = Propagation.REQUIRED)
methodA(){
methodB();
}
@Transactional(propagation = Propagation.SUPPORTS)
methodB();
}
此时如果调用methodA(),Spring同样会为methodA()上新建一个事务,然后再调用methodB()时,由于已经存在事务,此时methodB()将在已有的事务中运行。
事务的传播级别详解—MANDATORY
- 场景1
class Demo{
@Transactional(propagation = Propagation.MANDATORY)
methodB();
}
单独调用methodB(),由于默认没有事务,此时会报错。
- 场景2
class Demo{
@Transactional(propagation = Propagation.REQUIRED)
methodA(){
methodB();
}
@Transactional(propagation = Propagation.MANDATORY)
methodB();
}
通过methodA()来调用methodB(),由于methodA()中有事务,methodB()将运行在已有的事务中。
事务的传播级别详解—REQUIRES_NEW
- 场景1
class Demo{
@Transactional(propagation = Propagation.REQUIRES_NEW)
methodB();
}
单独调用methodB(),由于默认没有事务,会新创建一个事务。
- 场景2
class Demo{
@Transactional(propagation = Propagation.REQUIRED)
methodA(){
methodB();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
methodB();
}
通过methodA()来调用methodB(),由于methodA()中有事务,methodB()将会把已有的事务挂起,新创建一个事务,methodB()将运行在新创建的事务中。methodB()和methodA()相互的运行结果不会因为对方失败而回滚,因为他们是在两个相互独立的事务中。如果要使用PROPAGATION_REQUIRES_NEW,需要使用 JtaTransactionManager作为事务管理器。
事务的传播级别详解—NEVER
方法决不能运行在事务中,如果有事务存在,则会抛出异常。
事务的传播级别详解—NESTED
- 场景1
class Demo{
@Transactional(propagation = Propagation.NESTED)
methodB();
}
单独调用methodB(),行为和Propagation.REQUIRED一样,由于默认没有事务,会新创建一个事务。
- 场景2
class Demo{
@Transactional(propagation = Propagation.REQUIRED)
methodA(){
funBefore();
methodB();
funAfter();
}
@Transactional(propagation = Propagation.NESTED)
methodB();
}
嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。
PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别
如果不存在事务,两者的行为和PROPAGATION_REQUIRES一致,都会创建一个新的事务。
如果已存在事务,两者也都会新创建一个事务。
- PROPAGATION_REQUIRES_NEW注解中,内外层事务不会相互影响,内层事务开启的时候,外层事务是挂起的,内外层事务部是用的同一个数据访问连接,可以看作两个独立的事务,任何一方失败都不会对另一方造成影响。
- PROPAGATION_NESTED注解中,内部事务和外部事务使用的是同一个数据访问连接,只是在内部事务开启之前,会创建一个Savepoint,内部事务回滚,会回滚到这个Savepoint;外部事物如果回滚,会连带内部事务一起回滚,应为内部事务完成之后并没有提交事务。
由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back.
事务的隔离级别
事务之间并发可能产生的后果
- 脏读
发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
- 不可重复读
不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
- 幻读
幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
幻读与不可重复读的区别在于, 不可重复读常指一条记录,几次的查询结果不一致。幻读常指某一查询条件的结果的个数,多次查询后结果不一致。
隔离级别 | 含义 |
---|---|
ISOLATION_DEFAULT | 使用数据库的默认隔离级别 |
ISOLATION_READ_UNCOMMITTED | 最低的隔离级别,允许读取到尚未COMMIT的数据,会导致脏读,幻读和不可重复读 |
ISOLATION_READ_COMMITTED | 允许读取并发事务已经COMMIT的事务,可以阻止脏读,但是幻读和不可重复读还会发生 |
ISOLATION_REPEATABLE_READ | 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 |
ISOLATION_SERIALIZABLE | 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的 |
只读
事务超时
为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。
回滚规则
这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚,但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
事务状态
这个接口描述的是一些处理事务提供简单的控制事务执行和查询事务状态的方法,在回滚或提交的时候需要应用对应的事务状态。
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
3 如何使用事务
3.1 编程式事务和声明式事务的区别
- 编程式事务,需要将事务控制的代码与业务逻辑写在一起,优点是可以精准的控制事务的行为、缺点就是有非业务代码侵入。
- 声明式事务,将事务的控制通过Spring AOP来实现,优点是没有代码侵入,只需要在使用事务的地方添加注解,缺点是配置复杂。
3.2 编程式事务
3.2.1 使用TransactionTemplate实现的编程式事务
TransactionTemplate tt = new TransactionTemplate(); // 新建一个TransactionTemplate
Object result = tt.execute(
new TransactionCallback(){
public Object doTransaction(TransactionStatus status){
updateOperation();
return resultOfUpdateOperation();
}
}); // 执行execute方法进行事务管理
或者是
TransactionTemplate tt = new TransactionTemplate(); // 新建一个TransactionTemplate
Object result = tt.execute(
new TransactionCallbackWithoutResult(){
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
// call dao
}
}); // 执行execute方法进行事务管理
3.2.2 使用PlatformTransactionManager实现的编程式事务
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); //定义一个某个框架平台的TransactionManager,如JDBC、Hibernate
dataSourceTransactionManager.setDataSource(this.getJdbcTemplate().getDataSource()); // 设置数据源
DefaultTransactionDefinition transDef = new DefaultTransactionDefinition(); // 定义事务属性
transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); // 设置传播行为属性
TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef); // 获得事务状态
try {
// 数据库操作
dataSourceTransactionManager.commit(status);// 提交
} catch (Exception e) {
dataSourceTransactionManager.rollback(status);// 回滚
}
3.3 配置式事务
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。
DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。
具体如下图:
3.3.1 每个Bean都有一个代理
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 配置DAO -->
<bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="userDaoTarget" />
<property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
3.3.2 所有Bean共享一个代理基类
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 配置DAO -->
<bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDao" parent="transactionBase" >
<property name="target" ref="userDaoTarget" />
</bean>
</beans>
3.3.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Dao</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<!-- 配置DAO -->
<bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
3.3.4 使用tx标签配置的拦截器
<?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/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://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:annotation-config />
<context:component-scan base-package="com.bluesky" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="interceptorPointCuts"
expression="execution(* com.bluesky.spring.dao.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="interceptorPointCuts" />
</aop:config>
</beans>
3.3.5 全注解
<?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/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://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:annotation-config />
<context:component-scan base-package="com.bluesky" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
4 一个声明式事务的实例
//todo
Spring 事务归纳的更多相关文章
- Spring事务专题(五)聊聊Spring事务到底是如何实现的
前言 本专题大纲: 本文为本专题倒数第二篇文章. 在上篇文章中我们一起学习了Spring中的事务抽象机制以及动手模拟了一下Spring中的事务管理机制,那么本文我们就通过源码来分析一下Spring中的 ...
- spring事务概念理解
1.数据并发问题 脏读 A事务读取B事务尚未提交的更新数据,并在此数据的基础上操作.如果B事务回滚,则A事务读取的数据就是错误的.即读取了脏数据或者错误数据. 不可重复组 A事务先后读取了B事务提交[ ...
- 【Java EE 学习 52】【Spring学习第四天】【Spring与JDBC】【JdbcTemplate创建的三种方式】【Spring事务管理】【事务中使用dbutils则回滚失败!!!??】
一.JDBC编程特点 静态代码+动态变量=JDBC编程. 静态代码:比如所有的数据库连接池 都实现了DataSource接口,都实现了Connection接口. 动态变量:用户名.密码.连接的数据库. ...
- Spring事务
1.@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.@Transactional 的 ...
- spring事务管理器设计思想(二)
上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当前没有事务,就新建一个事务.这是最常见 ...
- spring事务管理器设计思想(一)
在最近做的一个项目里面,涉及到多数据源的操作,比较特殊的是,这多个数据库的表结构完全相同,由于我们使用的ibatis框架作为持久化层,为了防止每一个数据源都配置一套规则,所以重新实现了数据源,根据线程 ...
- Spring事务管理的三种方式
一 .第一种:全注解声明式事务 Xml代码 复制代码 收藏代码 .<?xml version="1.0" encoding="UTF-8"?> .& ...
- spring 事务传播特性 和隔离级别
事务的几种传播特性1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务 ...
- Spring事务管理
Spring是SSH中的管理员,负责管理其它框架,协调各个部分的工作.今天一起学习一下Spring的事务管理.Spring的事务管理分为声明式跟编程式.声明式就是在Spring的配置文件中进行相关配置 ...
随机推荐
- Docker最全教程——从理论到实战(二十一)
前言 MySQL是目前最流行的开源的关系型数据库,MySQL的容器化之前有朋友投稿并且写过此块,本篇仅从笔者角度进行总结和编写. 目录 镜像说明 运行MySQL容器镜像 1.运行MySQL容器 ...
- 数据库之十一:CASE表达式
1.简单Case表达式: 基本语法: CASE <表达式> WHEN <表达式> THEN <表达式> WHEN <表达式> THEN <表达式& ...
- cobbler自动安装linux
1- cobbler简介 cobbler是一个系统启动服务boot server,可以通过pxe得方式用来快速安装.重装系统,支持安装不同linux发行版和windows. 基于python开 ...
- psp 周计划2
日期\时间 开始时间 结束时间 中断时间 净时间 活动 备注 12/3 9:00 11:30 10:30 120分钟 自习,练习 教室 14:00 16:30 15:30 80分钟 练习 中午休息 1 ...
- redis安装并设置开机启动
1.下载并上传redis安装包至linux服务器目录:/usr/local/redis. 2.解压:tar -zxvf redis-5.0.7.tar.gz 3.编译安装:make && ...
- PIE-SDK For C++栅格数据集的读写
1.功能简介 栅格数据包含很多信息,在数据的运用中需要对数据的信息进行读取或写入,目前PIE SDK支持多种数据格式的数据读取和写入,下面对栅格数据格式的数据读写功能进行介绍. 2.功能实现说明 2. ...
- [POI2010] GRA-The Minima Game - 贪心,dp,博弈论
给出N个正整数,AB两个人轮流取数,A先取.每次可以取任意多个数,直到N个数都被取走.每次获得的得分为取的数中的最小值,A和B的策略都是尽可能使得自己的得分减去对手的得分更大.在这样的情况下,最终A的 ...
- Hbase出现ServerNotRunningYetException的解决方案(退出hadoop的安全模式)
退出安全模式 ./hadoop dfsadmin -safemode leave 然后出现 safemode off就成功了
- PP: Imaging time-series to improve classification and imputation
From: University of Maryland encode time series as different types of images. reformulate features o ...
- 在 window 上卸载 mysql
1.停止 mysql 服务 开始——>控制面板——>管理工具——>服务,停掉 MySQL 的服务 2.卸载安装包 控制面板-添加删除程序,找到MySQL,卸载(可能会有多个安装包,需 ...