在实际项目开发中数据库操作一般都是并发执行的,即有多个事务并发执行,并发执行就可能遇到问题,目前常见的问题如下:
为了解决这些并发问题,需要通过数据库隔离级别来解决,在标准SQL规范中定义了四种隔离级别:
未提交读(Read Uncommitted):最低隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读;
提交读(Read Committed):一个事务能读取到别的事务提交的更新数据,不能看到未提交的更新数据,不可能可能出现丢失更新、脏读,但可能出现不可重复读、幻读;
可重复读(Repeatable Read):保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响,可能可能出现丢失更新、脏读、不可重复读,但可能出现幻读;
序列化(Serializable):最高隔离级别,不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读
数据库事务类型有本地事务和分布式事务
Java事务类型有JDBC事务和JTA事务:
按是否通过编程实现事务有声明式事务和编程式事务;
声明式事务: 通过注解或XML配置文件指定事务信息;
编程式事务:通过编写代码实现事务
Spring框架最核心功能之一就是事务管理,而且提供一致的事务管理抽象,
Spring框架支持事务管理的核心是事务管理器抽象,对于不同的数据访问框架(如Hibernate)通过实现策略接口PlatformTransactionManager,
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
getTransaction():返回一个已经激活的事务或创建一个新 的事务(根据给定的TransactionDefinition类型参数定义的事务属性),返回的是TransactionStatus对象代表了当前事 务的状态,其中该方法抛出TransactionException(未检查异常)表示事务由于某种原因失败。
commit():用于**提交**TransactionStatus参数代表的事务
rollback():用于**回滚**TransactionStatus参数代表的事务
Spring提供了许多内置事务管理器实现:
还提供对如JMS事务管理的管理器等
Spring提供一致的事务抽象如图所示
一、声明对本地事务的支持:
a)JDBC及iBATIS、MyBatis框架事务管理器
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource"/>
bean>
b)Jpa事务管理器
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
……
<property name="jpaDialect" ref="jpaDialect"/>
bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
为entityManagerFactory对象指定jpaDialect属性,该属性所对应的对象指定了如何获取连接对象、开启事务、关闭事务等事务管理相关的行为。
c)Hibernate事务管理器
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
bean>
Spring支持两种事务管理方式:
编程式事务管理 ,声明式事务管理。
编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。
Spring框架提供一致的事务抽象,因此对于JDBC还是JTA事务都是采用相同的API进行编程。
在Spring中将采用一致的事务抽象进行控制和一致的异常控制,即面向 PlatformTransactionManager接口编程来控制事务。
Spring中的事务分为物理事务和逻辑事务;
逻辑事务两种方案:低和高
低:
使用工具类:使用工具类获取连接(会话)和释放连接(会话),DataSourceUtils 类来获取和释放具有逻辑事务功能的连接,第三方ORM框架类似的工具类,对Hibernate提供了SessionFactoryUtils工具类
高:
使用Spring提供的模板类,如JdbcTemplate、HibernateTemplate和JpaTemplate模板类等,而这些模板类内部其实是使用了低级别解决方案中的工具类来管理连接或会话;
Spring提供两种编程式事务支持:
(1),直接使用PlatformTransactionManager实现
(2),使用TransactionTemplate模板类,用于支持逻辑事务管理。
采用编程式事务推荐使用TransactionTemplate模板类和高级别解决方案。
TransactionTemplate模板类用于简化事务管理,事务管理由模板类定义,而具体操作需要通过回调接口指定,通过调用模板类的的execute方法来自动享受事务管理,参数类型为 TransactionCallback或TransactionCallbackWithoutResult
回调接口:
txManager = ctx.getBean(PlatformTransactionManager.class);
dataSource = ctx.getBean(DataSource.class);
jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute(CREATE_TABLE_SQL);
//创建事务模板类,其中构造器参数为PlatformTransactionManager实现
TransactionTemplate transactionTemplate = new TransactionTemplate(txManager);
/*
或
TransactionTemplate transactionTemplate = TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);
*/
//通过其相应方法设置事务定义,如事务隔离级别、传播行为等,此处未指定传播行为, 其默认为PROPAGATION_REQUIRED;
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
//通过execute方法执行需要事务管理的回调。
//使用不带返回的回调实现TransactionCallbackWithoutResult
transactionTemplate.execute(
new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
//表示向数据库中的test表中插入数据;
jdbcTemplate.update(INSERT_SQL, "test");
}
}
);
抛出Exception类型的异常且需要回滚时,需要捕获异常并通过调用status对象的setRollbackOnly()方法告知事务管理器当前事务需要回滚
try {
//业务操作
....
} catch (Exception e) { //可使用具体业务异常代替
status.setRollbackOnly();
}
实际运用: Service实现中需要Spring事务管理的部分应该使用TransactionTemplate模板类来包装执行
★注意:
Q:Spring事务全部在Service层定义,为什么会在Service层定义,而不是Dao层定义呢?
A:因为在服务层可能牵扯到业务逻辑,而每个业务逻辑可能调用多个Dao层方法,为保证这些操作的原子性,必须在Service层定义事务。
事务属性
通过TransactionDefinition接口实现定义,主要有事务隔离级别、事务传播行为、事务超时时间、事务是否只读。默认实现DefaultTransactionDefinition
声明式事务支持方式属于无侵入式,对业务逻辑实现无影响。
Spring配置:
1、XML命名空间定义,定义用于事务支持的tx命名空间和AOP支持的aop命名空间
2、业务实现配置,
id="userService" class="cn.javass.spring.chapter9.service.impl.ConfigUserServiceImpl">
<property name="userDao" ref="userDao"/>
3、事务相关配置:
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="*" propagation="REQUIRED" isolation="READ_COMMITTED" read-only="true"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="serviceMethod" expression="execution(* cn..chapter9.service..*.*(..))"/>
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/>
aop:config>
声明式事务管理同样是通过AOP代理方式实现(cglib或者原生jdk代理)
:id用于指定此通知的名字,
method>:用于定义事务属性即相关联的方法名
rollback-for:需要触发回滚的异常定义,以“,”分割;
no-rollback-for:不被触发进行回滚的 Exception(s);以“,”分割;
多事务语义配置:
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="merge*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="put*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="count*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="list*" propagation="SUPPORTS" read-only="true" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* cn.javass..service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
aop:config>
Spring提供基于@Transactional注解方式来实现,但需要Java 5+,
Spring提供的< tx:annotation-driven/>
用于开启对注解事务管理的支持,
Spring使用@Transaction来指定事务属性,可以在接口、类或方法上指定
1、业务逻辑代码
2、XML命名空间定义,定义用于事务支持的tx命名空间和AOP支持的aop命名空间:
3、业务实现Bean配置
4、事务相关配置:< tx:annotation-driven transaction-manager="txManager"/>
@Transaction元数据说明:
value:指定事务管理器名字,默认使用< tx:annotation-driven/>
指定的事务管理器,用于支持多事务管理器环境;
rollbackForClassname:指定一组异常类名字,其含义与< tx:method>
中的rollback-for属性语义完全一样;
★注:
Spring声明式事务实现其实就是Spring AOP+线程绑定实现,利用AOP实现开启和关闭事务,利用线程绑定(ThreadLocal)实现跨越多个方法实现事务传播